기술나눔

Spring AOP의 여러 구현 방법

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

1. Annotation을 통한 구현

1.1 가져오기 종속성

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-aop</artifactId>
  4. <version>5.1.6.RELEASE</version>
  5. </dependency>

1.2 정의 주석

  1. import java.lang.annotation.*;
  2. @Target(ElementType.METHOD)
  3. @Retention(RetentionPolicy.RUNTIME)
  4. @Documented
  5. public @interface TestAnnotation{
  6. }

1.2 측면 클래스 정의

  1. import org.aspectj.lang.ProceedingJoinPoint;
  2. import org.aspectj.lang.annotation.*;
  3. import org.springframework.stereotype.Component;
  4. /*
  5. * 切面类
  6. **/
  7. @Aspect
  8. @Component
  9. public class AnnotationAspect {
  10. // 定义一个切点:所有被RequestMapping注解修饰的方法会织入advice
  11. @Pointcut("@annotation(TestAnnotation)")
  12. private void advicePointcut() {}
  13. /*
  14. * 前置通知
  15. **/
  16. @Before("advicePointcut()")
  17. public void before() {
  18. System.out.println("annotation前置通知");
  19. }
  20. @After("advicePointcut()")
  21. public void after() {
  22. System.out.println("annotation后置通知");
  23. }
  24. @AfterReturning(pointcut = "advicePointcut()")
  25. public void afterReturning() {
  26. System.out.println("annotation后置返回通知");
  27. }
  28. @AfterThrowing(pointcut = "advicePointcut()", throwing = "ex")
  29. public void afterThrowing(Exception ex) throws Exception {
  30. System.out.println("annotation异常通知");
  31. System.out.println(ex.getMessage());
  32. }
  33. @Around("advicePointcut()")
  34. public Object around(ProceedingJoinPoint pjp) throws Throwable {
  35. Object proceed = null;
  36. if (!"".equals("admin")) {
  37. System.out.println("annotation环绕前置");
  38. proceed = pjp.proceed(pjp.getArgs());
  39. System.out.println("annotation环绕后置");
  40. }
  41. return proceed;
  42. }
  43. }

2.jdk 프록시 주석 방법

2.1. 인터페이스 정의

  1. public interface TargetInteface {
  2. void method1();
  3. void method2();
  4. int method3(Integer i);
  5. }

2.2. 인터페이스 구현

  1. public class Target implements TargetInteface{
  2. /*
  3. * 需要增强的方法,连接点JoinPoint
  4. **/
  5. public void method1() {
  6. System.out.println("method1 running ...");
  7. }
  8. public void method2() {
  9. System.out.println("method2 running ...");
  10. }
  11. public int method3(Integer i) {
  12. System.out.println("method3 running ...");
  13. return i;
  14. }
  15. }

2.3. 알림 정의

  1. public class TargetAdvice implements MethodInterceptor, MethodBeforeAdvice, AfterReturningAdvice {
  2. /*
  3. * 通知/增强
  4. **/
  5. @Override
  6. public Object invoke(MethodInvocation methodInvocation) throws Throwable {
  7. System.out.println("前置环绕通知");
  8. Object proceed = methodInvocation.proceed();
  9. System.out.println("后置环绕通知");
  10. return proceed;
  11. }
  12. @Override
  13. public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
  14. System.out.println("后置返回通知");
  15. }
  16. @Override
  17. public void before(Method method, Object[] args, Object target) throws Throwable {
  18. System.out.println("前置通知");
  19. }
  20. }

2.4.구성 파일 작성

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. 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.xsd">
  5. <bean id="target" class="com.heaboy.aopdemo.aop.Target"/>
  6. <bean id="targetAdvice" class="com.heaboy.aopdemo.aop.TargetAdvice"/>
  7. <bean id="targetProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
  8. <property name="target" ref="target"/> <!--被代理的类-->
  9. <property name="interceptorNames" value="targetAdvice"/> <!--如果用多种增强方式,value的值使用逗号(,)分割-->
  10. <property name="proxyTargetClass" value="false"/>
  11. <property name="interfaces" value="com.heaboy.aopdemo.aop.TargetInteface"/> <!--target实现的接口-->
  12. </bean>
  13. </beans>

2.5 테스트 시작

  1. public class AopTest {
  2. public static void main(String[] args) {
  3. ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-aop.xml");
  4. TargetInteface targetProxy = (TargetInteface) appCtx.getBean("targetProxy");
  5. targetProxy.method1();
  6. print(targetProxy);
  7. }
  8. }

3.cglib 구성 파일 방법

3.1 프록시 클래스 정의

  1. public class Target {
  2. public void method1() {
  3. System.out.println("method1 running ...");
  4. }
  5. public void method2() {
  6. System.out.println("method2 running ...");
  7. }
  8. /*
  9. * 连接点JoinPoint
  10. **/
  11. public int method3(Integer i) {
  12. System.out.println("method3 running ...");
  13. int i1 = 1 / i;
  14. return i;
  15. }
  16. }

3.2. 측면 정의

  1. import org.aspectj.lang.ProceedingJoinPoint;
  2. /*
  3. * 切面类
  4. **/
  5. public class TargetAspect {
  6. /*
  7. * 前置通知
  8. **/
  9. public void before() {
  10. System.out.println("conf前置通知");
  11. }
  12. public void after() {
  13. System.out.println("conf后置通知");
  14. }
  15. public void afterReturning() {
  16. System.out.println("conf后置返回通知");
  17. }
  18. public void afterThrowing(Exception ex) throws Exception {
  19. // System.out.println("conf异常通知");
  20. // System.out.println(ex.getMessage());
  21. }
  22. public Object around(ProceedingJoinPoint pjp) throws Throwable {
  23. Object proceed = null;
  24. if (!"".equals("admin")) {
  25. System.out.println("conf环绕前置");
  26. proceed = pjp.proceed(pjp.getArgs());
  27. System.out.println("conf环绕后置");
  28. }
  29. return proceed;
  30. }
  31. }

3.3 구성 파일 작성

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
  4. 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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
  5. <bean id="target" class="com.heaboy.aopdemo.confaop.Target"/>
  6. <bean id="targetAspect" class="com.heaboy.aopdemo.confaop.TargetAspect"/>
  7. <!--proxy-target-class="true" 表示使用cglib代理.默认为false,创建有接口的jdk代理-->
  8. <aop:config proxy-target-class="true">
  9. <!--切面:由切入点和通知组成-->
  10. <aop:aspect ref="targetAspect">
  11. <!--切入点 pointcut-->
  12. <aop:pointcut id="pointcut" expression="execution(* com.heaboy.aopdemo.confaop.*.*(..))"/>
  13. <!--增强/通知 advice-->
  14. <aop:before method="before" pointcut-ref="pointcut"/>
  15. <aop:after method="after" pointcut-ref="pointcut"/>
  16. <aop:around method="around" pointcut-ref="pointcut"/>
  17. <aop:after-returning method="afterReturning" pointcut-ref="pointcut"/>
  18. <aop:after-throwing method="afterThrowing" throwing="ex" pointcut-ref="pointcut"/>
  19. </aop:aspect>
  20. </aop:config>
  21. </beans>

3.4 테스트 시작

  1. public class AopTest {
  2. public static void main(String[] args) {
  3. ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-confaop.xml");
  4. Target targetProxy = (Target) appCtx.getBean("target");
  5. System.out.println(targetProxy.method3(1));
  6. }
  7. }