这个实例用于一个系统的所以方法执行过程中出现异常时,把异常信息都记录下来,还有记录每个方法的执行时间,这两个业务逻辑首先使用SpringAOP的自动代理功能,然后一个用Java的动态代理,一个用CGLIB代理
(1)定义负责异常处理的Advice为ExceptionHandler.java ,负责当程序执行过程中出现异常,把异常信息记录下来
public class ExceptionHandler implements ThrowsAdvice{ private Logger logger=Logger.getLogger(this.getClass().getName()); //重写afterThrowing()方法 public void afterThrowing(Method m,Object[] args,Object target, Throwable subclass) { logger.log(Level.INFO,args[0]+" 执行 "+m.getName()+" 时有异常抛出..."+subclass); } }(2)定义负责记录执行时间的Advice为TimeHandler.java 使用Spring提供的Around通知实现该功能
/* * 负责记录每个方法的执行时间 * 因为使用的是环绕通知,所以要实现接口MethodInterceptor */ public class TimeHandler implements MethodInterceptor { private Logger logger = Logger.getLogger(this.getClass().getName()); @Override public Object invoke(MethodInvocation invocation) throws Throwable { //获取初始时间 long procTime = System.currentTimeMillis(); logger.log(Level.INFO, invocation.getArguments()[0] + " 开始执行 " + invocation.getMethod() + " 方法"); try { Object result=invocation.proceed(); return result; } finally { // 计算执行时间 procTime=System.currentTimeMillis()-procTime; logger.log(Level.INFO, invocation.getArguments()[0] + " 执行 " + invocation.getMethod() + " 方法结束"); logger.log(Level.INFO, " 执行 "+invocation.getMethod().getName()+ " 方法共用了 "+procTime+" 毫秒"); } } }(3)定义业务逻辑接口LogicInterface.java
/* * 共定义3个方法,新增、修改和删除 */ public interface LogicInterface { public void doInsert(String name); public void doUpdate(String name); public void doDelete(String name); }(4)实现业务逻辑接口的类Logic1.java
public class Logic1 implements LogicInterface { @Override //负责新增 public void doInsert(String name) { System.out.println("执行具体负责新增的业务逻辑..."); for(int i=0;i<10000000;i++) { //模拟执行时间 } } @Override //负责修改 public void doUpdate(String name) { System.out.println("执行具体负责修改的业务逻辑..."); for(int i=0;i<20000000;i++) { //模拟执行时间 } } @Override //负责删除 public void doDelete(String name) { System.out.println("执行具体负责删除的业务逻辑..."); for(int i=0;i<20000000;i++) { //模拟异常发生 i=i/0; } } }不实现业务逻辑接口的类Logic2.java
public class Logic2 { //负责新增 public void doInsert(String name) { System.out.println("执行具体负责新增的业务逻辑..."); for(int i=0;i<10000000;i++) { //模拟执行时间 } } //负责修改 public void doUpdate(String name) { System.out.println("执行具体负责修改的业务逻辑..."); for(int i=0;i<20000000;i++) { //模拟执行时间 } } //负责删除 public void doDelete(String name) { System.out.println("执行具体负责删除的业务逻辑..."); for(int i=0;i<20000000;i++) { i=i/0; } } }(5)自动代理配置文档
<bean id="logic1" class="aop.action.Logic1"></bean> <bean id="logic2" class="aop.action.Logic2"></bean> <!-- 设定为自动代理 --> <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean> <!-- 负责记录有异常发生时的信息 --> <bean id="exceptionHandler" class="aop.action.ExceptionHandler"></bean> <bean id="exceptionHandlerAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref bean="exceptionHandler" /> </property> <!-- 对指定类的任何方法有效 --> <property name="patterns"> <value>.*.*</value> </property> </bean> <!-- 负责记录方法的记录时间 --> <bean id="timeHandler" class="aop.action.TimeHandler"></bean> <bean id="timeHandlerAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref bean="timeHandler" /> </property> <!-- 对指定类的任何方法有效 --> <property name="patterns"> <value>.*.*</value> </property> </bean>(6)测试Logic1
public class TestAop { public static void main(String[] args) { ApplicationContext context = new FileSystemXmlApplicationContext( "classpath:exception-config.xml"); LogicInterface logic = (LogicInterface) context.getBean("logic1"); // 模拟执行新增、修改、删除方法 try { logic.doInsert("张三"); logic.doUpdate("李四"); logic.doDelete("王五"); } catch (Exception e) { System.out.println(e); } } }运行结果 测试Logic2
Logic2 logic = (Logic2) context.getBean("logic2");运行结果同上
主要修改配置文件,去掉前面的自动代理,使用ProxyFactoryBean代理定义,Logic1只记录程序执行时间, Logic2只负责捕获异常
<bean id="logic1" class="aop.action.Logic1"></bean> <bean id="logic2" class="aop.action.Logic2"></bean> <!-- 设定为自动代理 --> <!-- <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean> --> <!-- 负责记录有异常发生时的信息 --> <bean id="exceptionHandler" class="aop.action.ExceptionHandler"></bean> <bean id="exceptionHandlerAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref bean="exceptionHandler" /> </property> <!-- 对指定类的任何方法有效 --> <property name="patterns"> <value>.*.*</value> </property> </bean> <!-- 负责记录方法的记录时间 --> <bean id="timeHandler" class="aop.action.TimeHandler"></bean> <bean id="timeHandlerAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref bean="timeHandler" /> </property> <!-- 对指定类的任何方法有效 --> <property name="patterns"> <value>.*.*</value> </property> </bean> <!-- 配置Logic1只负责记录执行时间 --> <bean id="logic1Proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 动态代理,实现接口 --> <property name="proxyInterfaces"> <value>aop.action.LogicInterface</value> </property> <property name="target"> <ref bean="logic1"/> </property> <!-- 指定代理类 --> <property name="interceptorNames"> <list> <value>timeHandlerAdvisor</value> </list> </property> </bean> <!-- 配置Logic只负责获取异常信息 --> <bean id="logic2Proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- CGLIB代理,不用实现接口 --> <property name="proxyTargetClass"> <value>true</value> </property> <property name="target"> <ref bean="logic2"/> </property> <!-- 指定代理类 --> <property name="interceptorNames"> <list> <value>exceptionHandlerAdvisor</value> </list> </property> </bean>Logic1的测试类,使用的是Java的动态代理
public class TestAop { public static void main(String[] args) { ApplicationContext context = new FileSystemXmlApplicationContext( "classpath:exception-config.xml"); LogicInterface logic = (LogicInterface) context.getBean("logic1Proxy"); // 模拟执行新增、修改、删除方法 try { logic.doInsert("张三"); logic.doUpdate("李四"); logic.doDelete("王五"); } catch (Exception e) { System.out.println(e); } } }运行结果只记录程序执行时间 Logic2的测试类,使用的是CGLIB的动态代理
public class TestAop { public static void main(String[] args) { ApplicationContext context = new FileSystemXmlApplicationContext( "classpath:exception-config.xml"); Logic2 logic = (Logic2) context.getBean("logic2Proxy"); // 模拟执行新增、修改、删除方法 try { logic.doInsert("张三"); logic.doUpdate("李四"); logic.doDelete("王五"); } catch (Exception e) { System.out.println(e); } } }运行结果只记录异常信息
AOP编程的实质就是,业务逻辑不再实现横切关注点,而是由单独的类来封装,当业务逻辑需要用到封装的横切关注点,AOP会自动把封装的横切关注点插入到具体的业务逻辑中
