【Spring】 AOP Base

AOP Overview

  The AOP ( Aspect Oriented Programing), aspect-oriented programming , the AOP taken transverse extraction mechanism replacing the traditional longitudinal succession repetitive coding system (performance monitoring, transaction management, security check, a cache)
  the Spring the AOP pure Java implementation, no special type compilation process and loader at runtime woven into the code to enhance the target class through a proxy way
  AspecJ is a Java-based AOP framework, Spring2.0 start, Spring AOP support for the introduction of Aspect, AspectJ extends the Java language, provides a special the compiler provides lateral woven into the code at compile time

AOP terminology:

  • Connection point (Joinpoint): The so-called connection points are those points being intercepted. In Springthese points it refers to a method, because the Springonly support method type connection points.
  • Entry point (Pointcut): The so-called entry point refers to what we want to Joinpointdefine interception.
  • Notification / enhancement (Advice): The so-called notification means to intercept Joinpointafter the thing to do is to inform.
    • Pre-notification (Before advice): the target method before calling call notification method
    • After returning advice (After / finally advice): the target method after the completion of call notification method, the method does not care about anything at this time is output
    • Return notification (After returning advice): the target method after successful execution of call notification
    • Exception notification (After throwing advice): the target method after throwing an exception call notification
    • Around advice (Around advice): notification methods are wrapped in a notice, in the method to be notified before the call and after the call to perform custom behavior
  • Introduce / introduction (Introduction): introducing a special notification is, without modifying the premise class code, Introduction runtime class can be dynamically added or methods Field
  • Audience (Target): proxy target object
  • Weaving (Weaving): it refers to the enhancement applied to the target object to create a new proxy object processes. SpringDynamic proxy woven into, and AspectJthe use of compile-time weaving and weaving classes loaded in the period
  • Proxy (Proxy): a class is AOPthe knitted reinforcement, generates a proxy class Results
  • : Section (Aspect) binding and entry point notification (introducing) of

    And in a plurality of connection points can function section (notification) woven into the execution of the program
    And in a plurality of connection points can function section (notification) woven into the execution of the program

The term AOP
The term AOP

AOP underlying principle

SpringThe AOPimplementation mechanisms are mainly two:

  1. JDKDynamic Agent: The class that implements the interface generation agent
  2. CGLibProxy mechanism: to generate a proxy class

See proxy mode

In Spring AOP

Outline

classification

  1. Agent-based classic Spring AOP (traditional AOP)
  2. Pure POJO section;
  3. @AspectJ annotation-driven section;
  4. Injection AspectJ aspect (for Spring versions).

Traditional Spring AOP

  AOP: Organization definition .AOP Union is not defined by the Spring.

Spring in the notification :( enhanced Code)

  1. Interface enhancements implemented before the target method execution, to be achieved: Front noticeorg.springframework.aop.MethodBeforeAdvice
  2. Post Notification: Enhanced embodiment performed after the target method, the interface to be achieved,org.springframework.aop.AfterReturningAdvice
  3. Around advice: before and after the target method embodiment Enhanced performed, the interface to be achieved,org.aopalliance.intercept.MethodInterceptor
  4. An exception is thrown notice: After the implementation of enhanced method throws an exception, to implement an interface,org.springframework.aop.ThrowsAdvice
  5. Introducing notice: Add some new methods and properties in the target class to implement an interface,org.springframework.aop.IntroductionInterceptor

For all methods of enhancing :( without a section cut point)

Requires the introduction of Maven coordinates:

<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.5.RELEASE</version>
            <!-- 这里要注释掉,因为设置了scope为test是,测试类只能卸载 Maven中的测试包下 -->
            <!-- <scope>test</scope> -->
        </dependency>

Write the proxy object

interface:

public interface ICustomerDao {
    public void add();
    public void update();
    public void delete();
    public void find();
}

Implementing Classes:

public class CustomerDaoImpl implements ICustomerDao {
    @Override
    public void add() {
        System.out.println("添加客户");     
    }
    @Override
    public void update() {
        System.out.println("更新客户");
    }
    @Override
    public void delete() {
        System.out.println("删除客户");
    }
    @Override
    public void find() {
        System.out.println("查询客户");
    }
}

Written enhanced code

Front enhancements:

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class MyBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("前置增强。。。。。");
    }

}

:( generate the proxy configuration generation agent in XML)

<!-- 不带有切点的切面 -->
    <!-- 1.定义目标对象 -->
    <bean id="customerDao"
        class="com.hao.aop.tradition.demo1.CustomerDaoImpl"></bean>

    <!-- 2.定义增强 -->
    <bean id="beforeAdvice"
        class="com.hao.aop.tradition.demo1.MyBeforeAdvice"></bean>

    <!-- 3.Spring支持配置生成代理: -->
    <bean id="customerDaoProxy"
        class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 设置目标对象 -->
        <property name="target" ref="customerDao" />

        <!-- 设置代理要实现的接口 -->
        <property name="proxyInterfaces"
            value="com.hao.aop.tradition.demo1.ICustomerDao"></property>

        <!-- 设置需要织入目标的Advice -->
        <property name="interceptorNames" value="beforeAdvice" />
    </bean>

Configuration instructions in XML:

  • 首先要将前面定义的目标对象增强 注册到Spring 容器中,
  • 然后是代理类的配置(主要是这里的配置):
    通过类 org.springframework.aop.framework.ProxyFactoryBean 来设置代理对象,对于这个类,以后有时间要看一下,下面先看一下它在XML中需要配置的属性:

    • target : 代理的目标对象
    • proxyInterfaces : 代理要实现的接口,如果多个接口可以使用以下格式赋值:

      <list>
          <value></value>
      ....
      </list>
    • proxyTargetClass:是否对类代理而不是接口,设置为true时,使用CGLib代理

    • interceptorNames : 需要织入目标的Advice

    • singleton : 返回代理是否为单实例,默认为单例

    • optimize : 当设置为true时,强制使用CGLib

测试

这里要注意的是,要注入代理对象!!!!

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AOPTest1 {

    @Qualifier("customerDaoProxy")
    @Autowired
    private ICustomerDao customerDao;
    
    @Test
    public void test() {
        customerDao.add();
        customerDao.find();
        customerDao.update();
        customerDao.delete();
    }
}

带有切点的切面:(针对目标对象的某些方法进行增强)

创建目标对象:

这里没有实现接口,这里试下用CGLIB代理的方式

public class OrderDao {
    public void add() {
        System.out.println("添加订单");
    }
    public void delete() {
        System.out.println("删除订单");
    }
    
    public void find() {
        System.out.println("查询订单");
    }
}

编写增强的类:

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class MyAroundAdvice implements MethodInterceptor{

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("执行方法之前增强.....");
        Object result = invocation.proceed();
        System.out.println("指向方法之后增强.....");
        return result;
    }

}

生成代理(配置生成代理):

<!-- 定义带有切点的切面 -->
    
    <!-- 定义目标对象 -->
    <bean id="orderDao" class="com.hao.aop.tradition.demo2.OrderDao"></bean>
    
    <!-- 定义增强 -->
    <bean id="aroundAdvice"
        class="com.hao.aop.tradition.demo2.MyAroundAdvice"></bean>
    
    <!-- 定义切面 -->
    <bean id="myPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!-- 定义表达式,规定哪些方法执行拦截 -->
        <!-- . 任意字符  * 任意个 -->
        <property name="patterns" value=".*add.*,.*find.*"></property>
        
        <!-- 应用增强 -->
        <property name="advice" ref="aroundAdvice"/>
    </bean>
    
    <!-- 定义生成代理对象 -->
    <bean id="orderDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 配置目标 -->
        <property name="target" ref="orderDao"></property>
        <!-- 针对类的代理 -->
        <property name="proxyTargetClass" value="true"></property>
        <!-- 在目标上应用增强 -->
        <property name="interceptorNames" value="myPointcutAdvisor"></property>
    </bean>

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AOPTest2 {

    @Qualifier("orderDaoProxy") //此处注入的是代理对象
    @Autowired
    private OrderDao orderDao;
    
    @Test
    public void test() {
        orderDao.add();
        orderDao.delete();
        orderDao.find();
    }
}

自动代理

  前面的案例中,每个代理都是通过ProxyFactoryBean织入切面代理,在实际开发中,非常多的Bean每个都配置ProxyFactoryBean开发维护量巨大

  自动创建代理(基于后处理Bean,在Bean创建的过程中完成的增强,生成Bean就是代理。前面利用ProxyFactoryBean代理的方式需要先生成代理对象才可以实现代理功能,而这种方式在Bean的创建过程中就可以完成代码的增强)
  

  • BeanNameAutoProxyCreator:根据Bean名称创建代理
  • DefaultAdvisorAutoProxyCreator:根据Advisor本身包含信息创建代理
  • AnnotationAwareAspectJAutoProxyCreator:基于Bean中的AspectJ 注解进行自动代理

BeanNameAutoProxyCreator

  目标对象和增强,应用前面中的例子,配置示例:
  

<?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 id="customerDao" class="cn.itcast.spring3.demo3.CustomerDaoImpl"></bean>
    <bean id="orderDao" class="cn.itcast.spring3.demo4.OrderDao"></bean>

    <!-- 定义增强 -->
    <bean id="beforeAdvice" class="cn.itcast.spring3.demo3.MyBeforeAdvice"></bean>
    <bean id="aroundAdvice" class="cn.itcast.spring3.demo4.MyAroundAdvice"></bean>

    <!-- 自动代理:按名称的代理 基于后处理Bean,后处理Bean不需要配置ID-->
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames" value="*Dao"/>
        <property name="interceptorNames" value="aroundAdvice"/>
    </bean>
    
</beans>

测试代码:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.hao.aop.tradition.demo1.ICustomerDao;
import com.hao.aop.tradition.demo2.OrderDao;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class AOPTest3 {
    
    @Qualifier("customerDao")
    @Autowired
    private ICustomerDao customerDao;
    
    @Qualifier("orderDao")
    @Autowired
    private OrderDao orderDao;

    @Test
    public void test() {
        orderDao.add();
        orderDao.find();
        customerDao.add();
        customerDao.delete();
    }
}

DefaultAdvisorAutoProxyCreator

根据切面本身包含信息创建代理
配置示例:

<!-- 目标对象 -->
    <bean id="customerDao" class="com.hao.aop.tradition.demo1.CustomerDaoImpl"></bean>
    <bean id="orderDao" class="com.hao.aop.tradition.demo2.OrderDao"></bean>
    
    <!-- 定义增强-->
    <bean id="beforeAdvice" class="com.hao.aop.tradition.demo1.MyBeforeAdvice"></bean>
    <bean id="aroundAdvice" class="com.hao.aop.tradition.demo2.MyAroundAdvice"></bean>

    <!-- 定义一个带有切点的切面 -->
    <bean id="myPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="pattern" value=".*add.*"/>
        <property name="advice" ref="aroundAdvice"/>
    </bean>
    
    <!-- 自动生成代理 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>

测试代码:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.hao.aop.tradition.demo1.ICustomerDao;
import com.hao.aop.tradition.demo2.OrderDao;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext3.xml")
public class AOPTest4 {

    @Autowired
    @Qualifier("customerDao")
    private ICustomerDao customerDao;
    
    @Autowired
    @Qualifier("orderDao")
    private OrderDao orderDao;
    
    @Test
    public void test() {
        customerDao.add();
        customerDao.update();
        
        orderDao.add();
        orderDao.delete();
    }
}

区别:基于ProxyFattoryBean的代理与自动代理

  • ProxyFactoryBean:先有被代理对象,将被代理对象传入到代理类中生成代理.
  • 自动代理基于后处理Bean.在Bean的生成过程中,就产生了代理对象,把代理对象返回.生成Bean已经是代理对象.

AspectJ

概述

AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。
AspectJ是一个基于Java语言的AOP框架
Spring2.0以后新增了对AspectJ切点表达式支持
@AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
新版本Spring框架,建议使用AspectJ方式来开发AOP

AspectJ表达式

  In Spring AOP, to use AspectJ pointcut expression language to define the cut-off point. About Spring AOP AspectJ cut-off point, the most important point is that Spring supports AspectJ only cut point indicator ( pointcut designator) is a subset. Spring is agent-based, and some cut point expression is independent of the proxy-based AOP. Spring AOP supported AspectJ tangential point indicator as follows:

When you try to use other indicators AspectJ in the Spring, will be thrown IllegalArgument-Exception exception. When we look at these Spring support as shown in the indicator, note that only the execution indicator is the practical implementation of matching, while other indicators are used to restrict the match. This indicates that execution is an indicator of our most important indicator used in the preparation of the cut point is defined. On this basis, we use other indicators to limit the matching cut-off point.

execution expression syntax:

execution (<access modifier>? <return type> <method name> (<parameter>) <Exceptions>)


  We use the execution() pointer to select Performance the perform() method. The method of expression to “*” start number, indicating that we do not care method returns the type of value. Then, we specify the fully qualified name of the class and method names. For the method parameter list, we use two dots (..) tables Mingqie point to choose any perform() method, regardless of the method to the Senate Yes.

  请注意我们使用了“&&”操作符把execution()within()指示器连接在一起形成与(and)关系(切点必须匹配所有的指示器)。类似地,我们可以使用“||”操作符来标识或(or)关系,而使用“!”操作符来标识非(not)操作。
  因为“&”在XML中有特殊含义,所以在Spring的XML配置里面描述切点时,我们可以使用and 来代替“&&”。同样,ornot可以分别用来代替“||”“!”

AspectJ增强:

  • @Before 前置通知,相当于BeforeAdvice
  • @AfterReturning 后置通知,相当于AfterReturningAdvice
  • @Around 环绕通知,相当于MethodInterceptor
  • @AfterThrowing抛出通知,相当于ThrowAdvice
  • @After 最终final通知,不管是否异常,该通知都会执行
  • @DeclareParents 引介通知,相当于IntroductionInterceptor (了解)

开发步骤

开发之前需要引入依赖

<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.1.5.RELEASE</version>
</dependency>

基于XML

第一步:编写被增强的类:

 public class ProductDao {
    public int add(){
        System.out.println("添加商品...");
        int d = 10/0;
        return 100;
    }
    public void update(){
        System.out.println("修改商品...");
    }
    public void delete(){
        System.out.println("删除商品...");
    }
    public void find(){
        System.out.println("查询商品...");
    }
}   

第二步:定义切面

import org.aspectj.lang.ProceedingJoinPoint;
/**
 * 切面类
 * @author hao
 *
 */
public class MyAspectXML {
    
    public void before(){
        System.out.println("前置通知...");
    }
    
    public void afterReturing(Object returnVal){
        System.out.println("后置通知...返回值:"+returnVal);
    }
    
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("环绕前增强....");
        Object result = proceedingJoinPoint.proceed();
        System.out.println("环绕后增强....");
        return result;
    }
    
    public void afterThrowing(Throwable e){
        System.out.println("异常通知..."+e.getMessage());
    }
    public void after(){
        System.out.println("最终通知....");
    }
}

第三步:配置applicationContext.xml

<!-- 定义目标对象 -->
    <bean id="productDao" class="com.hao.aop.aspectj.xml.ProductDao"></bean>
    
    <!-- 定义增强 -->
    <bean id="myAspectXML" class="com.hao.aop.aspectj.xml.MyAspectXML"></bean>
    
    <aop:config>
        <!-- 定义切点: -->
        <aop:pointcut id="mypointcut" expression="execution(* com.hao.aop.aspectj.xml.ProductDao.add(..))" />
        <aop:aspect ref="myAspectXML">
            <!-- 前置通知 -->
            <aop:before method="before" pointcut-ref="mypointcut"/>
            <!-- 后置通知 -->
            <aop:after-returning method="afterReturing" pointcut-ref="mypointcut" returning="returnVal"/>
            
            <!-- 环绕通知 -->
            <aop:around method="around" pointcut-ref="mypointcut"/>
             
            <!-- 异常通知 -->
            <aop:after-throwing method="afterThrowing" pointcut-ref="mypointcut" throwing="e"/>
            <!-- 最终通知 -->
            <aop:after method="after" pointcut-ref="mypointcut"/>
        </aop:aspect>
    </aop:config>
基于注解

第一步:导入aop模块;Spring AOP:(spring-aspects)
第二部:定义一个业务逻辑类:在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)

public class UserDao {
    public void add(){
        System.out.println("添加用户");
    }
    public int update(){
        System.out.println("修改用户");
        return 1;
    }
    public void delete(){
        System.out.println("删除用户");
    }
    public void find(){
        System.out.println("查询用户");
        //int d = 1/ 0;
    }
}

第三步:定义一个切面类:切面类里面的方法需要动态感知业务类的方法运行到哪里然后执行;

  1. 给切面类的目标方法标注何时何地运行(通知注解);
  2. 必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect)
/**
 * 切面类:就是切点与增强结合
 * 
 * @author hao
 *
 */
@Aspect
public class MyAspect {

    // 定义一个切点
    @Pointcut("execution(* com.hao.aop.aspectj.anno.UserDao.find(..))")
    private void myPointcut() {} // 此方法没有实际的意义,就是为了提供给注解一个修饰的地方

    @Before("execution(* com.hao.aop.aspectj.anno.UserDao.add(..))")
    public void before(JoinPoint joinPoint) {
        System.out.println("前置增强...." + joinPoint);
    }

    @AfterReturning(value = "execution(* com.hao.aop.aspectj.anno.UserDao.update(..))", returning = "returnVal")
    public void afterReturin(Object returnVal) {
        System.out.println("返回增强....方法的返回值:" + returnVal);

    }

    @Around(value = "MyAspect.myPointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前增强....");
        Object obj = proceedingJoinPoint.proceed();
        System.out.println("环绕后增强....");
        return obj;
    }
    @AfterThrowing(value = "MyAspect.myPointcut()", throwing = "e")
    public void afterThrowing(Throwable e) {
        System.out.println("不好了 出异常了!!!" + e.getMessage());
    }

    @After("MyAspect.myPointcut()")
    public void after() {
        System.out.println("最终/后置通知...");
    }

}

AspectJ types of notifications:

  • Pre-notification (@Before): logStart: running before the target method (div) run
  • After returning advice (@After): logEnd: run (regardless of method of normal or abnormal end) after the end of the target method (div) run
  • Return notification (@AfterReturning): logReturn: run after the target method (div) to return to normal
  • Exception notification (@AfterThrowing): logException: run after the target method (div) abnormal
  • Around advice (@Around): dynamic proxy, manually advance the goals of the method run (joinPoint.procced ())
  • Introduce notification (@DeclareParents), equivalent to IntroductionInterceptor (not required to master)

Cut-off point definition:

// 定义一个切点
@Pointcut("execution(* com.hao.aop.aspectj.anno.UserDao.find(..))")
private void myPointcut() {} // 此方法没有实际的意义,就是为了提供给注解一个修饰的地方

The difference between the Advisor and Aspect?

  • Advisor: Spring cut on the traditional sense: a support point cut and a combination of a notification.
  • Aspect: can support a combination of multiple cut points and multiple notifications.

Step 4: Enable annotations, and cut classes and business logic classes (class where the target method) are added to the vessel

XML ways:

<!-- 自动生成代理  底层就是AnnotationAwareAspectJAutoProxyCreator -->
    <aop:aspectj-autoproxy />

    <bean id="userDao" class="com.hao.aop.aspectj.anno.UserDao"></bean>
    <bean id="myAspect" class="com.hao.aop.aspectj.anno.MyAspect"></bean>

Annotations way

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {
    //业务逻辑类加入容器中
    @Bean 
    public UserDao userDao(){
        return new UserDao();
    }
    //切面类加入到容器中
    @Bean
    public MyAspect myAspect(){
        return new MyAspect();
    }
}

  In addition to the configuration class @EnableAspectJAutoProxy [open] annotation-based aop mode, in Spring many @EnableXXX (to take the time to sort out its principles);

to sum up
  1. The business logic components and cut classes are added to the vessel; tell Spring which is cut class (@Aspect)
  2. Each notification method in the class marked on the notification section annotation, Spring told when and where to run (pointcut expression)
  3. Aop open annotation-based model; @EnableAspectJAutoProxy

AOP mechanism for realization of the principle of (AnnotationAwareAspectJAutoProxyCreator)

The underlying principle AnnotationAwareAspectJAutoProxyCreator

"Pending finishing" ...

Guess you like

Origin www.cnblogs.com/haoworld/p/spring-aop-base.html
Recommended