0C 개발일지

스프링 공부 - DI, AOP 본문

Spring

스프링 공부 - DI, AOP

0C 2024. 5. 16. 00:02

스프링 프레임워크 구성 요소

주요 기술

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