初识 Spring AOP

Spring AOP(传统AOP)

1. 什么是AOP

  • AOP (Aspect Oriented Programing) :面向切面编程
  • AOP采取横向抽取机制,取代了传统的纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)
  • Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期,通过代理方式向目标类织入增强代码

2. AOP相关术语

  • Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
  • Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.
  • Advice(通知/增强):所谓通知是指拦截到 Joinpoint之后所要做的事情就是通知。通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
  • Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field。
  • Target(目标对象):代理的目标对象
  • Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入
  • Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
  • Aspect(切面):是切入点和通知(引介)的结合

3.Spring AOP 增强类型

  • AOP联盟为通知Advice定义了org.aopalliance.aop.Interface.Advice

  • Spring按照通知Advice在目标类方法的连接点位置,可以分为5类

    – 前置通知 org.springframework.aop.MethodBeforeAdvice

    • 在目标方法执行前实施增强

    – 后置通知org.springframework.aop.AfterReturningAdvice

    • 在目标方法执行后实施增强
  • 环绕通知 org.aopalliance.intercept.MethodInterceptor

  • 在目标方法执行前后实施增强

  • 异常抛出通知 org.springframework.aop.ThrowsAdvice

    • 在方法抛出异常后实施增强

传统AOP的底层实现

1.JDK动态代理

只能对实现接口的类产生动态代理

类 Proxy,控制其中的 invoke 方法

//此类继承 InvocationHandler 该类
Object proxy = Proxy.newProxyInstance(userDao.getClass.getClassLoader(),
                                                                  userDao.getClass.getInterfaces(),this);
//第一个参数:类加载器   第二个参数:该类所实现的接口   第三个参数:接口 InvocationHandler

2.CGLIB动态代理

底层实现:采用非常底层字节码技术,可以为一个类创建子类,生成一个类来继承目标类 , 解决没有实现接口也可以进行增强的问题

//此类继承 MethodInterceptor 类

//创建代理的方法
    public Object createProxy(){
        //1.创建核心类
        Enhancer enhancer = new Enhancer();
        //2.设置父类
        enhancer.setSuperclass(productDao.getClass());
        //3.设置回调
        enhancer.setCallback(this);
        //4.生成代理
        Object proxy = enhancer.create();
        return proxy;
    }

Spring AOP的切面类型的介绍

  • Advisor:代表一般切面,Advice本身就是一个切面,对目标类所有方法进行拦截 (对所有目标进行增强)
  • PointcutAdvisor:代表具有切点的切面,可以指定拦截目标类哪些方法
  • IntroductionAdvisor:代表引介切面,针对引介通知而使用切面(不要求掌握

1.Advisor一般切面案例

  1. ProxyFactoryBean常用可配置属性
  • target:代理的目标对象
  • proxyInterfaces:代理要实现的接口
    • 如果多个接口可以使用以下格式赋值



  1. proxyTargetClass:是否对类代理而不是接口,设置为true时,使用CGLib代理

  2. interceptorNames:需要织入目标的Advice

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

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

    <!--配置目标类==========================-->
        <bean id="studentDao" class="com.tao.aop.demo3.StudentDaoImpl"/>
    
        <!--前置通知类型=========================-->
        <bean id="myBeforeAdvice" class="com.tao.aop.demo3.MyBeforeAdvice"/>
    
        <!--Spring 的AOP 产生代理对象==============-->
        <bean id="studentDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <!--配置目标类-->
            <property name="target" ref="studentDao"/>
            <!--实现的接口-->
            <property name="proxyInterfaces" value="com.tao.aop.demo3.StudentDao"/>
            <!--采用拦截的名称-->
            <property name="interceptorNames" value="myBeforeAdvice"/>
            <!--optimize:当设置为true时,强制使用CGLib-->
            <property name="optimize" value="true"/>
        </bean>
    

2.PointcutAdvisor 切点切面

  • 使用普通Advice作为切面,将对目标类所有方法进行拦截,不够灵活,在实际开发中常采用带有切点的切面
  • 常用PointcutAdvisor 实现类
    • DefaultPointcutAdvisor最常用的切面类型,它可以通过任意Pointcut和Advice组合定义切面
    • JdkRegexpMethodPointcut 构造正则表达式切点
	<!--配置目标类=======================-->
    <bean id="customerDao" class="com.tao.aop.demo4.CustomerDao"/>

    <!--配置通知 环绕通知================-->
    <bean id="myAroundAdvice" class="com.tao.aop.demo4.MyAroundAdvice"/>

    <!--一般的切面是使用通知作为切面的,因为要对目标类的某些方法进行增强,就需要配置一个带有切入点的切面-->
    <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!--pattern 中配置正则表达式: .任意字符  *任意次数 -->
        
        <!--对所有进行增强-->
        <!--<property name="pattern" value=".*"/>-->
        <!--只对save(某一个方法)方法进行增强-->
        <!--<property name="pattern" value=".*save.*"/>-->
        <!--对多个表达式进行增强-->
        <property name="patterns" value=".*save.*,.*delete.*"/>
        
        <property name="advice" ref="myAroundAdvice"/>
    </bean>
    <!--配置产生代理=====================-->
    <bean id="customerDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="customerDao"/>
        <property name="proxyTargetClass" value="true"/>
        <property name="interceptorNames" value="myAdvisor"/>
    </bean>

3.自动创建代理

由于非常多的Bean每个都配置ProxyFactoryBean开发维护量巨大

  • BeanNameAutoProxyCreator 根据Bean名称创建代理
  • DefaultAdvisorAutoProxyCreator 根据Advisor本身包含信息创建代理
  • AnnotationAwareAspectJAutoProxyCreator基于Bean中的AspectJ注解进行自动代理
1.BeanNameAutoProxyCreator: 基于Bean名称的自动代理
  • 对所有以DAO结尾Bean所有方法使用代理
<!--配置目标类-->
    <bean id="studentDao" class="com.tao.aop.demo5.StudentDaoImpl"/>
    <bean id="customerDao" class="com.tao.aop.demo5.CustomerDao"/>

    <!--配置增强(通知)-->
    <bean id="myBeforeAdvice" class="com.tao.aop.demo5.MyBeforeAdvice"/>
    <bean id="myAroundAdvice" class="com.tao.aop.demo5.MyAroundAdvice"/>
	
	<!--产生代理-->
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames" value="*Dao"/>
        <property name="interceptorNames" value="myBeforeAdvice"/>
    </bean>
2.DefaultAdvisorAutoProxyCreator: 基于切面信息产生代理
<!--配置目标类-->
    <bean id="studentDao" class="com.tao.aop.demo6.StudentDaoImpl"/>
    <bean id="customerDao" class="com.tao.aop.demo6.CustomerDao"/>

    <!--配置增强(通知)-->
    <bean id="myBeforeAdvice" class="com.tao.aop.demo6.MyBeforeAdvice"/>
    <bean id="myAroundAdvice" class="com.tao.aop.demo6.MyAroundAdvice"/>

    <!--配置切面-->
    <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="pattern" value="com\.tao\.aop\.demo6\.CustomerDao\.save"/>
        <property name="advice" ref="myAroundAdvice"/>
    </bean>

    <!--根据切面的信息产生代理-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值