Java Web学习(八)

AOP的应用场合是受限的,它一般只适合于那些具有横切逻辑的应用场合:性能检测,访问控制、事务管理,日志记录等

  1. AOP是什么?

    Aspect Oriented Programming。面向方面编程。

    一些重复代码无法通过纵向继承(即抽象父类)的方式来消除,AOP提供了一种解决这类无法通过纵向编程解决的问题的方法,即通过横向抽取机制。

  2. AOP概念

    ①连接点(JoinPoint)

    一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点称为连接点。连接点由两个信息确定,第一为用方法表示的程序执行点,第二是用相对点表示的方位。

    ②切点(PointCut)

    一个类中有多个连接点,如何定位到某一个特定的连接点呢?AOP通过切点来定位连接点。切点只定位到某个方法上,具体的方位还不能确定.

    ③增强(Advice)

    增强是织入到目标类连接点上的一段代码。增强除了用来描述一段程序代码外,还拥有连接点的方位、

    只有结合切点和增强才能够确定特定的连接点并实施增强逻辑。

    ④目标对象(Target)

    增强逻辑的织入目标类

    ⑤引入(Introduction)

    引入是一种特殊的增强。它为类添加一些属性和方法。即即使一个业务类没有实现某个接口,通过AOP的引入功能,可以动态地为该业务类添加接口的实例逻辑,让业务类成为这个接口的实现类。

    ⑥织入(Weaving)

    织入是将增强添加到目标类具体连接点上的过程。AOP由三种织入的方式:编译器织入,类装载器织入,动态代理织入。

    ⑦代理(Proxy)

    一个类被AOP织入增强后,就产生一个结果类,它是融合了原类和增强逻辑的代理类。代理类可能是与原类实现相同接口的类,也可能就是原类的子类。所以可以以调用原类相同的方法来调用代理类。

    ⑧切面(Aspect)

    切面由切点和增强组成,它既包括了横切逻辑的定义,也包括了连接点的定义。AOP将切面所定义的横切逻辑织入到切面定义的连接点中。

  3. 通过创建增强类的方式来实现AOP

    步骤:①首先创建增强类,通过实现某个接口(BeforeAdvice, AfterReturningAdvice, MethodInterceptor, ThrowsAdvice, IntroductionInterceptor)来实现一个增强逻辑类。

             ②在Spring配置文件中进行配置。首先配置一个Advice Bean和目标对象Bean,然后创建一个代理Bean(ProxyFactoryBean),在代理Bean中配置interfaces。target,advice等等属性;

             ③得到代理Bean,调用业务方法。

    ①定义一个接口
    public interface Waiter {
         void greetTo(String name);
        void serveTo(Sring name);
    }
    ②实现此接口
    public class MyWaiter implements Waiter {
         public void greetTo(String name){
              System.out.println("hello!"+name);
        }
        
        public void serveTo(String name){
              System.out.println("serving"+name);
         }
    } 
    ③创建增强类
    public class GreetingBeforeAdvice implements MethodBeforeAdvice {
         public void before(Method method, Object[] args, Object obj){
              String name = (String) args[0];
             System.out.println("before " + name);
         }
     }
     
    ④配置AOP
    <bean id="beforeAdvice" class="GreetingBeforeAdvice"/>
    <bean id="target" class="MyWaiter"/>
    <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean">
          <property name="proxyInterfaces" value="Waiter"/>
          <property name="interceptorNames">
               <list>
                     <idref local="beforeAdvice"/>
              </list>
          </property>
         <property name="target" ref="target"/>
    </bean>
    ⑤调用业务方法     
    Waiter waiter = (Waiter) ctx.getBean("waiter");
    waiter.greetTo("kaka");

    ProxyFactoryBean为其他Bean创建代理实例。它的可配置属性有target、proxyInterfaces、interceptorNames、singleton、optimize。proxyTargetClass(设置为true是使用CGLib进行代理)

    说明:public void before(Method method, Object[] args, Object obj)中method为要加入增强逻辑的方法,args为方法入参,obj为代理目标对象

    public void afterReturning(Method method, Object[] args, Object obj)、

    Object invoke(MethodInvocation invocation) { Object[] args = invocation.getArguments(); Object resuld = invocation.proceed();}

    public void afterThrowing(Method method, Object[] args, Object obj, Exception ex)

    比较特殊的一个是引入增强。他不是在目标方法周围织入增强,而是为目标类创建新的属性或方法,所以引入增强的连接点是类级别的,而非方法级别的。一般通过扩展DelegatingIntroductionInterceptor类。

    定义一个接口
    public interface Monitor {
        void setMonitorActive(boolean active);
    }
    定义一个引入增强类
    public class IntroductionAdvice extends DelegatingIntrodutionInterceptor implements Monitor {
           private ThreadLocal<Boolean> map = new ThreadLocal<>();
         
          public void setMonitorActive(boolean active){
                   map.set(active);
            }
            
            public Object invoke(MethodInvocation invocation){
                  Object obj = null;
                  if(map.get()){
                        begin();
                       obj = super.invoke(invocation);
                       end();
                  }else{
                        obj = super.invoke(invocation);
                  }
                  return obj;
             }
     }
     
     配置引入增强
     
    <bean id="introductionAdvice" class="IntroductionAdvice"/>
    <bean id="target" class="MyWaiter"/>
    <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean">
          <property name="interfaces" value="...Monitor"/>
          <property name="interceptorNames">
               <list>
                     <idref local="beforeAdvice"/>
              </list>
          </property>
         <property name="target" ref="target"/>
         <property name="proxyTargetClass" value="true"/>
    </bean>
    调用业务方法
    Waiter waiter = (Waiter) ctx.getBean("waiter");
    waiter.greetTo("kaka");
    Monitor monitor = (Monitor) waiter;
    monitor.setMonitorActive(true);
    monitor.greetTo("kaka")
  4. 通过创建切面(Aspect)的方式来实现AOP

    切面同时包含横切代码和连接点信息。切面可分为三类:一般切面,切点切面,引入切面

     ‍      PointcutAdvisor有6个主要的实现类:DefaultPointcutAdvisor, NameMatchMethodPointcutAdvisor, RegexpMethodPointcutAdvisor, StaticMethodMatcherPointcutAdvisor, AspectJExpressionPointcutAdvisor, AspectJPointcutAdvisor。

    ①静态方法名匹配切面

    步骤:1)定义目标类; 2)定义切面; 3)定义增强类;4)配置切面;5)运行业务代码 

    public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor {
          public bolean matches(Method method, Class clazz){
               return "greetTo".equals(method.getName());
          }
          
          public ClassFilter getClassFilter(){
               return new ClassFilter(){
                     public boolean matches(Class clazz){
                           return Waiter.class.isAssignable(clazz);
                     }
              };
          }
    }      
    配置
    <bean id="target" class="MyWaiter"/>
    <bean id="beforeAdvice" class="GreetingBeforeAdvice"/>
    <bean id="beforeAdvisor" class="GreetingAdvisor"/>
            <property name="advisor" ref="beforeAdvice"/>
    </bean>
    <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean">
          <property name="interceptorNames">
               <list>
                     <idref local="beforeAdvisor"/>
              </list>
          </property>
          <property name="target" ref="target"/>
          <property name="targetProxyClass" value="true"/>
    </bean>

    ②静态正则表达式方法匹配切面

    只需配置即可

    <bean id="beforeAdvice" class="GreetingBeforeAdvice"/>
    <bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
          <property name="patterns">
                <list>
                     <value>.*greet.*</value>
                </list>
          </proerty>
          <property name="advice" ref="beforeAdvice"/>
    </bean>
    <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean">
          <property name="interceptorNames">
               <list>
                     <idref local="regexpAdvisor"/>
              </list>
          </property>
          <property name="target" ref="target"/>
         <property name="targetProxyClass" value="true"/>
    </bean>

     

  5. 自动创建代理

    在前面的例子中,我们通过PRoxyFactoryBean创建织入切面的代理,但每一个需要被代理的Bean都需要一个单独的PRoxyFactoryBean进行配置,这样配置很是麻烦。所以Spring引入了自动代理机制,让容器为我们自动生成代理,将我们从繁琐的配置工作中解放出来。在内部,Spring用BeanPostProcessor自动的完成这项工作。

    ①实现类

    基于BeanPostProcessor的自动创建器的实现类,将根据一些规则自动的在容器实例化Bean时为匹配的Bean生成代理实例。

    这些代理创建器可以分为一下三类:

    ~根据Bean配置名规则的自动代理创建器,BeanNameAutoProxyCreator

    ~基于Advisor匹配机制的自动代理创建器 DefaultAdvisorAutoProxyCreator

    ~基于Bean中AspectJ注解标签的自动代理创建器 AnnotatiobAwareAspectJAutoProxyCreator

    ②使用Bean名进行自动代理

    <bean id="beforeAdvice" class="GreetingBeforeAdvice"/>
    <bean id="nameCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
           <property name="beanNames" value="*er"/>
          <property name="interceptorNames">
               <idref local="beforeAdvice"/>
          </property>
    </bean>

    ③使用Advisor自动代理创建器

    因为Advisor切面已经包括了连接点信息和横切逻辑,所以直接而配置一自动代理创建器即可

<bean id="beforeAdvice" class="GreetingBeforeAdvice"/>

<bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">

      <property name="patterns">

            <list>

                 <value>.*greet.*</value>

            </list>

      </proerty>

      <property name="advice" ref="beforeAdvice"/>

</bean>

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

 

 

 

 

 

你可能感兴趣的:(Java Web学习(八))