美文网首页
Spring 传统AOP

Spring 传统AOP

作者: 新晋魔法师 | 来源:发表于2019-01-24 09:07 被阅读0次

    什么是AOP

    AOP Aspect Oriented Programing面向切面编程

    AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码,可用于:性能监视、事务管理、安全检查、缓存等

    Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码

    AOP相关术语

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

    代理知识总结

    • Spring在运行期,生成动态代理对象,不需要特殊的编译器
    • Spring AOP的底层就是通过JDK动态代理或CGLib动态代理技术为目标Bean执行横向织入
      • 若目标对象实现了若干接口,Spring使用JDK的java.lang.reflect.Proxy类代理
      • 若目标对象没有实现任何接口,Spring使用CGLIB库生成目标对象的子类
    • 程序中应优先对接口创建代理,便于程序解耦维护
    • 标记为final的方法,不能被代理,因为无法进行覆盖
      • JDK动态代理,是针对接口生成子类,接口中方法不能使用final修饰
      • CGLib是针对目标类生成子类,因此类或方法不能使用final修饰
    • Spring只支持方法连接点,不提供属性连接

    Spring AOP增强类型

    • AOP联盟为通知Advice定义了org.aopalliance.aop.Interface.Advice
    Spring按照通知Advice在目标类方法的连接点位置,可分为5类
    1. 前置通知 org.springframework.aop.MethodBeforeAdvice
    • 在目标方法执行前实施增强
    1. 后置通知 org.springframework.aop.AfterReturningAdvice
    • 在目标方法执行后实施增强
    1. 环绕通知 org.aopalliance.intercept.MethodInterceptor
    • 在目标方法执行前后实施增强
    1. 异常抛出通知 org.springframework.aop.ThrowsAdvice
    • 在方法抛出异常后实施增强
    1. 引介通知 org.springframework.aop.IntroductionInterceptor
    • 在目标类中添加一些新的方法和属性

    Spring AOP切面类型

    1. Advisor:代表一般切面,Advice本身就是一个切面,对目标类所有方法进行拦截
    2. PointcutAdvisor:代表具有切入点的切面,可以指定拦截目标类哪些方法
    3. IntroductionAdvisor:代表引介切面,针对引介通知而使用切面

    Advisor切面案例

    代码

    <!--配置目标类-->
    <bean id="studentDao" class="demo4.StudentDaoImpl" />
    
    <!--前置通知类型-->
    <bean id="myBeforeAdvice" class="demo4.MyBeforeAdvice" />
    
    <!--Spring的AOP产生代理对象-->
    <bean id="studentDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--配置目标类-->
        <property name="target" ref="studentDao" />
        <!--实现接口-->
        <property name="proxyInterfaces" value="demo4.StudentDao" />
        <!--采用拦截的名称-->
        <property name="interceptorNames" value="myBeforeAdvice" />
    </bean>
    

    ProxyFactoryBean常用可配置属性

    • target:代理的目标对象

    • proxyInterfaces:代理要实现的接口

      如果多个接口可以使用列表的方式

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

    • interceptorNames:需要织入目标的Advice

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

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

    PointcutAdvisor切点切面

    • 使用普通Advice作为切面,将对目标类所有方法进行拦截,不够灵活,在实际开发中常采用带有切入点的切面
    • 常用PointcutAdvisor实现类
      1. DefaultPointcutAdvisor最常用的切面类型,它可以通过任意Pointcut和Advice组合定义切面
      2. JdkRegexpMethodPointcut构造正则表达式切点

    代码

    <bean id="studentDao" class="demo4.StudentDao" />
    <bean id="myAdvice" class="demo4.MyAdvice" />
    
    <bean id="myAdvicer" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="pattern" value=".*" />
        <property name="advice" ref="myAdvice" />
    </bean>
    
    <bean id="proxyStudent" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="studentDao"/>
        <property name="proxyTargetClass" value="true"/>
        <property name="interceptorNames" value="myAdvicer" />
    </bean>
    

    自动创建代理

    • 前面的案例中,每个代理都是通过ProxyFactoryBean织入切面代理,在实际开发中,非常多的Bean每个都配置ProxyFactoryBean开发维护量巨大
    • 解决方案:==自动创建代理==
    1. BeanNameAutoProxyCreator根据Bean名称创建代理
    2. DefaultAdvisorAutoProxyCreator根据Advisor本身包含信息创建代理
    3. AnnotationAwareAspectJAutoProxyCreator基于Bean中的AspectJ注释进行自动代理

    BeanNameAutoProxyCreator例子

    • 对所有以DAO结尾Bean所有方法使用代理
    <!--配置基于Bean名称的自动代理-->
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <!--配置Bean名称-->
        <property name="beanNames" value="*Dao" />
        <!--配置增强的名称-->
        <property name="interceptorNames" value="beforeAdvice" />
    </bean>
    

    DefaultAdvisorAutoProxyCreator例子

    • 配置环绕代理案例
    <!--配置目标类-->
    <bean id="personDao" class="demo3.PersonDaoImpl" />
    <!--配置增强-->
    <bean id="proxyPerson" class="demo3.MyPersonProxy" />
    <!--配置切面-->
    <bean id="myadvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!--为add方法添加增强-->
        <property name="pattern" value="demo3.PersonDaoImpl.add" />
        <property name="advice" ref="proxyPerson" />
    </bean>
    <!--创建自动代理-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
    

    相关文章

      网友评论

          本文标题:Spring 传统AOP

          本文链接:https://www.haomeiwen.com/subject/wraejqtx.html