SpringAOP创建增强类
1)前置增强:org.springframework.aop.BeforeAdvice 代表前置增强,因为Spring 只支持方法级的增强,所有MethodBeforeAdvice是目前可用的前置增强,表示在目标方法执行前实施增强,而BeforeAdvice是为了将来版本扩展需要而定义的;
2)后置增强:org.springframework.aop.AfterReturningAdvice 代表后增强,表示在目标方法执行后实施增强;
3)环绕增强:org.aopalliance.intercept.MethodInterceptor 代表环绕增强,表示在目标方法执行前后实施增强;
4)异常抛出增强:org.springframework.aop.ThrowsAdvice 代表抛出异常增强,表示在目标方法抛出异常后实施增强;
5)引介增强:org.springframework.aop.IntroductionInterceptor 代表引介增强,表示在目标类中添加一些新的方法和属性。
1、前置增强
模拟服务员向顾客表示欢迎和对顾客提供服务。
Waiter接口:
package com.yyq.advice;publicinterface Waiter {void greetTo(String name);void serveTo(String name);}
NaiveWaiter服务类:
package com.yyq.advice;publicclass NaiveWaiter implements Waiter {@Override
publicvoid greetTo(String name) {System.out.println(
"greet to " + name + "...");}
@Override
publicvoid serveTo(String name) {System.out.println(
"serving to " + name + "...");}
}
前置增强实现类:
package com.yyq.advice;import org.springframework.aop.MethodBeforeAdvice;import java.lang.reflect.Method;publicclass GreetingBeforeAdvice implements MethodBeforeAdvice {@Override
publicvoid before(Method method, Object[] objects, Object o) throws Throwable {String clientName
= (String) objects[0];System.out.println(
"How are you ! Mr." + clientName + ".");}
}
测试方法:
@Testpublicvoid testBeforeAdvice(){Waiter target
= new NaiveWaiter();BeforeAdvice advice
= new GreetingBeforeAdvice();ProxyFactory pf
= new ProxyFactory(); //Spring提供的代理工厂pf.setTarget(target); //设置代理目标
pf.addAdvice(advice);
Waiter proxy = (Waiter)pf.getProxy(); //生成代理实例
proxy.greetTo("John");
proxy.serveTo("Tom");
}
输出结果:
How are you ! Mr.John.
greet to John...
How are you ! Mr.Tom.
serving to Tom...
在Spring中配置:beans.xml
<bean id="greetingAdvice" class="com.yyq.advice.GreetingBeforeAdvice"/><bean id="target" class="com.yyq.advice.NaiveWaiter"/>
<bean id="waiter1" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.yyq.advice.Waiter"
p:interceptorNames="greetingAdvice"
p:target-ref="target"/>
ProxyFactoryBean 是FactoryBean接口的实现类。
· target:代理的目标对象;
· proxyInterfaces:代理所实现的接口,可以是多个接口。该属性还有一个别名属性interfaces;
· interceptorNames:需要织入目标对象的Bean列表,采用Bean的名称指定。这些Bean必须是实现了org.aopalliance.intercept.Method 或 org.springframework.aop.Advisor的Bean,配置中的顺序对应调用的顺序;
· singleton:返回的代理是否是单实例,默认为单实例;
· optimize:当设置为true时,强制使用CGLib代理。对于singleton的代理,我们推荐使用CGLib,对于其他作用域类型的代理,最好使用JDK代理。原因是CGLib创建代理时速度慢,而创建出的代理对象运行效率较高,而使用JDK代理的表现正好相反;
· proxyTargetClass:是否对类进行代理(而不是对接口进行代理),设置为true时,使用CGLib代理。
测试方法:
@Testpublicvoid testBeforeAdvice2(){String configPath
= "com\yyq\advice\beans.xml";ApplicationContext ctx
= new ClassPathXmlApplicationContext(configPath);Waiter waiter
= (Waiter)ctx.getBean("waiter1");waiter.greetTo(
"Joe");}
输出结果:
How are you ! Mr.Joe.
greet to Joe...
2、后置增强
后置增强在目标类方法调用后执行。模拟服务员在每次服务后使用礼貌用语。
GreetingAfterAdvice后置增强实现类:
package com.yyq.advice;import org.springframework.aop.AfterReturningAdvice;import java.lang.reflect.Method;publicclass GreetingAfterAdvice implements AfterReturningAdvice {@Override
publicvoid afterReturning(Object o, Method method, Object[] objects, Object o2) throws Throwable {System.out.println(
"Please enjoy yourself.");}
}
在beans.xml文件添加后置增强:
<bean id="greetingBefore" class="com.yyq.advice.GreetingBeforeAdvice"/><bean id="greetingAfter" class="com.yyq.advice.GreetingAfterAdvice"/>
<bean id="waiter2" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.yyq.advice.Waiter"
p:interceptorNames="greetingBefore,greetingAfter"
p:target-ref="target"/>
测试方法:
@Testpublicvoid testBeforeAndAfterAdvice(){String configPath
= "com\yyq\advice\beans.xml";ApplicationContext ctx
= new ClassPathXmlApplicationContext(configPath);Waiter waiter
= (Waiter)ctx.getBean("waiter2");waiter.greetTo(
"Joe");}
结果输出:
How are you ! Mr.Joe.
greet to Joe...
Please enjoy yourself.
3、环绕增强
环绕增强允许在目标类方法调用前后织入横切逻辑,它综合实现了前置、后置增强两者的功能。
GreetingInterceptor环绕增强实现类:
package com.yyq.advice;import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;publicclass GreetingInterceptor implements MethodInterceptor {@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {Object[] args
= methodInvocation.getArguments();String clientName
= (String) args[0];System.out.println(
"Hi,Mr " + clientName + ".");Object obj
= methodInvocation.proceed();System.out.println(
"Please enjoy yourself~");return obj;}
}
Spring 直接使用AOP联盟所定义的MethodInterceptor作为环绕增强的接口。该接口拥有唯一的接口方法 Object invoke(MethodInvocation invocation), MethodInvocation不但封装目标方法及其入参数组,还封装了目标方法所在的实例对象,通过MethodInvocation的getArguments()可以获取目标方法的入参数组,通过proceed()反射调用目标实例相应的方法。
在beans.xml文件添加环绕增强:
<bean id="greetingAround" class="com.yyq.advice.GreetingInterceptor"/><bean id="waiter3" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.yyq.advice.Waiter"
p:interceptorNames="greetingAround"
p:target-ref="target"/>
测试方法:
@Testpublicvoid testAroundAdvice(){String configPath
= "com\yyq\advice\beans.xml";ApplicationContext ctx
= new ClassPathXmlApplicationContext(configPath);Waiter waiter
= (Waiter)ctx.getBean("waiter3");waiter.greetTo(
"Joe");}
结果输出:
Hi,Mr Joe.
greet to Joe...
Please enjoy yourself~
4、异常抛出增强
异常抛出增强最适合的应用场景是事务管理,当参与事务的某个Dao发送异常时,事务管理器就必须回滚事务。
Forum业务类:
package com.yyq.advice;publicclass Forum {privateint forumId;publicint getForumId() {return forumId;}
publicvoid setForumId(int forumId) {this.forumId = forumId;}
}
ForumService业务类:
package com.yyq.advice;import java.sql.SQLException;publicclass ForumService {publicvoid removeForum(int forumId){System.out.println(
"removeForum....");thrownew RuntimeException("运行异常");}
publicvoid updateForum(Forum forum)throws Exception{System.out.println(
"updateForum");thrownew SQLException("数据更新操作异常。");}
}
TransactionManager异常抛出增强实现类:
package com.yyq.advice;import org.springframework.aop.ThrowsAdvice;import java.lang.reflect.Method;publicclass TransactionManager implements ThrowsAdvice {publicvoid afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable {System.out.println(
"----------------");System.out.println(
"method:" + method.getName());System.out.println(
"抛出异常:" + ex.getMessage());System.out.println(
"成功回滚事务。");}
}
ThrowAdvice异常抛出增强接口没有定义任何方法,它是一个标识接口,在运行期Spring使用反射的机制自行判断,我们采用以下签名形式定义异常抛出的增强方法:void afterThrowing(Mehod method, Object[] args, Object target, Throwable);方法名必须为afterThrowing,方法入参规定,前三个参数是可选的,要么三个入参提供,要么不提供,最后一个入参是Throwable或者子类。
在beans.xml文件添加异常抛出增强:
<bean id="transactionManager" class="com.yyq.advice.TransactionManager"/><bean id="forumServiceTarget" class="com.yyq.advice.ForumService"/>
<bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="transactionManager"
p:target-ref="forumServiceTarget"
p:proxyTargetClass="true"/>
测试方法:
@Testpublicvoid testThrowsAdvice(){String configPath
= "com\yyq\advice\beans.xml";ApplicationContext ctx
= new ClassPathXmlApplicationContext(configPath);ForumService fs
= (ForumService)ctx.getBean("forumService");try{fs.removeForum(
10);}
catch (Exception e) {}try{fs.updateForum(
new Forum());}
catch (Exception e) {}}
结果输出:
----------------
method:removeForum
抛出异常:运行异常
成功回滚事务。
updateForum
----------------
method:updateForum
抛出异常:数据更新操作异常。
成功回滚事务。
5、引介增强
引介增强为目标类创建新的方法和属性,所以引介增强的连接点是类级别的,而非方法级别的。通过引介增强,我们可以为目标类添加一个接口的实现,即原来目标类未实现某个接口,通过引介增强可以为目标类创建实现某个接口的代理。Spring定义了引介增强接口IntroductionInterceptor,该接口没有定义任何的方法,Spring为该接口提供了DelegatingIntroductionInterceptor实现类。
Monitorable:用于标识目标类是否支持性能监视的接口
package com.yyq.advice;publicinterface Monitorable {void setMonitorActive(boolean active);}
ControllablePerformanceMonitor 为引介增强实现类:
package com.yyq.advice;import org.aopalliance.intercept.MethodInvocation;import org.springframework.aop.support.DelegatingIntroductionInterceptor;publicclass ControllablePerformanceMonitor extends DelegatingIntroductionInterceptor implements Monitorable {private ThreadLocal<Boolean> MonitorStatusMap = new ThreadLocal<Boolean>();@Override
publicvoid setMonitorActive(boolean active) {MonitorStatusMap.set(active);
}
public Object invoke(MethodInvocation mi) throws Throwable {Object obj
= null;if (MonitorStatusMap.get() != null && MonitorStatusMap.get()) {PerformanceMonitor.begin(mi.getClass().getName()
+ "." + mi.getMethod().getName());obj
= super.invoke(mi);PerformanceMonitor.end();
}
else {obj
= super.invoke(mi);}
return obj;}
}
PerformanceMonitor监视类:
package com.yyq.advice;publicclass PerformanceMonitor {privatestatic ThreadLocal<MethodPerformance> performanceRecord = new ThreadLocal<MethodPerformance>();publicstaticvoid begin(String method) {System.out.println(
"begin monitor...");MethodPerformance mp
= new MethodPerformance(method);performanceRecord.set(mp);
}
publicstaticvoid end(){System.out.println(
"end monitor...");MethodPerformance mp
= performanceRecord.get();mp.printPerformance();
}
}
MethodPerformance记录性能信息:
publicclass MethodPerformance {privatelong begin;privatelong end;private String serviceMethod;public MethodPerformance(String serviceMethod){this.serviceMethod = serviceMethod;this.begin = System.currentTimeMillis();}
publicvoid printPerformance(){end
= System.currentTimeMillis();long elapse = end - begin;System.out.println(serviceMethod
+ "花费" + elapse + "毫秒。");}
}
在beans.xml文件添加引介增强:
<bean id="pmonitor" class="com.yyq.advice.ControllablePerformanceMonitor"/><bean id="forumServiceImplTarget" class="com.yyq.advice.ForumServiceImpl"/>
<bean id="forumService2" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interfaces="com.yyq.advice.Monitorable"
p:interceptorNames="pmonitor"
p:target-ref="forumServiceImplTarget"
p:proxyTargetClass="true"/>
测试方法:
@Testpublicvoid testIntroduce(){String configPath
= "com\yyq\advice\beans.xml";ApplicationContext ctx
= new ClassPathXmlApplicationContext(configPath);ForumServiceImpl forumServiceImpl
= (ForumServiceImpl)ctx.getBean("forumService2");forumServiceImpl.removeForum(
23);forumServiceImpl.removeTopic(
1023);Monitorable monitorable
= (Monitorable)forumServiceImpl;monitorable.setMonitorActive(
true);forumServiceImpl.removeForum(
22);forumServiceImpl.removeTopic(
1023);}
结果输出:
模拟删除Forum记录:23
模拟删除Topic记录:1023
begin monitor...
模拟删除Forum记录:22
end monitor...
org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.removeForum花费40毫秒。
begin monitor...
模拟删除Topic记录:1023
end monitor...
org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.removeTopic花费21毫秒。
以上是 SpringAOP创建增强类 的全部内容, 来源链接: utcz.com/z/513022.html