下面所有代码和示例仅仅是为了讲解spring aop,不能用于实际开发,因为实际没有这样用的,但是看看,理解下肯定是有好处的。
示例:对于更新或者删除用户来说,我们要进行事务管理,更新或删除之前要打开事务,之后要提交事务。
这里以更新来作为示例。
spring可以利用jdk或cglid来生成动态代理,我们直接利用cglib对类进行代理,不创建interface了。
UserService:
package spring3.aop.aop1; public class UserService { public void updUser() { System.out.println("UserService updUser!"); } }
创建前置增强 OpenTransaction:
package spring3.aop.aop1; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class OpenTransaction implements MethodBeforeAdvice { /** * 前置增强 * * @param method 目标类方法 * @param args 目标类方法的入参 * @param obj 目标类实例 */ @Override public void before(Method method, Object[] args, Object obj) throws Throwable { System.out.println("Open Transaction"); } }
创建后置增强 CommitTransaction:
package spring3.aop.aop1; import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; public class CommitTransaction implements AfterReturningAdvice { /** * 后置增强 * * @param returnObj 目标类方法返回的结果 * @param method 目标类方法 * @param args 目标类方法的入参 * @param obj 目标类实例 */ @Override public void afterReturning(Object returnObj, Method method, Object[] args, Object obj) throws Throwable { System.out.println("Close Transaction"); } }
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="beforeAdvice" class="spring3.aop.aop1.OpenTransaction"/> <bean id="afterAdvice" class="spring3.aop.aop1.CommitTransaction"/> <bean id="target" class="spring3.aop.aop1.UserService"/> <bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="beforeAdvice, afterAdvice" p:target-ref="target"/> </beans>
我们可以通过编码方式和配置方式来完成织入,现在我们来写测试类 TestAdvice:
package spring3.aop.aop1; import org.springframework.aop.AfterReturningAdvice; import org.springframework.aop.BeforeAdvice; import org.springframework.aop.framework.ProxyFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestAdvice { public static void main(String[] args) { // 通过编码方式来织入增强 START UserService target = new UserService(); BeforeAdvice beforeAdvice = new OpenTransaction(); AfterReturningAdvice afterAdvice = new CommitTransaction(); // Spring提供的代理工厂 ProxyFactory pf = new ProxyFactory(); // 设定代理目标类 pf.setTarget(target); // 为代理目标类织入增强 pf.addAdvice(beforeAdvice); pf.addAdvice(afterAdvice); // 生成代理实例 target = (UserService) pf.getProxy(); target.updUser(); // 通过编码方式来织入增强 END System.out.println(""); // 通过XML配置方式来织入增强 START ApplicationContext app = new ClassPathXmlApplicationContext( "spring3/aop/aop1/aop.xml"); UserService userService = (UserService) app.getBean("userService"); userService.updUser(); // 通过XML配置方式来织入增强 START } }
测试结果:
Open Transaction UserService updUser! Close Transaction 4 12, 2013 1:45:44 午後 org.springframework.context.support.AbstractApplicationContext prepareRefresh 情報: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@15ede11: startup date [Fri Apr 12 13:45:44 CST 2013]; root of context hierarchy 4 12, 2013 1:45:44 午後 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 情報: Loading XML bean definitions from class path resource [spring3/aop/aop1/aop.xml] 4 12, 2013 1:45:45 午後 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 情報: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1a3eaa8: defining beans [beforeAdvice,afterAdvice,target,userService,aroundInterceptor,userService1]; root of factory hierarchy Open Transaction UserService updUser! Close Transaction
上面测试类程序中使用了org.springframework.aop.framework.ProxyFactory,它利用cglib或者jdk技术来创建代理,如果利用ProxyFactory.setInterfaces(arg0)方法来对特定接口来实现代理的话,ProxyFactory会选择利用jdk技术生成代理;如果没有指定针对接口代理或者指定ProxyFactory.setOptimize(true)(启用优化)时,ProxyFactory会选择利用cglib技术生成代理。
注意,如果ProxyFactory.setOptimize(true)设定true时,即使指定对接口进行代理,也会利用cglib技术来生成代理。
环绕增强 AroundInterceptor:
package spring3.aop.aop1; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class AroundInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("Open Transaction"); Object obj = invocation.proceed(); System.out.println("Close Transaction"); return obj; } }
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="target" class="spring3.aop.aop1.UserService"/> <bean id="aroundInterceptor" class="spring3.aop.aop1.AroundInterceptor"/> <bean id="userService1" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="aroundInterceptor" p:target-ref="target"/> </beans>
测试类
package spring3.aop.aop1; import org.springframework.aop.framework.ProxyFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestAdvice { public static void main(String[] args) { UserService target = new UserService(); AroundInterceptor inteceptor = new AroundInterceptor(); ProxyFactory pf = new ProxyFactory(); pf.addAdvice(inteceptor); pf.setTarget(target); target = (UserService) pf.getProxy(); target.updUser(); System.out.println(""); ApplicationContext app = new ClassPathXmlApplicationContext( "spring3/aop/aop1/aop.xml"); UserService userService1 = (UserService) app.getBean("userService1"); userService1.updUser(); } }
测试结果:
Open Transaction UserService updUser! Close Transaction 4 12, 2013 1:57:55 午後 org.springframework.context.support.AbstractApplicationContext prepareRefresh 情報: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1565e9d: startup date [Fri Apr 12 13:57:55 CST 2013]; root of context hierarchy 4 12, 2013 1:57:55 午後 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 情報: Loading XML bean definitions from class path resource [spring3/aop/aop1/aop.xml] 4 12, 2013 1:57:55 午後 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 情報: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@196de7e: defining beans [target,aroundInterceptor,userService1]; root of factory hierarchy Open Transaction UserService updUser! Close Transaction