Spring AOP示例

这里给出了Spring1.2旧版AOP(基于DTD的实现)的示例。

尽管在Spring 3中支持这种方式,但建议使用我们将在下一页学习的带有AspectJ的Spring AOP。

Spring1.2旧版AOP支持4种类型的通知:

1.Before Advice:在实际方法调用之前执行。
2.After Advice:在实际方法调用之后执行。如果方法返回一个值,则在返回值后执行。
3.Around Advice:在实际方法调用之前和之后执行。
4.Throws Advice:如果实际方法抛出异常,则执行。

要了解Spring AOP的基本概念,请访问前一页。

理解通知接口的层次结构

让我们通过下面的图表来理解通知接口的层次结构:
6c8fc45199773b1cb3baa12cef6d564.png

所有接口都属于AOP。

MethodBeforeAdvice接口扩展BeforeAdvice接口。

AfterReturningAdvice接口扩展AfterAdvice接口。

ThrowsAdvice接口扩展AfterAdvice接口。

MethodInterceptor接口扩展Interceptor接口。在Around Advice中使用。

1)MethodBeforeAdvice示例

创建一个包含实际业务逻辑的类。

文件:A.java

package cn.javatiku;  
public class A {  
public void m(){System.out.println("actual business logic");}  
}  

现在,创建一个实现MethodBeforeAdvice接口的Advisor类。

文件:BeforeAdvisor.java

package cn.javatiku;  
import java.lang.reflect.Method;  
import org.springframework.aop.MethodBeforeAdvice;  
public class BeforeAdvisor implements MethodBeforeAdvice{  
    @Override  
    public void before(Method method, Object[] args, Object target)throws Throwable {  
        System.out.println("additional concern before actual logic");  
    }  
}  

在xml文件中创建3个bean,一个用于A类,第二个用于Advisor类,第三个用于ProxyFactoryBean类。

文件:applicationContext.xml

<?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:p="http://www.springframework.org/schema/p"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  
  
<bean id="obj" class="cn.javatiku.A"></bean>  
<bean id="ba" class="cn.javatiku.BeforeAdvisor"></bean>  
  
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">  
<property name="target" ref="obj"></property>  
<property name="interceptorNames">  
<list>  
<value>ba</value>  
</list>  
</property>  
</bean>  
  
</beans>  

了解ProxyFactoryBean类:

ProxyFactoryBean类由Spring框架提供。它包含两个属性:target和interceptorNames。A类的实例将被视为目标对象,Advisor类的实例将被视为拦截器。您需要将Advisor对象作为列表对象传递,就像上面的xml文件中所示。

ProxyFactoryBean类的代码大致如下:

public class ProxyFactoryBean{  
private Object target;  
private List interceptorNames;  
//getters and setters  
}  

现在,让我们调用实际的方法。

文件:Test.java

package cn.javatiku;  
import org.springframework.beans.factory.BeanFactory;  
import org.springframework.beans.factory.xml.XmlBeanFactory;  
import org.springframework.core.io.ClassPathResource;  
import org.springframework.core.io.Resource;  
public class Test {  
public static void main(String[] args) {  
    Resource r=new ClassPathResource("applicationContext.xml");  
    BeanFactory factory=new XmlBeanFactory(r);  
      
    A a=factory.getBean("proxy",A.class);  
    a.m();  
}  
}  

输出结果:

additional concern before actual logic  
actual business logic  

在MethodBeforeAdvice中打印附加信息
我们可以打印更多的信息,比如方法名称,方法参数,目标对象,目标对象的类名,代理类等。

您只需要更改BeforeAdvisor.java和Test.java这两个类。

文件:BeforeAdvisor.java

package cn.javatiku;  
import java.lang.reflect.Method;  
import org.springframework.aop.MethodBeforeAdvice;  
  
public class BeforeAdvisor implements MethodBeforeAdvice{  
    @Override  
    public void before(Method method, Object[] args, Object target)throws Throwable {  
        System.out.println("additional concern before actual logic");  
        System.out.println("method info:"+method.getName()+" "+method.getModifiers());  
        System.out.println("argument info:");  
        for(Object arg:args)  
            System.out.println(arg);  
        System.out.println("target Object:"+target);  
        System.out.println("target object class name: "+target.getClass().getName());  
    }  
}  

文件:Test.java

package cn.javatiku;  
import org.springframework.beans.factory.BeanFactory;  
import org.springframework.beans.factory.xml.XmlBeanFactory;  
import org.springframework.core.io.ClassPathResource;  
import org.springframework.core.io.Resource;  
public class Test {  
public static void main(String[] args) {  
    Resource r=new ClassPathResource("applicationContext.xml");  
    BeanFactory factory=new XmlBeanFactory(r);  
      
    A a=factory.getBean("proxy",A.class);  
        System.out.println("proxy class name: "+a.getClass().getName());  
    a.m();  
}  
}  

输出结果:

proxy class name: cn.javatiku.A$$EnhancerByCGLIB$$409872b1  
additional concern before actual logic  
method info:m 1  
argument info:  
target Object:cn.javatiku.A@11dba45  
target object class name: cn.javatiku.A  
actual business logic  

AfterReturningAdvice示例

创建一个包含实际业务逻辑的类。

文件:A.java

与上一个示例中的A类相同。

现在,创建一个实现AfterReturningAdvice接口的Advisor类。

文件:AfterAdvisor.java

package cn.javatiku;  
import java.lang.reflect.Method;  
import org.springframework.aop.AfterReturningAdvice;  
public class AfterAdvisor implements AfterReturningAdvice{  
    @Override  
    public void afterReturning(Object returnValue, Method method,  
         Object[] args, Object target) throws Throwable {  
          
        System.out.println("additional concern after returning advice");  
    }  
  
}  

创建与之前示例中的xml文件相同的xml文件,在此处只需要更改advisor类。

文件:applicationContext.xml

<?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:p="http://www.springframework.org/schema/p"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  
  
<bean id="obj" class="cn.javatiku.A"></bean>  
<bean id="ba" class="cn.javatiku.AfterAdvisor"></bean>  
  
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">  
<property name="target" ref="obj"></property>  
<property name="interceptorNames">  
<list>  
<value>ba</value>  
</list>  
</property>  
</bean>  
  
</beans>  

文件:Test.java

与之前的示例相同。

输出结果:

actual business logic
additional concern after returning advice

MethodInterceptor(AroundAdvice)示例

创建一个包含实际业务逻辑的类。

文件:A.java

与之前的示例相同。

现在,创建一个实现MethodInterceptor接口的advisor类。

文件:AroundAdvisor.java

package cn.javatiku;  
import org.aopalliance.intercept.MethodInterceptor;  
import org.aopalliance.intercept.MethodInvocation;  
public class AroundAdvisor implements MethodInterceptor{  
  
    @Override  
    public Object invoke(MethodInvocation mi) throws Throwable {  
        Object obj;  
        System.out.println("additional concern before actual logic");  
        obj=mi.proceed();  
        System.out.println("additional concern after actual logic");  
        return obj;  
    }  
  
}  

创建与之前示例中相同的xml文件,在此处只需更改advisor类。

文件:applicationContext.xml

<?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:p="http://www.springframework.org/schema/p"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  
  
<bean id="obj" class="cn.javatiku.A"></bean>  
<bean id="ba" class="cn.javatiku.AroundAdvisor"></bean>  
  
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">  
<property name="target" ref="obj"></property>  
<property name="interceptorNames">  
<list>  
<value>ba</value>  
</list>  
</property>  
</bean>  
  
</beans>  

文件:Test.java

与之前的示例相同。

输出结果:

additional concern before actual logic  
actual business logic  
additional concern after actual logic  

文件:Validator.java

package cn.javatiku;  
public class Validator {  
    public void validate(int age)throws Exception{  
        if(age<18){  
            throw new ArithmeticException("Not Valid Age");  
        }  
        else{  
            System.out.println("vote confirmed");  
        }  
    }  
}  

文件:ThrowsAdvisor.java

package cn.javatiku;  
import org.springframework.aop.ThrowsAdvice;  
public class ThrowsAdvisor implements ThrowsAdvice{  
    public void afterThrowing(Exception ex){  
        System.out.println("additional concern if exception occurs");  
    }  
}  

文件:applicationContext.xml

<?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:p="http://www.springframework.org/schema/p"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  
  
<bean id="obj" class="cn.javatiku.Validator"></bean>  
<bean id="ba" class="cn.javatiku.ThrowsAdvisor"></bean>  
  
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">  
<property name="target" ref="obj"></property>  
<property name="interceptorNames">  
<list>  
<value>ba</value>  
</list>  
</property>  
</bean>  
  
</beans>  

文件: Test.java

package cn.javatiku;  
  
import org.springframework.beans.factory.BeanFactory;  
import org.springframework.beans.factory.xml.XmlBeanFactory;  
import org.springframework.core.io.ClassPathResource;  
import org.springframework.core.io.Resource;  
  
public class Test {  
public static void main(String[] args) {  
    Resource r=new ClassPathResource("applicationContext.xml");  
    BeanFactory factory=new XmlBeanFactory(r);  
      
    Validator v=factory.getBean("proxy",Validator.class);  
    try{  
    v.validate(12);  
    }catch(Exception e){e.printStackTrace();}  
}  
}  

输出:

java.lang.ArithmeticException: Not Valid Age  
  
additional concern if exception occurs  
  
    at cn.javatiku.Validator.validate(Validator.java:7)  
    at cn.javatiku.Validator$$FastClassByCGLIB$$562915cf.invoke(<generated>)  
    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)  
    at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invoke  
Joinpoint(Cglib2AopProxy.java:692)  
    at org.springframework.aop.framework.ReflectiveMethodInvocation.  
proceed(ReflectiveMethodInvocation.java:150)  
    at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.  
invoke(ThrowsAdviceInterceptor.java:124)  
    at org.springframework.aop.framework.ReflectiveMethodInvocation.  
proceed(ReflectiveMethodInvocation.java:172)  
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.  
intercept(Cglib2AopProxy.java:625)  
    at cn.javatiku.Validator$$EnhancerByCGLIB$$4230ed28.validate(<generated>)  
    at cn.javatiku.Test.main(Test.java:15)  

标签: spring, Spring教程, Spring技术, Spring语言学习, Spring学习教程, Spring下载, Spring框架, Spring框架入门, Spring框架教程, Spring框架高级教程, Spring面试题, Spring笔试题, Spring编程思想