Spring教程-Spring AOP示例
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的基本概念,请访问前一页。
理解通知接口的层次结构
让我们通过下面的图表来理解通知接口的层次结构:
所有接口都属于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)