0. 增强分类
org.aopalliance.aop.Advice:aop联盟给出的接口规范,
package org.aopalliance.aop;
/**
* Tag interface for Advice. Implementations can be any type
* of advice, such as Interceptors.
*/
public interface Advice {
}
1.前置增强
1.0: 继承树
1.1: org.springframework.aop.BeforeAdvice:前置增强
package org.springframework.aop;
import org.aopalliance.aop.Advice;
public interface BeforeAdvice extends Advice {
}
1.2: org.springframework.aop.MethodBeforeAdvice:前置增强
package org.springframework.aop;
import java.lang.reflect.Method;
import org.springframework.lang.Nullable;
/**
* Advice invoked before a method is invoked. Such advices cannot
* prevent the method call proceeding, unless they throw a Throwable.
*/
public interface MethodBeforeAdvice extends BeforeAdvice {
/**
* 在一个指定的方法调用之前调用
* @param method 待调用的方法
* @param args 待调用方法的参数
* @param target 待调用方法的目标对象.可能是null.
* @throws Throwable 异常
*/
void before(Method method, Object[] args, @Nullable Object target) throws Throwable;
}
1.3: org.springframework.aop.AspectJMethodBeforeAdvice :前置增强
该类的方法实现是在其父类:org.springframework.aop.aspectj.AbstractAspectJAdvice,后面再说
package org.springframework.aop.aspectj;
import java.io.Serializable;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.lang.Nullable;
/**
* Spring AOP advice that wraps an AspectJ before method.
*/
@SuppressWarnings("serial")
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {
public AspectJMethodBeforeAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
super(aspectJBeforeAdviceMethod, pointcut, aif);
}
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
@Override
public boolean isBeforeAdvice() {
return true;
}
@Override
public boolean isAfterAdvice() {
return false;
}
}
接口如下:
package com.ghq.cloud.aop;
public interface Waiter {
void greetingTo(String name);
void serveTo(String name);
}
实现如下:
package com.ghq.cloud.aop;
public class NaiveWaiter implements Waiter {
@Override
public void greetingTo(String name) {
System.out.println("greeting to :"+name);
}
@Override
public void serveTo(String name) {
System.out.println("serving to :"+name);
}
}
前置增强的实现:
package com.ghq.cloud.aop;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class GreetingBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
String clientName = (String) args[0];
System.out.println("How are you! Mr."+clientName);
}
}
测试类:
@Test
public void test01() {
Waiter target = new NaiveWaiter();
BeforeAdvice advice = new GreetingBeforeAdvice();
//1. spring 提供的代理工厂
ProxyFactory pf = new ProxyFactory();
//1.1 指定代理接口
//pf.setInterfaces(target.getClass().getInterfaces());
//1.2 设置优化
//pf.setOptimize(true);
//2. 设置代理目标
pf.setTarget(target);
//3. 为代理目标添加增强
pf.addAdvice(advice);
//4. 生成代理实例
Waiter proxy = (Waiter) pf.getProxy();
System.out.println(proxy.getClass());//NaiveWaiter$$EnhancerBySpringCGLIB$$fdce4fb4
proxy.greetingTo("john");
proxy.serveTo("Tom");
}
输出结果:这里使用的CGLib代理
class com.ghq.cloud.aop.NaiveWaiter$$EnhancerBySpringCGLIB$$45749675
How are you! Mr.john
greeting to :john
How are you! Mr.Tom
serving to :Tom
1.4: spring xml配置 使用 ProxyFactory
xml配置如下:
<bean id="target" class="com.ghq.cloud.aop.NaiveWaiter"/>
<bean id="greetingAdvice" class="com.ghq.cloud.aop.GreetingBeforeAdvice"/>
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="greetingAdvice"
p:interfaces="com.ghq.cloud.aop.Waiter"
p:target-ref="target"/>
main方法如下:
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("classpath:beans2.xml");
Waiter waiter = (Waiter) context.getBean("waiter");
System.out.println(waiter.getClass());
waiter.greetingTo("snow");
}
输出结果:
class com.sun.proxy.$Proxy4
How are you! Mr.snow
greeting to :snow
关于ProxyFactory我们下一篇文章再说
2.后置增强
2.0: 继承树
2.1: org.springframework.aop.BeforeAdvice:后置增强
后置增强在方法正常返回的情况下会被调用,如果方法抛出异常,那么后置增强不会调用。
后置增强可以拿到方法的返回值,但是不能改变这个返回值。
package org.springframework.aop;
import java.lang.reflect.Method;
import org.springframework.lang.Nullable;
public interface AfterReturningAdvice extends AfterAdvice {
void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}
2.2: org.springframework.aop.BeforeAdvice:后置增强
public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice
implements AfterReturningAdvice, AfterAdvice, Serializable {
public AspectJAfterReturningAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
super(aspectJBeforeAdviceMethod, pointcut, aif);
}
@Override
public boolean isBeforeAdvice() {
return false;
}
@Override
public boolean isAfterAdvice() {
return true;
}
@Override
public void setReturningName(String name) {
setReturningNameNoCheck(name);
}
@Override
public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable {
if (shouldInvokeOnReturnValueOf(method, returnValue)) {
invokeAdviceMethod(getJoinPointMatch(), returnValue, null);
}
}
/**
* Following AspectJ semantics, if a returning clause was specified, then the
* advice is only invoked if the returned value is an instance of the given
* returning type and generic type parameters, if any, match the assignment
* rules. If the returning type is Object, the advice is *always* invoked.
* @param returnValue the return value of the target method
* @return whether to invoke the advice method for the given return value
*/
private boolean shouldInvokeOnReturnValueOf(Method method, @Nullable Object returnValue) {
Class<?> type = getDiscoveredReturningType();
Type genericType = getDiscoveredReturningGenericType();
// If we aren't dealing with a raw type, check if generic parameters are assignable.
return (matchesReturnValue(type, method, returnValue) &&
(genericType == null || genericType == type ||
TypeUtils.isAssignable(genericType, method.getGenericReturnType())));
}
/**
* Following AspectJ semantics, if a return value is null (or return type is void),
* then the return type of target method should be used to determine whether advice
* is invoked or not. Also, even if the return type is void, if the type of argument
* declared in the advice method is Object, then the advice must still get invoked.
* @param type the type of argument declared in advice method
* @param method the advice method
* @param returnValue the return value of the target method
* @return whether to invoke the advice method for the given return value and type
*/
private boolean matchesReturnValue(Class<?> type, Method method, @Nullable Object returnValue) {
if (returnValue != null) {
return ClassUtils.isAssignableValue(type, returnValue);
}
else if (Object.class == type && void.class == method.getReturnType()) {
return true;
}
else {
return ClassUtils.isAssignable(type, method.getReturnType());
}
}
}
后置增强的实现:
public class GreetingAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("please enjoy yourself");
}
}
xml配置:
<bean id="target" class="com.ghq.cloud.aop.NaiveWaiter"/>
<bean id="greetingBeforeAdvice" class="com.ghq.cloud.aop.GreetingBeforeAdvice"/>
<bean id="greetingAfterAdvice" class="com.ghq.cloud.aop.GreetingAfterAdvice"/>
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="greetingBeforeAdvice,greetingAfterAdvice"
p:interfaces="com.ghq.cloud.aop.Waiter"
p:target-ref="target"/>
注意增加的内容:
这里需要注意的是:p:interceptorNames 是String[]类型的,它接收增强的Bean的名称而不是增强Bean的实例。这里因为ProxyBeanFactory内部在生成代理类时,需要使用增强Bean的类,而不是增强Bean的实例,以织入增强类中所写的横切逻辑代码,因而可以说增强时类级别的
<bean id="greetingAfterAdvice" class="com.ghq.cloud.aop.GreetingAfterAdvice"/>
p:interceptorNames="greetingBeforeAdvice,greetingAfterAdvice"
main方法不变:参考前文(#1)的的main方法
输出结果如下:
How are you! Mr.snow
greeting to :snow
please enjoy yourself
3.环绕增强
3.0: 继承树
3.1: org.aopalliance.intercept.MethodInterceptor:环绕增强
package org.aopalliance.intercept;
/**
* Intercepts calls on an interface on its way to the target. These
* are nested "on top" of the target.
*
* <p>The user should implement the {@link #invoke(MethodInvocation)}
* method to modify the original behavior. E.g. the following class
* implements a tracing interceptor (traces all the calls on the
* intercepted method(s)):
*
* <pre class=code>
* class TracingInterceptor implements MethodInterceptor {
* Object invoke(MethodInvocation i) throws Throwable {
* System.out.println("method "+i.getMethod()+" is called on "+
* i.getThis()+" with args "+i.getArguments());
* Object ret=i.proceed();
* System.out.println("method "+i.getMethod()+" returns "+ret);
* return ret;
* }
* }
* </pre>
*
* @author Rod Johnson
*/
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
/**
* Implement this method to perform extra treatments before and
* after the invocation. Polite implementations would certainly
* like to invoke {@link Joinpoint#proceed()}.
* @param invocation the method invocation joinpoint
* @return the result of the call to {@link Joinpoint#proceed()};
* might be intercepted by the interceptor
* @throws Throwable if the interceptors or the target object
* throws an exception
*/
Object invoke(MethodInvocation invocation) throws Throwable;
}
环绕增强的实现:
package com.ghq.cloud.aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class GreetingInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation i) throws Throwable {
System.out.println("method "+i.getMethod()+" is called on "+
i.getThis()+" with args "+i.getArguments());
Object o = i.proceed();
System.out.println("method "+i.getMethod()+" returns "+o);
return o;
}
}
xml配置:
<bean id="greetingInterceptor" class="com.ghq.cloud.aop.GreetingInterceptor"/>
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="greetingInterceptor"
p:interfaces="com.ghq.cloud.aop.Waiter"
p:target-ref="target"/>
main方法不变:参考前文(#1)的的main方法
输出结果如下:
method public abstract void com.ghq.cloud.aop.Waiter.greetingTo(java.lang.String) is called on com.ghq.cloud.aop.NaiveWaiter@453da22c with args [Ljava.lang.Object;@71248c21
greeting to :snow
method public abstract void com.ghq.cloud.aop.Waiter.greetingTo(java.lang.String) returns null
4.异常抛出增强(场景:事务处理)
案例:
Service
public class ForumService {
public void removeForum(int forumId){
throw new RuntimeException("运行异常...");
}
public void updateForum(int forumId){
throw new RuntimeException("数据更新异常...");
}
}
异常抛出增强实现
package com.ghq.cloud.aop;
import org.springframework.aop.ThrowsAdvice;
import java.lang.reflect.Method;
public class TransactionManager implements ThrowsAdvice {
public void afterThrowing(Method method, Object[] args, Object target, Exception ex){
System.out.println("------------------");
System.out.println("method:"+method.getName());
System.out.println("抛出异常:"+ex.getMessage());
System.out.println("成功回滚事务...");
}
}
xml配置
<bean id="transactionManager" class="com.ghq.cloud.aop.TransactionManager"/>
<bean id="forumServiceTarget" class="com.ghq.cloud.aop.ForumService"/>
<bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="transactionManager"
p:proxyTargetClass="true"
p:target-ref="forumServiceTarget"/>
5.引介增强(场景:性能监控)
定义一个是否支持监控的接口:
package com.ghq.cloud.aop;
public interface Monitorable {
void setMonitorActive(boolean active);
}
通过继承DelegatingIntroductionInterceptor为目标类引入性能监视的可控功能。
public class ControllablePerformanceMonitor extends DelegatingIntroductionInterceptor implements Monitorable {
private ThreadLocal<Boolean> map = new ThreadLocal<>();
@Override
public void setMonitorActive(boolean active) {
map.set(active);
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
if(map.get()!=null && map.get()){
System.out.println("开始 性能检测");
Object o = super.invoke(mi);
System.out.println("结束性能检测");
return o;
}else {
return super.invoke(mi);
}
}
}
xml配置如下:
<bean id="monitor" class="com.ghq.cloud.aop.ControllablePerformanceMonitor"/>
<bean id="forumServiceTarget" class="com.ghq.cloud.aop.ForumService"/>
<bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interfaces="com.ghq.cloud.aop.Monitorable"
p:target-ref="forumServiceTarget"
p:interceptorNames="monitor"
p:proxyTargetClass="true"/>
service
public class ForumService {
public void removeForum(int forumId){
//throw new RuntimeException("运行异常...");
System.out.println("根据id移除对象");
}
public void updateForum(int forumId){
throw new RuntimeException("数据更新异常...");
}
}
main方法:
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("classpath:beans2.xml");
ForumService forumService = (ForumService) context.getBean("forumService");
forumService.removeForum(1);
System.out.println("---------------------");
Monitorable monitorable = (Monitorable) forumService;
monitorable.setMonitorActive(true);
forumService.removeForum(1);
}
输出结果:
根据id移除对象
---------------------
开始 性能检测
根据id移除对象
结束性能检测