在上篇文章详细介绍了AOP的思想以及相关的术语 《Spring AOP原理》并写了一个前置增强的示例代码,本篇文章继续把其他类型的增强实现码出来,希望对家有所帮助。
后置增强:
1.目标类:
public class Waiter {
public void greetTo(String name) {
System.out.println("waiter greet to " + name + "...");
}
public void serveTo(String name) {
System.out.println("waiter serving " + name + "...");
}
}
2.后置增强:实现 org.springframework.aop.AfterReturningAdvice
public class GreetAterAdvice implements AfterReturningAdvice {
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("Please enjoy yourself!");
}
}
3.测试:
public class AfterAdviceTest {
private Waiter target;
private AfterAdvice advice;
private ProxyFactory pf;
@BeforeTest
public void init() {
target = new Waiter();
advice = new GreetAterAdvice();
//①Spring提供的代理工厂
pf = new ProxyFactory();
// ②设置代理目标
pf.setTarget(target);
//③为代理目标添加增强
pf.addAdvice(advice);
}
@Test
public void beforeAdvice() {
Waiter proxy = (Waiter) pf.getProxy();
proxy.greetTo("John");
proxy.serveTo("Tom");
}
}
打印结果:
waiter greet to John...
Please enjoy yourself! //该行是后置增强植入的逻辑
waiter serving Tom...
Please enjoy yourself! //该行是后置增强植入的逻辑
这样就在方法执行之后,织入了增强逻辑。如果想同时织入前置增强和后置增强,可以同时添加多个增强,如下,(或者一个增强类同时实现多个增强接口)
//③为代理目标添加增强
pf.addAdvice(advice);
pf.addAdvice(beforeAdvice);
当然也可以采用Spring提供的环绕增强,也可以达到相同的目的。
环绕增强:
环绕增强需要实现:rg.aopalliance.intercept.MethodInterceptor
实现方法和前面提到的后置增强有所不同:
public class GreetInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
Object[] args = invocation.getArguments();
String clientName = (String) args[0];
//在目标方法执行前调用
System.out.println("How are you!Mr." + clientName + ".");
//通过反射调用目标方法
Object obj = invocation.proceed();
//在目标方法执行后调用
System.out.println("Please enjoy yourself!");
return obj;
}
}
最终效果和上面同时引入前置增强和后置增强的效果一致。
异常抛出增强:
该增强最适合的场景是事务管理,当参与事务的Dao发生异常,事务管理器就必须回滚事务。
1.目标类:
在模拟业务类ViewSpaceService中定义了两个业务方法,deleteViewSpace ()抛出运行期异常,而updateViewSpace ()抛出SQLException。
public class ViewSpaceService {
public boolean deleteViewSpace(int spaceId) {
throw new RuntimeException("运行异常。");
}
public void updateViewSpace(ViewSpace viewSpace) throws Exception {
// do sth...
throw new SQLException("数据更新操作异常。");
}
}
2.抛出异常增强:
public class TransactionManager implements ThrowsAdvice {
public void afterThrowing(Method method, Object[] args, Object target,
Exception ex) throws Throwable {
ex = null;
System.out.println("-----------");
System.out.println("method:" + method.getName());
//System.out.println("抛出异常:" + ex.getMessage());
System.out.println("成功回滚事务。");
}
ThrowsAdvice异常抛出增强接口没有定义任何方法,它是一个标识接口,在运行期Spring使用反射的机制自行判断,必须采用以下签名形式定义异常抛出的增强方法。
void afterThrowing([Method method, Object[] args, Object target], Throwable);
方法名必须为afterThrowing,方法入参规定如下:前3个入参Method method, Object[] args, Object target是可选的(要么提供3个入参,要么不提供),而最后一个入参是Throwable或其子类。
下面几种都是合法的:
· afterThrowing(SQLException e);
· afterThrowing(RuntimeException e);
· afterThrowing(Method method, Object[] args, Object target,RuntimeException e)
可以在同一个异常抛出增强中定义多个afterThrowing(),当目标类方法,抛出异常时,Spring会自动选用最匹配的增强方法。
引介增强:
引介增强,不太常用,这里暂不讨论。
基于XML配置的增强实现:
前面我们在织入 增强时,通过代码进行装配 :
advice = new GreetInterceptor();
//①Spring提供的代理工厂
pf = new ProxyFactory();
// ②设置代理目标
pf.setTarget(target);
//③为代理目标添加增强
pf.addAdvice(advice);
开发中很多时候是基于配置文件进行组织(当然,到SpringBoot就另当别论,当原理都是一样)
下面我们用xml配置实现抛出异常增强的配置:
1.增强类编写(和前面一致)
TransactionManager
2.xml配置:
将目标对象和增强类,通过bean标签配置。
<?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.1.xsd">
<!--
<bean id="greetingBefore" class="com.smart.advice.GreetingBeforeAdvice" />
<bean id="greetingAfter" class="com.smart.advice.GreetingAfterAdvice" />
<bean id="greetingAdvice" class="com.smart.advice.GreetingBeforeAdvice" />
<bean id="greetingAround" class="com.smart.advice.GreetingInterceptor" />
<bean id="target" class="com.smart.advice.NaiveWaiter" />
-->
<!--4. 异常抛出增强 -->
<bean id="viewSpaceServiceTarget" class="com.smart.advice.ViewSpaceService" />
<bean id="transactionManager" class="com.smart.advice.TransactionManager" />
<bean id="viewSpaceService" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="transactionManager"
p:target-ref="viewSpaceServiceTarget"
p:proxyTargetClass="true"/>
</beans>
说明:p:interceptorNames 指明要织入的增强类id,关联上面的配置。
p:target-ref指明目标对象
p:proxyTargetClass指明要使用CGLib代理。因为ViewSpace是一个类。(如果不指定,也会默认使用)
总结:
我们介绍了几种增强的简单示例,但是我们注意到一个问题,增强,被织入到了类中的所有方法。如果我们希望有选择的织入目标类的某些特定方法,就需要使用切点进行目标连接点的定位。这就涉及到切点和切面相关的内容。最近更新,码字不易,路过点个赞。