Spring learning summary (9): Two ways to develop AOP in AspectJ

1. XML-based declarative

       XML-based declarative means defining aspects, pointcuts, and declaration notifications through Spring configuration files, and all aspects and notifications must be defined in the <aop:config> element.

       Proceed as follows:

       (1) Import the jar package.

   <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.2.6.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
    <dependency>
      <groupId>aopalliance</groupId>
      <artifactId>aopalliance</artifactId>
      <version>1.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.13</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.8.9</version>
    </dependency>

       (2) Create the Book class

public class Book {
    public void addBook(){
        System.out.println("add Book……");
    }
    public void updateBook(){
        System.out.println("update Book……");
    }

}

       (3) Create the BookProxy class

public class BookProxy {
    public void before(){
        System.out.println("before……");
    }
    public void after(){
        System.out.println("after……");
    }
    public void afterReturing(){
        System.out.println("afterReturing……");
    }
    public void afterThrowing(){
        System.out.println("afterThrowing……");
    }
    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("around  之前……");
        point.proceed();
        System.out.println("around  之后……");
    }
}

       (4) Bean configuration and aop configuration in bean.xml.

    <!--  基于XML的AOP实现  -->
    <!--  配置bean  -->
    <bean id="book" class="com.yht.example6.Book"></bean>
    <bean id="bookProxy" class="com.yht.example6.BookProxy"></bean>
    <!-- aop配置   -->
    <aop:config>
        <!--
            expression : 配置切入点的具体位置
            id:切入点的id
         -->
        <aop:pointcut id="p1" expression="execution(* com.yht.example6.Book.*(..))"/>
        <!--    -->
        <aop:aspect ref="bookProxy">
            <aop:before method="before" pointcut-ref="p1"></aop:before>
            <aop:after method="after" pointcut-ref="p1"></aop:after>
            <aop:after-returning method="afterReturing" pointcut-ref="p1"></aop:after-returning>
            <aop:after-throwing method="afterThrowing" pointcut-ref="p1"></aop:after-throwing>
            <aop:around method="around" pointcut-ref="p1"></aop:around>
        </aop:aspect>
    </aop:config>

       (5) Perform unit testing

    @Test
    public void testBook(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        Book book = context.getBean("book", Book.class);
        book.addBook();
    }

       The execution results are as follows:

 

Two, annotation-based declarative

       In Spring, although the use of XML configuration files can achieve AOP development, if all related configurations are concentrated in the configuration file, it will inevitably lead to the XML configuration file being too bloated, which will bring certain difficulties to maintenance and upgrades. The AspectJ framework provides another development method for AOP development-Declarative based on Annotation. AspectJ allows the use of annotations to define aspects, pointcuts and enhancements, while the Spring framework can identify and generate AOP proxies based on these annotations. Common annotations are introduced as follows:

name Description
@Aspect Used to define an aspect
@Before Used to define pre-notification, equivalent to BeforeAdvice
@AfterReturning Used to define post notification, equivalent to AfterReturningAdvice
@Around Used to define surrounding notifications, equivalent to MethodInterceptor
@AfterThrowing Used to define exception throw notifications, equivalent to ThrowAdvice
@After Used to define the final (final) notification, regardless of whether it is abnormal, the notification will be executed
@DeclareParents Used to define the introduction notification, equivalent to IntroductionInterceptor (understand)

       (1) Configure in bean.xml.

<!--  配置注解扫描的包  -->
    <context:component-scan base-package="com.yht.example6"></context:component-scan>
    <!--   
        通过aop命名空间的<aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面。
     -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

       Through the <aop:aspectj-autoproxy /> declaration in the aop namespace, proxies are automatically created for the beans configured with the @aspectJ aspect in the spring container, and the aspects are woven. There is a proxy-target-class attribute in <aop:aspectj-autoproxy />, which is false by default. If the attribute value of proxy-target-class is set to false or this attribute is omitted, then the standard JDK interface-based proxy will start effect. When it is configured as <aop:aspectj-autoproxy poxy-target-class="true"/>, it means to use CGLib dynamic proxy technology to weave and enhance. But even if proxy-target-class is set to false, if the target class does not declare an interface, spring will automatically use CGLib dynamic proxy.

       (2) Create the User class

@Component
public class User {
    public void addUser(){
        System.out.println("添加用户");
    }
    public void updateUser(){
        System.out.println("修改用户");
    }
    public void deleteUser(){
        System.out.println("删除用户");
    }
    public void searchUser(){
        System.out.println("查找用户");
    }

}

       (3) Create UserProxy

@Component
@Aspect
public class UserProxy {
    @Before(value = "execution(* com.yht.example6.User.addUser(..))")
    public void before(){
        System.out.println("方法执行之前");
    }
    @After(value = "execution(* com.yht.example6.User.addUser(..))")
    public void after(){
        System.out.println("方法执行之后");
    }
    @AfterReturning(value = "execution(* com.yht.example6.User.addUser(..))")
    public void afterReturning(){
        System.out.println("返回后通知");
    }
    @AfterThrowing(value = "execution(* com.yht.example6.User.addUser(..))")
    public void afterThrowing(){
        System.out.println("抛出异常后通知");
    }
    @Around(value = "execution(* com.yht.example6.User.addUser(..))")
    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕通知——方法执行之前");
        point.proceed();
        System.out.println("环绕通知——方法执行之后");
    }
}

       (4) Perform unit testing.

    @Test
    public void testUser(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        User user = context.getBean("user", User.class);
        user.addUser();
    }

       The execution results are as follows:

A few notes:

       (1) The afterThrowing method is executed when the program is abnormal, and the addUser() of the User makes the program abnormal. Check whether the method will be executed.

    @AfterThrowing(value = "execution(* com.yht.example6.User.addUser(..))")
    public void afterThrowing(){
        System.out.println("抛出异常后通知");
    }

       Create a NumberFormatException:

    public void addUser(){
        int val = Integer.parseInt("123ab");//异常
        System.out.println("添加用户");
    }

        The results are as follows:

(2) Introduction of @Order

       The @Order annotation is used to declare the order of components. The smaller the value, the higher the priority, and the earlier it will be executed/initialized. If there is no such annotation, the priority is the lowest. For the above code, add another PersonProxy class, given @Order(1) and UserProxy given @Order(5), the execution result will be that the before method of PersonProxy will be executed before the before method of UserProxy.

       1) Define the PersonProxy class:

@Component
@Aspect
@Order(1)
public class PersonProxy {
    @Before(value = "execution(* com.yht.example6.User.addUser(..))")
    public void beforeMethod(){
        System.out.println("我是PersonProxy的before方法");
    }
}

       2) Add @Order(5) to UserProxy:

       3) Perform a test. The results are as follows:

       (3) Extraction of the same entry point

       In the above example, the five notification configurations in UserProxy have the same entry point expressions. We can extract them and quote them in the annotations of each notification. So the UserProxy class is as follows:

@Component
@Aspect
@Order(5)
public class UserProxy {
    
    @Pointcut(value = "execution(* com.yht.example6.User.addUser(..))")
    public void commonMsg(){}
    
    @Before(value = "commonMsg()")
    public void before(){
        System.out.println("方法执行之前");
    }
    @After(value = "commonMsg()")
    public void after(){
        System.out.println("方法执行之后");
    }
    @AfterReturning(value = "commonMsg()")
    public void afterReturning(){
        System.out.println("返回后通知");
    }
    @AfterThrowing(value = "commonMsg()")
    public void afterThrowing(){
        System.out.println("抛出异常后通知");
    }
    @Around(value = "commonMsg()")
    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕通知——方法执行之前");
        point.proceed();
        System.out.println("环绕通知——方法执行之后");
    }
}

       The final result will be the same as before.

       (4) AOP pure annotation development 

       AOP pure annotation development is basically similar to IOC annotation development, providing a configuration class. Add comments:

@Configuration
@ComponentScan(basePackages = "com.yht.example6")
//@EnableAspectJAutoProxy标记在主配置类上,表示开启基于注解的aop模式
@EnableAspectJAutoProxy
public class AopConfig {
}

The test is as follows:

    @Test
    public void testUserAnno(){
        ApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);
        User user = context.getBean("user", User.class);
        user.addUser();
    }

 

Guess you like

Origin blog.csdn.net/weixin_47382783/article/details/112821681