0C 개발일지
스프링 공부 - DI, AOP 본문
스프링 프레임워크 구성 요소
주요 기술
1. POJO 기반
2. 의존성 주입 지원(DI)
3. 관점 지향 프로그래밍 지원(AOP)
4. Spring MVC
5. 레이아웃 지원(Tiles)
6. 데이터베이스 연동 지원
- JDBC
- Spring JDBC
- MyBatis
- JPA
7. Spring Security
Spring Core → DI(*****), AOP
Spring DI
디자인 패턴 : DI → Dependency Injection → 의존(성) 주입
- 스프링 도입/적용 → Spring DI
- 스프링에서 가장 중요한 개념 중 하나 → 스프링의 모든 객체 관리에 사용한다.(*****)
- "프로그래밍에서 구성 요소간의 의존 관계가 소스 내부가 아닌 외부 환경에서 정의되게 하는 디자인 패턴"
예를 들어 Main, Servie, Hong 3개의 class가 있다고 한다.
public class Main {
public static void main(String[] args) {
// 목적] > Hong(실무자)에게 일을 시키자
// Main > Hong(X) 다이렉트로 접근 X
// Main > Service(관리자) > Hong (O)
// Hong hong = new Hong();
// Main > (위임) > Service > (위임) > Hong
// Main <-> (의존관계) <-> Service <-> (의존관계) <-> Hong
// Main > Service(의존객체)
// **** 필요할 때마다 직접(***) 의존 객체를 생성해서 사용하는 방식을 사용해왔다.
Service service = new Service();
service.work();
}
}
public class Service {
public void work() {
// 업무의 일부 > 홍길동에게 위임
Hong hong = new Hong();
hong.conding();
}
}
public class Hong {
public void conding() {
System.out.println("코드를 작성합니다.");
}
}
public class Main {
public static void main(String[] args) {
Hong hong = new Hong();
// Service service = new Service();
// service.setHong(hong); // 의존 주입 발생(DI)
// service.work();
Service service = new Service(hong); // 의존 주입 발생(DI)
service.work();
}
}
public class Service {
// 멤버 변수
private Hong hong;
// 내가 의존하는 객체를 직접 생성을 하지 않고, 외부로부터 받아와서 사용한다.
// > 의존 주입 (DI)
// 생성자 오버로딩
// 생성자 > 의존 주입 도구
public Service(Hong hong) {
this.hong = hong;
}
// setter > 의존 주입 도구
// public void setHong(Hong hong) {
// this.hong = hong;
//
// }
public void work() {
// *** 의존 객체를 직접 생성한다.(X)
hong.conding();
}
}
*** 스프링 환경에서는 클래스의 객체(Bean, 빈)를 생성~관리~소멸까지를
1. 개발자가 직접
2. 스프링이 조작 → 스프링 환경 설정 파일(XML > Annotation > Java)
pom.xml →
jar 파일 1개 당 <dependency> 코드 추가
public class Main {
public static void main(String[] args) {
// Hong 객체 생성하기
// 1. 개발자가 직접 생성
// Hong hong = new Hong();
// 2. 스프링을 통해서 생성 > 빈 생성
// - di3.xml 환경 설정을 읽어오기
// ApplicationContext context = new ClassPathXmlApplicationContext("file:/src/main/java/com/test/begin/di3/di3.xml");
ApplicationContext context = new ClassPathXmlApplicationContext("com/test/begin/di3/di3.xml");
// 형변환 필수
// Hong hong = (Hong)context.getBean("hong");
// hong.conding();
// 스프링에서 의존 주입 구현
Service service = (Service) context.getBean("service");
// service.setHong(hong);
service.work();
// <bean id="hong2" name="h1, h2, h3" class="com.test.begin.di3.Hong"></bean>
Hong hong2 = (Hong) context.getBean("hong2");
Hong hong3 = (Hong) context.getBean("h1");
Hong hong4 = (Hong) context.getBean("h2");
Hong hong5 = (Hong) context.getBean("h3");
hong2.conding();
hong5.conding();
}
}
public class Service {
// 멤버 변수
private Hong hong;
// 내가 의존하는 객체를 직접 생성을 하지 않고, 외부로부터 받아와서 사용한다.
// > 의존 주입 (DI)
// 생성자 오버로딩
// 생성자 > 의존 주입 도구
public Service(Hong hong) {
this.hong = hong;
}
// setter > 의존 주입 도구
// public void setHong(Hong hong) {
// this.hong = hong;
//
// }
public void work() {
// *** 의존 객체를 직접 생성한다.(X)
hong.conding();
}
}
<!--
스프링 빈
- 스프링이라는 환경이 관리하는 객체
스프링 빈 선언(정의)
- Hong hong = new Hong();
-->
<bean id="hong" class="com.test.begin.di3.Hong"></bean>
<!-- id와 name 보통 다르게 만들고, name 은 여러개 가능, name은 별칭, 기본은 id -->
<bean id="hong2" name="h1, h2, h3" class="com.test.begin.di3.Hong"></bean>
<!-- <bean id="service" class="com.test.begin.di3.Service"></bean> -->
<!-- setter -->
<!-- <bean id="service" class="com.test.begin.di3.Service">
<property name="hong">
<bean class="com.test.begin.di3.Hong"></bean>
</property>
</bean> -->
<bean id="service" class="com.test.begin.di3.Service">
<!-- Setter 주입 -->
<!-- <property name="hong" ref="hong"></property>-->
<!-- 생성자 주입 -->
<!--
<constructor-arg>
<bean class="com.test.begin.di3.Hong"></bean>
</constructor-arg>
-->
<constructor-arg ref="hong"></constructor-arg>
</bean>
</beans>
Spring AOP, Aspect Oriented Programming
- 관점 지향 프로그래밍
- 코드를 작성 → 주업무 코드 + 보조업무 코드
Spring AOP 용어
1. Core Concern
- 주업무, 비즈니스 코드
2. Cross-cutting Concern
- 보조업무
3. Target
4. Proxy
5. JointPoint
6. Pointcut
7. Aspect
8. Advice
- Before Advice
- After Advice
- Around Advice
주업무에 의존적인 편
- After-returning Advice
- After-throwing Advice
public class Main {
public static void main(String[] args) {
// 주 업무 객체 > MemoImpl
// MemoImpl memo = new MemoImpl();
// 주 업무 객체 > 빈으로 생성하기 > 스프링 컨테이너에 의해서 관리
ApplicationContext context = new ClassPathXmlApplicationContext("com/test/begin/aop/memo.xml");
MemoImpl memo = (MemoImpl) context.getBean("memo");
// 글쓰기
memo.add("스프링 작업 중입니다.");
memo.addSecret("스프링 작업 중입니다.");
// 글읽기
try {
String content = memo.read(10);
System.out.println(content);
} catch (Exception e) {
e.printStackTrace();
}
// 수정
boolean result = memo.edit(15, "수정할 내용입니다.");
// 삭제
result = memo.del(15);
}
}
public class MemoImpl {
public void add(String memo) {
System.out.println("메모 쓰기: " + memo);
}
public void addSecret(String memo) {
System.out.println("비밀 메모를 작성합니다.");
}
public String read(int seq) throws Exception {
if (seq != 10) {
System.out.println("메모 읽기: " + seq);
return "새로운 메모입니다";
} else {
throw new Exception("존재하지 않는 메모입니다.");
}
}
public boolean edit(int seq, String memo) {
System.out.println("메모 수정: " + memo);
return true;
}
public boolean del(int seq) {
System.out.println("메모 삭제: " + seq);
return true;
}
}
// 보조 업무 객체
public class Logger {
public void log(String message) {
Calendar now = Calendar.getInstance();
System.out.printf("[LOG]%tF %tT > %s\n", now, now, message);
}
// 보조 업무 구현
public void after() {
System.out.println("보조 업무를 실행합니다.");
}
// 보조 업무 구현
public void around(ProceedingJoinPoint jp) {
// ProceedingJoinPoint jp 프록시 객체 > 주업무 대리자
// 주업무를 실행되는 소요시간 기록
// 1. 기록 시작
// 2. 주업무 실행
// 3. 기록 종료
long begin = System.nanoTime();
System.out.println("[LOG] 기록을 시작합니다.");
// 주업무 실행
// memo.add("메모");
try {
jp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
// 주업무 실행
long end = System.nanoTime();
System.out.println("[LOG] 기록을 종료합니다.");
System.out.printf("[LOG] 소요 시간 %,dns\n", end - begin);
}
// After-returning
public void history(Object memo) {
System.out.println("[LOG] 메모 읽기: " + memo);
}
// After-throwing
public void check(Exception e) {
System.out.println("[LOG] 예외 발생: " + e.getMessage());
// DB Insert..
// 담당자 메일 발생 or 문자 메세지
}
}
<!-- Spring AOP 1. 주업무 객체 > 빈으로 등록 2. 보조업무 객체 > 빈으로 등록 memo.xml > Spring
> Add Bean Con.. > 파일에 S가 붙으면 스프링이 관리하는 대상 Namespaces 탭 > aop 추가 -->
<!-- 주업무 객체 -->
<bean id="memo" class="com.test.begin.aop.MemoImpl"></bean>
<!-- 보조업무 객체 -->
<bean id="logger" class="com.test.begin.aop.Logger"></bean>
<!-- 주업무 객체 + 보조업무 객체 -->
<aop:config>
<!-- 보조업무 객체를 지정한다. 역할 부여 -->
<aop:aspect ref="logger" id="loggerAdvice">
<!-- 1. 주 업무 객체를 지정 2. 메서드를 지정 1 + 2 = Pointcut > 보조 업무를 결합 시킬 대상 = 주업무
객체.특정 메서드() expression="AspectJ 표현식" - execution() 지시자 - execution(특정 클래스
+ 특정 메서드) - execution([접근 지정자] 반환형 [패키지.클래스].메서드(인자)) - execution(public
void com.test.begin.aop.MemoImpl.add(String)) -->
<aop:pointcut
expression="execution(public void com.test.begin.aop.MemoImpl.add(String))"
id="p1" />
<aop:pointcut
expression="execution(public String com.test.begin.aop.MemoImpl.read(int))"
id="p2" />
<aop:pointcut
expression="execution(public String com.test.begin.aop.MemoImpl.read(int)) || execution(public void com.test.begin.aop.MemoImpl.add(String))"
id="p3" />
<!-- 전체 -->
<aop:pointcut
expression="execution(public * com.test.begin.aop.MemoImpl.*(..))"
id="p4" />
<aop:pointcut
expression="execution(* *(..))"
id="p5" />
<aop:pointcut
expression="execution(* add(String))"
id="p6" />
<aop:pointcut
expression="execution(* add*(String))"
id="p7" />
<!-- 보조업무 객체.메서드 + Pointcut > 위빙(Weaving) > Advice - 주업무 실행 > 보조 업무 실행
(예 : 로깅) - 보조업무 실행 > 주업무 실행 (예: 권한체크) -->
<!-- <aop:after method="after" pointcut-ref="p1" /> -->
<!-- <aop:after method="after" pointcut-ref="p2" /> -->
<!-- <aop:after method="after" pointcut-ref="p3" /> -->
<!-- <aop:after method="after" pointcut-ref="p4" /> -->
<!-- <aop:after method="after" pointcut-ref="p5" /> -->
<!-- <aop:after method="after" pointcut-ref="p7" /> -->
<!-- <aop:before method="after" pointcut-ref="p1" /> -->
<!-- <aop:after method="after" pointcut-ref="p1" />
<aop:before method="after" pointcut-ref="p1" /> -->
<!-- <aop:around method="around" pointcut-ref="p1" /> -->
<!-- <aop:after-returning method="history" pointcut-ref="p2" returning="memo" /> -->
<aop:after-throwing method="check" pointcut-ref="p2" throwing="e" />
</aop:aspect>
</aop:config>
</beans>
'Spring' 카테고리의 다른 글
스프링 배치(Spring Batch)란 (0) | 2024.08.12 |
---|---|
Spring Boot (0) | 2024.08.07 |