zoukankan      html  css  js  c++  java
  • Spring AOP介绍

         Spring的AOP是上面代理模式的深入。使用Spring AOP,开发者无需实现业务逻辑对象工厂,无需实现代理工厂,这两个工厂都由Spring容器充当。Spring AOP不仅允许使用XML文件配置目标方法,ProxyHandler也允许使用依赖注入管理,Spring AOP提供了更多灵活的选择。
    在下面Spring AOP的示例中,InvocationHandler采用动态配置,需要增加的方法也采用动态配置,一个目标对象可以有多个拦截器(类似于代理模式中的代理处理器)。
    下面是原始的目标对象:
    //目标对象的接口
    public interface  Person
    {
     //该接口声明了两个方法
     void info();
     void run();
    }
    下面是原始目标对象的实现类,实现类的代码如下:
    //目标对象的实现类,实现类实现Person接口
    public class PersonImpl implements Person
    {
     //两个成员属性
     private String name;
     private int age;
     //name属性的 setter方法
     public void setName(String name)
     {
      this.name = name;
     }
     //age属性的setter方法
    public void setAge(int age)
     {
      this.age = age;
     }
     //info方法,该方法仅仅在控制台打印一行字符串
     public void info()
     {
      System.out.println("我的名字是:  " + name + " , 今年年龄为:  " + age);
     }
     //run方法,该方法也在控制台打印一行字符串。
     public void run()
     {
      if (age < 45)
      {
       System.out.println("我还年轻,奔跑迅速...");
      }
      else
      {
       System.out.println("我年老体弱,只能慢跑...");
      }
     }
    }
    该Person实例将由Spring容器负责产生和管理,name属性和age属性也采用依赖注入管理。
    为了充分展示Spring AOP的功能,此处为Person对象创建三个拦截器。第一个拦截器是调用方法前的拦截器,代码如下:
    //调用目标方法前的拦截器,拦截器实现MethodBeforeAdvice接口
    public class MyBeforeAdvice implements MethodBeforeAdvice
    {
     //实现MethodBeforeAdvice接口,必须实现before方法,该方法将在目标
     //方法调用之前,自动被调用。
         public void before(Method m, Object[] args, Object target) throws Throwable
     {
      System.out.println("方法调用之前...");
      System.out.println("下面是方法调用的信息:");
      System.out.println("所执行的方法是:" + m);
      System.out.println("调用方法的参数是:" + args);
      System.out.println("目标对象是:" + target);
         }
    }
    第二个拦截器是方法调用后的拦截器,该拦截器将在方法调用结束后自动被调用,拦截器代码如下:
    //调用目标方法后的拦截器,该拦截器实现AfterReturningAdvice接口
    public class MyAfterAdvice implements AfterReturningAdvice
    {
     //实现AfterReturningAdvice接口必须实现afterReturning方法,该方法将在目标方法
     //调用结束后,自动被调用。
         public void afterReturning(Object returnValue, Method m, Object[] args, Object target)throws Throwable
     {
      System.out.println("方法调用结束...");
    System.out.println("目标方法的返回值是 : " + returnValue);
      System.out.println("目标方法是 : " + m);
      System.out.println("目标方法的参数是 : " + args);
      System.out.println("目标对象是 : " + target);
        }
    }
    第三个拦截器是是Around拦截器,该拦截器既可以在目标方法之前调用,也可以在目标方法调用之后被调用。下面是Around拦截器的代码:
    //Around拦截器实现MethodInterceptor接口
    public class MyAroundInterceptor implements MethodInterceptor
    {
     //实现MethodInterceptor接口必须实现invoke方法
         public Object invoke(MethodInvocation invocation) throws Throwable
     {
      //调用目标方法之前执行的动作
             System.out.println("调用方法之前: invocation对象:[" + invocation + "]");
      //调用目标方法
             Object rval = invocation.proceed();
      //调用目标方法之后执行的动作
             System.out.println("调用结束...");
             return rval;
        }
    }
    利用Spring AOP框架,实现之前的代理模式相当简单。只需要实现对应的拦截器即可,无需创建自己的代理工厂,只需采用Spring容器作为代理工厂。下面在Spring配置文件中配置目标bean,以及拦截器。
    下面是Spring配置文件的代码:
    <?xml version="1.0" encoding="gb2312"?>
    <!--  Spring配置文件的文件头-->
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
     "http://www.springframework.org/dtd/spring-beans.dtd">
    <!--  Spring配置文件的根元素-->
    <beans>
     <!--  配置目标对象-->
     <bean id="personTarget" class="lee.PersonImpl">
      <!--  为目标对象注入name属性值-->
      <property name="name">
       <value>Wawa</value>
      </property>
      <!--  为目标对象注入age属性值-->
      <property name="age">
       <value>51</value>
      </property>
     </bean>
     <!--  第一个拦截器-->
     <bean id="myAdvice" class="lee.MyBeforeAdvice"/>
     <!--  第二个拦截器-->
     <bean id="myAroundInterceptor" class="lee.MyAroundInterceptor"/>
    <!--  将拦截器包装成Advisor,该对象还确定代理对怎样的方法增加处理-->
     <bean id="runAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
      <!--  advice属性确定处理bean-->
      <property name="advice">
       <!-- 此处的处理bean定义采用嵌套bean,也可引用容器的另一个bean-->
       <bean class="lee.MyAfterAdvice"/>
      </property>
      <!--  patterns确定正则表达式模式-->
      <property name="patterns">
       <list>
        <!--  确定正则表达式列表-->
        <value>.*run.*</value>
       </list>
      </property>
     </bean>
     <!--  使用ProxyFactoryBean 产生代理对象-->
     <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
      <!--  代理对象所实现的接口-->
      <property name="proxyInterfaces">
       <value>lee.Person</value>
      </property>
      <!--  设置目标对象-->
      <property name="target">
       <ref local="personTarget"/>  
      </property>
      <!--  代理对象所使用的拦截器-->
      <property name="interceptorNames">
       <list>
        <value>runAdvisor</value>
        <value>myAdvice</value>
        <value>myAroundInterceptor</value>
       </list>
      </property>
     </bean>
    </beans>
    该配置文件使用ProxyFactoryBean来生成代理对象,配置ProxyFactoryBean工厂bean时,指定了target属性,该属性值就是目标对象,该属性值为personTarget,指定代理的目标对象为personTarget。通过interceptorNames属性确定代理需要的拦截器,拦截器可以是普通的Advice,普通Advice将对目标对象的所有方法起作用,拦截器也可以是Advisor,Advisor是Advice和切面的组合,用于确定目标对象的哪些方法需要增加处理,以及怎样的处理。在上面的配置文件中,使用了三个拦截器,其中myAdvice、myAroundInterceptor都是普通Advice,它们将对目标对象的所有方法起作用。而runAdvisor则使用了正则表达式切面,匹配run方法,即该拦截器只对目标对象的run方法起作用。

    下面是测试代理的主程序:
    public class BeanTest
    {
        public static void main(String[] args)throws Exception
    {
      //创建Spring容器
    ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
      //获取代理对象
      Person p = (Person)ctx.getBean("person");
      //执行info方法
      p.info();
             System.out.println("===========================================");
      //执行run方法
      p.run();
        }
    }
    下面是程序的执行结果:
    方法调用之前...
    下面是方法调用的信息:
    所执行的方法是:public abstract void lee.Person.info()
    调用方法的参数是:null
    目标对象是:lee.PersonImpl@b23210
    调用方法之前: invocation对象:[invocation: method 'info', arguments
    []; target is of class [lee.PersonImpl]]
    我的名字是:  Wawa , 今年年龄为:  51
    调用结束...
    ===========================================
    方法调用之前...
    下面是方法调用的信息:
    所执行的方法是:public abstract void lee.Person.run()
    调用方法的参数是:null
    目标对象是:lee.PersonImpl@b23210
    调用方法之前: invocation对象:[invocation: method 'run', arguments [
    ]; target is of class [lee.PersonImpl]]
    我年老体弱,只能慢跑...
    调用结束...
    方法调用结束...
    目标方法的返回值是 : null
    目标方法是 : public abstract void lee.Person.run()
    目标方法的参数是 : null
    目标对象是 : lee.PersonImpl@b23210
    程序的执行结果中一行“=”用于区分两次调用的方法。在调用info方法时,只有myAdvice和myAroundInterceptor两个拦截器起作用,调用run方法时候,三个拦截器都起作用了。

           通过上面的介绍,可看出Spring的AOP框架是对代理模式简化,并拓展了代理模式的使用。
    Spring AOP是Spring声明式事务的基础。了解Spring AOP对深入理解Spring的声明式事务管理是非常有好处的。Spring AOP还可以完成很多功能,例如基于AOP的权限检查。

  • 相关阅读:
    服务器上往Mongo导入json文件里的数据
    在Flask蓝图中使用动态URL前缀
    python 的 optparser库
    lowB 三人组
    Linux基础介绍
    html的q标签、blockquote标签
    单冒号伪元素和双冒号伪元素
    CSS中的伪元素选择器
    CSS中的选择器
    CSS中的关系选择器
  • 原文地址:https://www.cnblogs.com/lowerCaseK/p/an_example_aop_spring.html
Copyright © 2011-2022 走看看