【Spring】 AOP Base

一、AOP概述

  AOP(Aspect Oriented Programing),面向切面编程,AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)
  Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
  AspecJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入

二、AOP的术语:

  • 连接点(Joinpoint):所谓连接点是指那些被拦截到的点。在Spring中,这些点指的是方法,因为Spring只支持方法类型的连接点.
  • 切入点(Pointcut):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.
  • 通知/增强(Advice):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.
    • 前置通知(Before advice):在目标方法被调用之前调用通知方法
    • 后置通知(After/finally advice):在目标方法完成之后 调用通知方法,此时不会关心方法的输出是什么
    • 返回通知(After returning advice):在目标方法成功执行之后调用通知
    • 异常通知(After throwing advice):在目标方法抛出异常之后调用通知
    • 环绕通知(Around advice):通知包裹了被通知的方法,在被通知的方法调用之前调用之后执行自定义的行为
  • 引介/引入(Introduction):引介是一种特殊的通知,在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field
  • 目标对象(Target):代理的目标对象
  • 织入(Weaving):是指把增强应用到目标对象创建新的代理对象的过程. Spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入
  • 代理(Proxy):一个类被AOP织入增强后,就产生一个结果代理类
  • 切面(Aspect):是切入点和通知(引介)的结合

    在一个和多个连接点上可以把切面的功能(通知)织入到程序的执行过程中

AOP的术语

三、AOP底层原理

SpringAOP实现机制主要有两种:

  1. JDK动态代理:对实现了接口的类生成代理
  2. CGLib代理机制:对类生成代理

详见代理模式

四、Spring 中的AOP

1. 概述

2. 分类

  1. 基于代理的经典Spring AOP(传统AOP)
  2. 纯POJO切面;
  3. @AspectJ注解驱动的切面;
  4. 注入式AspectJ切面(适用于Spring各版本)。

3. Spring的传统AOP

  AOP:不是由Spring定义.AOP联盟的组织定义.

Spring中的通知:(增强代码)

  1. 前置通知:在目标方法执行前实施增强,要实现的接口org.springframework.aop.MethodBeforeAdvice
  2. 后置通知:在目标方法执行后实施增强,要实现的接口,org.springframework.aop.AfterReturningAdvice
  3. 环绕通知:在目标方法执行前后实施增强,要实现的接口,org.aopalliance.intercept.MethodInterceptor
  4. 异常抛出通知:在方法抛出异常后实施增强,要实现的接口,org.springframework.aop.ThrowsAdvice
  5. 引介通知:在目标类中添加一些新的方法和属性,要实现的接口,org.springframework.aop.IntroductionInterceptor

针对所有方法的增强:(不带有切点的切面)

需要引入的Maven坐标:

<!-- 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>

编写被代理对象

接口:

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

实现类:

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("查询客户");
    }
}

编写增强的代码

前置增强:

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("前置增强。。。。。");
    }

}

生成代理:(在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>

在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();
    }
}

4. 自动代理

  前面的案例中,每个代理都是通过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="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,后处理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已经是代理对象.

5. AspectJ

概述

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

AspectJ表达式

  在Spring AOP中,要使用AspectJ的切点表达式语言来定义切点。关于Spring AOP的AspectJ切点,最重要的一点就是Spring仅支持AspectJ切点指示器(pointcut designator)的一个子集。Spring是基于代理的,而某些切点表达式是与基于代理的AOP无关的。Spring AOP所支持的AspectJ切点指示器如下:

在Spring中尝试使用AspectJ其他指示器时,将会抛出IllegalArgument-Exception异常。当我们查看如上所展示的这些Spring支持的指示器时,注意只有execution指示器是实际执行匹配的,而其他的指示器都是用来限制匹配的。这说明execution指示器是我们在编写切点定义时最主要使用的指示器。在此基础上,我们使用其他指示器来限制所匹配的切点。

execution 表达式语法:

execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)


  我们使用execution()指示器选择Performanceperform()方法。方法表达式以“*”号开始,表明了我们不关心方法返回值的类型。然后,我们指定了全限定类名和方法名。对于方法参数列表,我们使用两个点号(..)表明切点要选择任意的perform()方法,无论该方法的入参是什么。

  请注意我们使用了“&&”操作符把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的通知类型:

  • 前置通知(@Before):logStart:在目标方法(div)运行之前运行
  • 后置通知(@After):logEnd:在目标方法(div)运行结束之后运行(无论方法正常结束还是异常结束)
  • 返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后运行
  • 异常通知(@AfterThrowing):logException:在目标方法(div)出现异常以后运行
  • 环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())
  • 引介通知(@DeclareParents) ,相当于IntroductionInterceptor (不要求掌握)

切点的定义:

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

Advisor和Aspect的区别?

  • Advisor:Spring传统意义上的切面:支持一个切点和一个通知的组合.
  • Aspect:可以支持多个切点和多个通知的组合.

第四步:开启注解,并将切面类和业务逻辑类(目标方法所在类)都加入到容器中

XML方式:

<!-- 自动生成代理  底层就是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>

注解方式

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();
    }
}

测试

  • 注意加载的配置文件
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(classes=MainConfigOfAOP.class)
//此处的配置文件可以加载java类 或者 XML文件
//@ContextConfiguration("classpath:contextApplication5.xml") 
public class AOPTest2 {

    @Autowired
    @Qualifier("userDao")
    private UserDao userDao;
    @Test
    public void demo1(){
        userDao.add();
        userDao.delete();
        userDao.update();
        userDao.find();
    }
}

  给配置类中加@EnableAspectJAutoProxy【开启基于注解的aop模式】,在Spring中很多的 @EnableXXX(要抽时间整理一下其原理);

总结
  1. 将业务逻辑组件和切面类都加入到容器中;告诉Spring哪个是切面类(@Aspect)
  2. 在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
  3. 开启基于注解的aop模式;@EnableAspectJAutoProxy

6. AOP的实现机制原理(AnnotationAwareAspectJAutoProxyCreator)

AnnotationAwareAspectJAutoProxyCreator 底层的原理

已经整理完,查阅【Spring】AOP注解方式实现机制

原文地址:https://www.cnblogs.com/haoworld/p/spring-aop-base.html