`

Spring Aop

阅读更多

使用Spring AOP,开发者无需实现业务逻辑对象工厂,无需实现代理工厂,这两个工厂都由Spring容器充当。Spring AOP不仅允许使用XML文件配置目标方法,ProxyHandler也允许使用依赖注入管理,Spring AOP提供了更多灵活的选择。
在下面Spring AOP的示例中,InvocationHandler采用动态配置,需要增加的方法也采用动态配置,一个目标对象可以有多个拦截器(类似于代理模式中的代理处理器)。

public interface  Person
{
 void info();
 void run();
}

public class PersonImpl implements Person {
 private String name;
 private int age;
 public void setName(String name) {
  this.name = name;
 }
 public void setAge(int age) {
  this.age = age;
 }
 public void info() {
  System.out.println("我的名字是:  " + name + " , 今年年龄为:  " + age);
 }
 public void run() {
  if (age < 45) {
   System.out.println("我还年轻,奔跑迅速...");
  } else {
   System.out.println("我年老体弱,只能慢跑...");
  }
 }
}

 

为了充分展示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="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
 default-autowire="byName">

 <!--<context:annotation-config /-->
 <!--  配置目标对象-->
 <bean id="personTarget" class="com.fb.spring.aop.PersonImpl">
  <!--  为目标对象注入name属性值-->
  <property name="name">
   <value>Wawa</value>
  </property>
  <!--  为目标对象注入age属性值-->
  <property name="age">
   <value>51</value>
  </property>
 </bean>
 <!--  第一个拦截器-->
 <bean id="myAdvice" class="com.fb.spring.aop.MyBeforeAdvice" />
 <!--  第二个拦截器-->
 <bean id="myAroundInterceptor" class="com.fb.spring.aop.MyAroundInterceptor" />
 <!--  将拦截器包装成Advisor,该对象还确定代理对怎样的方法增加处理-->
 <bean id="runAdvisor"
  class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  <!--  advice属性确定处理bean-->
  <property name="advice">
   <!-- 此处的处理bean定义采用嵌套bean,也可引用容器的另一个bean-->
   <bean class="com.fb.spring.aop.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>com.fb.spring.aop.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();
    }
}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics