본문 바로가기

스프링 Spring

AOP 끝 21. 03. 31.

ProxyFactoryBean

package site.levinni.aop3;

MyDependency.java

package site.levinni.aop3;

public class MyDependency {
	public void hello() {
		System.out.println("hello");
	}
	public void goodbye() {
		System.out.println("bye");
	}
}
advice가 적용될 곳. 
advisor는 hello()만 특정 되게 할 것.

 

 

MyBean.java

package site.levinni.aop3;

import lombok.Setter;

@Setter
public class MyBean {
	private MyDependency dependency;
	
	public void run() {
		dependency.hello();
		dependency.goodbye();
	}
}

 

 

 

MyBefore.java

package site.levinni.aop3;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class MyBefore implements MethodBeforeAdvice{

	@Override
	public void before(Method method, Object[] args, Object target) throws Throwable {
		System.out.println("사전충고");
	}

	
}

 

 

MyApp.java

package site.levinni.aop3;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyApp {
	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("my.xml");
		ctx.getBean("myBean1", MyBean.class).run(); // advice
		ctx.getBean("myBean2", MyBean.class).run(); // advisor
	}
}

 

 

my.xml

더보기
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<bean class="site.levinni.aop3.MyBefore" id="myBefore"></bean>
	<bean class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor" id="pointcutAdvisor">
		<property name="advice" ref="myBefore"/>
		<property name="expression" value="execution(* hello(..))"></property>
	</bean>
	
	<bean class="site.levinni.aop3.MyBean" id="myBean1">
		<property name="dependency">
			<bean class="org.springframework.aop.framework.ProxyFactoryBean">
				<property name="target">
					<bean class="site.levinni.aop3.MyDependency"></bean>
				</property>
				<property name="interceptorNames">
					<list>
						<value>myBefore</value>
					</list>
				</property>
			</bean>
		</property>
	</bean>
	
	<bean class="site.levinni.aop3.MyBean" id="myBean2">
		<property name="dependency">
			<bean class="org.springframework.aop.framework.ProxyFactoryBean">
				<property name="target">
					<bean class="site.levinni.aop3.MyDependency"></bean>
				</property>
				<property name="interceptorNames">
					<list>
						<value>pointcutAdvisor</value>
					</list>
				</property>
			</bean>
		</property>
	</bean>
</beans>
dependency는 ProxyFactoryBean을 통해 가짜 객체를 만들 것이고 그 대상(target)은 class=MyDependency가 됨.
interceptorNames는 이름값만으로 가져옴.
그 value 값을 가져오기 위해 myBefore빈 생성.
myBean2는 Advisor (어드바이스 + 포인트컷) 적용.
execution(* hello(..)) : "헬로우"이름 딱 지정. (..) 말고 ()는 파라미터 없는 것.

myBean1에만 충고 적용됨.

 

 

meBean2는 execution에 의해 hello()에만 충고 적용됨.

 

익명 bean 형태

 


 

AOP 네임스페이스

선언적인 스프링 AOP 설정을 간단하게 해 줌.
aop 네임스페이스 선언.
모든 스프링 aop 설정을 <aop:config></aop:config> 안에 넣어야 하는데 포인트컷, 애스펙트, 어드바이저 등을 정의하고 다른 스프링 빈을 참조 가능함.

 

package site.levinni.aop4;

 

MyDependency.java

package site.levinni.aop4;

public class MyDependency {
	public void hello(int val) {
		System.out.println("hello :: " + val);
	}
	public void goodbye() {
		System.out.println("bye");
	}
}

 

 

MyBean.java

package site.levinni.aop4;

import lombok.Setter;

@Setter
public class MyBean {
	private MyDependency dependency;
	
	public void run() {
		dependency.hello(5200);
		dependency.hello(4800);
		dependency.goodbye();
	}
}

 

 

MyAdvice.java

package site.levinni.aop4;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyAdvice {
	public void customBefore(JoinPoint joinPoint, int val) {
		if(val > 5000) {
			System.out.println("사전충고 실행");
		}
	}
	
	public Object customAround(ProceedingJoinPoint pjp, int val) throws Throwable {
		if(val < 5000) {
			System.out.println("주변충고 전처리");
		}
		return pjp.proceed();
	}
}
before advice는 리턴 안 해도 됨. around advice는 리턴 값 필요.
befor advice는 반드시 Joinpoint 타입 인자 필요하고, around advice는 ProceedingJoinPoint 인자 필요!!

 

 

MyApp.java

package site.levinni.aop4;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyApp {
	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("aop4.xml");
		ctx.getBean("myBean", MyBean.class).run(); // advice
	}
}

 

 

aop4.xml

더보기
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">

	<bean class="site.levinni.aop4.MyBean" id="myBean">
		<property name="dependency">
			<bean class="site.levinni.aop4.MyDependency"></bean>
		</property>
	</bean>
	<bean class="site.levinni.aop4.MyAdvice" id="myAdvice"></bean>
	<aop:config>
		<aop:pointcut expression="execution(* hello(..)) and args(val)" id="pc"/>
		<aop:aspect ref="myAdvice">
			<aop:before method="customBefore" pointcut-ref="pc"/>		
		</aop:aspect>
		<aop:aspect ref="myAdvice">
			<aop:around method="customAround" pointcut-ref="pc"/>		
		</aop:aspect>
	</aop:config>
</beans>
첫 부분 역시나 익명빈 사용!
pointcut의 표현식 인자가 있으면 and args(매개변수 이름) 해 줘야 함.

 


 

package site.levinni.smallmart4;

 

MyAdvice.java

package site.levinni.smallmart4;

import org.aspectj.lang.JoinPoint;

public class MyAdvice {
	public void beforeAdv(JoinPoint jp) {
		System.out.println("사전처리맨");
	}
}
인터페이스를 구현해서 사용하는 게 아니라 조인포인트를 이용하는 것!!

 

 

SmallMart.java

package site.levinni.smallmart4;

public interface SmallMart {
	public void getProducts(String productName) throws Exception;
	public void getProducts2(String productName) throws Exception;
}

 

 

SmallMartImpl.java

package site.levinni.smallmart4;

public class SmallMartImpl implements SmallMart{

	@Override
	public void getProducts(String productName) throws Exception {
		System.out.println(productName + ":: getProducts()");
//		throw new Exception("small mart 예외");
	}

	@Override
	public void getProducts2(String productName) throws Exception {
		System.out.println(productName + ":: getProducts2()");
		
	}

}

 

 

smallmart4.xml

더보기
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">

	<bean class="site.levinni.smallmart4.SmallMartImpl" id="smallMart"/>
	<bean class="site.levinni.smallmart4.MyAdvice" id="myAdvice"/>
	<aop:config>
		<aop:pointcut expression="execution(* *2(..))" id="pc"/>
		<aop:aspect ref="myAdvice">
			<aop:before method="beforeAdv" pointcut-ref="pc"/>
			<aop:after-returning method="beforeAdv" pointcut-ref="pc"/>
			<aop:after method="beforeAdv" pointcut-ref="pc"/>
			<aop:after-throwing method="beforeAdv" pointcut-ref="pc"/>
			
		</aop:aspect>
	</aop:config>
</beans>
똑같은 메서드로 다른 종류의 충고들을 추가할 수 있음.
어떤 advice를 넣을 것인지 어디에 넣을 것인지!만 기억하자.
pointcut-ref 대신 pointcut만 쓰면 value 값을 나타내는 거니깐,
pointcut-ref="pc"대신에 pointcut="execution(* *))"도 됨!!

 

 

SmallMartApp.java

package site.levinni.smallmart4;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SmallMartApp {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("smallmart4.xml");
		SmallMart proxy = ctx.getBean("smallMart", SmallMart.class);
		
		try{
			System.out.println("===proxy===");
			proxy.getProducts("칫솔");
			proxy.getProducts2("치실2");
			
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
}

 

 

 

package site.levinni.smallmart5; (@AspectJ 방식의 Annotation) 제일 많이 씀!

 

MyAdvice.java

package site.levinni.smallmart5;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Service;

@Aspect @Service
public class MyAdvice {
	@Before("execution(* *2(..))")
	public void beforeAdv(JoinPoint jp) {
		System.out.println("사전처리맨");
	}
}
이 클래스에서 모든 걸 다 처리할 것이기 때문에 제일 중요!

 

 

SmallMart.java

package site.levinni.smallmart5;

public interface SmallMart {
	public void getProducts(String productName) throws Exception;
	public void getProducts2(String productName) throws Exception;
}

 

 

SmallMartImpl.java

package site.levinni.smallmart5;

import org.springframework.stereotype.Service;

@Service("smallMart")
public class SmallMartImpl implements SmallMart{

	@Override
	public void getProducts(String productName) throws Exception {
		System.out.println(productName + ":: getProducts()");
//		throw new Exception("small mart 예외");
	}

	@Override
	public void getProducts2(String productName) throws Exception {
		System.out.println(productName + ":: getProducts2()");
		
	}

}

 

 

smallmart5.xml

더보기
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">

	<context:component-scan base-package="site.levinni.smallmart5"/>
	<aop:aspectj-autoproxy/>
</beans>
aop 네임스페이스 추가!

 

 

SmallMartApp.java

package site.levinni.smallmart5;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SmallMartApp {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("smallmart5.xml");
		SmallMart proxy = ctx.getBean("smallMart", SmallMart.class);
		
		try{
			System.out.println("===proxy===");
			proxy.getProducts("칫솔");
			proxy.getProducts2("치실2");
			
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
}

 

getProducts2()에만 충고 적용됨.

 

 

참고

 

'스프링 Spring' 카테고리의 다른 글

21. 04. 01.  (0) 2021.04.01
Spring JDBC 21. 03. 31.  (0) 2021.03.31
AOP 21. 03. 30.  (0) 2021.03.30
IoC 21. 03. 29.  (0) 2021.03.29
Spring IoC 및 DI 21. 03. 26.  (0) 2021.03.26