• 【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注解方式实现机制

  • 相关阅读:
    长沙雅礼中学集训-------------------day1(内含day0)
    17年 5月份刷题版
    manecher_回文串;
    后缀数组
    湖南集训
    好像又好久没更了;计算课noip模拟赛;
    dp的练习题;
    oj1638
    【noi】植物大战僵尸
    #日常吐槽
  • 原文地址:https://www.cnblogs.com/haoworld/p/spring-aop-base.html
Copyright © 2020-2023  润新知