这个实例用于一个系统的所以方法执行过程中出现异常时,把异常信息都记录下来,还有记录每个方法的执行时间,这两个业务逻辑首先使用SpringAOP的自动代理功能,然后一个用Java的动态代理,一个用CGLIB代理
用Spring AOP的自动代理实现
(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");
运行结果同上
用Spring AOP的动态代理和CGLIB代理实现
主要修改配置文件,去掉前面的自动代理,使用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会自动把封装的横切关注点插入到具体的业务逻辑中