目录
代理模式
静态代理
动态代理
Advice 与 MethodInterceptor
走进ProxyFactory
?总结
代理模式
? ? ? ? 简单来讲,代理模式就是在一个对象的基础上,提供另外一个代理对象,这个代理对象拥有原有对象的引用,拥有原有对象的任何功能,除此之外,还能添加一些功能上去,也就是所说的增强。
? ? ? ? 举例来说,这其实就像我们生活中的房屋中介,房东相当于原有对象,中介就是代理对象,中介止有房东的出售出租房屋的权利,他还能额外收取你一些中介费,保洁费什么的,这是原有对象房东所不具备的能力。所以说代理对象又可以说是增强的对象。
? ? ? ? 在代码世界里,代理模式有什么用呢?举例来说,比如现在有个订单服务,它提供了查询商品的功能,那么产品经理想添加一个功能,比如,查询完某个商品之后,想要保存一条查询记录,目的是为了监测那个商品被查询的次数最多,此时应该怎么做呢?你可以在原有的查询方法后面加一些保存纪录的代码,可是这样侵入性太强了,你这明明是查询的接口,里面又是查询又是保存,以至于到最后你都说不好它到底是什么接口了。这个时候如果用代理模式就能很好的解决问题了,原有的查询逻辑保持不变,且又能拥有保存搜索记录的功能。
静态代理
? ? ? ? 静态代理其实就是自己定义代理类,它与代理对象实现同一个接口,然后再引入代理对象的引用,这样就可以对被代理的对象进行增强了。如下
//订单接口
public interface IOrder {
//查询功能的接口
Integer query(String type);
}
//订单服务实现类
public class OrderService implements IOrder {
@Override
public Integer query(String type) {
System.out.println("查询类型为" + type + "订单数量");
return 1;
}
}
//代理类
public class OrderServiceProxy implements IOrder {
//被代理对象
private OrderService orderService = new OrderService();
@Override
public Integer query(String type) {
System.out.println("======通过认证======");
Integer retVal = orderService.query(type);
System.out.println("=====保存一条搜索纪录====");
return retVal;
}
}
//测试类
public class ProxyMain {
public static void main(String[] args) {
OrderServiceProxy orderServiceProxy = new OrderServiceProxy();
orderServiceProxy.query("鸿星尔克");
}
}
//执行结果
======通过认证======
查询类型为鸿星尔克订单数量
=====保存一条搜索纪录====
? ? ? ? 从上面的代码可以看出来,代理对象拥有被代理对象的功能,且对其进行了增强。我们得到了想要的结果,也没有修改之前查询方法的代码。
动态代理
? ? ? ? 可是又有同学会觉得,你这也太麻烦了吧,还不如自己在原有方法里面加一点逻辑呢,最起码不用这么麻烦,动态代理就是为了解决静态代理的繁琐的。动态代理不用声明代理类,可以通过反射创建出来一个代理对象。
? ? ? ? 通过反射获取代理对象,可以使用 Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h), 首先前两个参数直接从类信息就可以获取到了,第三个参数是什么呢?我们可以自定义一个InvocationHandler
public class MyInvocationHandler implements InvocationHandler {
//被代理对象
private Object object;
public MyInvocationHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("====认证通过=====");
Object retVal = method.invoke(object, args);
System.out.println("保存了一条类型为:" + args[0] + " 的纪录");
return retVal;
}
}
? ? ? ? 实现 InvocationHandler 必须重写 invoke 方法, 然后可以通过反射反射执行对象的具体方法,而在方法前后便可以进行增强操作。
public class ProxyMain {
public static void main(String[] args) {
/*OrderServiceProxy orderServiceProxy = new OrderServiceProxy();
orderServiceProxy.query("鸿星尔克");*/
//实例化被代理对象
OrderService orderService = new OrderService();
//获取代理对象
IOrder iOrder = (IOrder) Proxy.newProxyInstance(orderService.getClass().getClassLoader(),
orderService.getClass().getInterfaces(), new MyInvocationHandler(orderService));
//执行代理对象的查询方法
iOrder.query("鸿星尔克");
}
}
//执行结果:
====认证通过=====
查询类型为鸿星尔克订单数量
保存了一条类型为:鸿星尔克 的纪录
? ? ? ? 可以看到,动态代理相比于静态代理要简单一些。于此同时,大家有没有发现这个 InvocationHandler 跟拦截器有点像,好像也是拦截到某个方法,然后对其进行一些操作。
Advice 与 MethodInterceptor
? ? ? ? 首先看一下类继承图
? ? ? ? ?从图上看出,这俩其实差不多是一回事,MethodInterceptor 实现了 Advice, 但是 Advice 其实啥也没干,一个方法和属性都没有,可以理解为 Advice 就是定义了一个规范,它用来拦截方法的,但是具体怎么拦截,交给他的孩子去处理。MethodInterceptor 自定义了一个 invoke() 来拦截我们想要拦截的方法,可以在被拦截方法前后进行增强。而 Advice 还有其他的孩子,比如 AfterReturningAdvice 接口,它可以在方法执行完返回之后再进行拦截。而 MethodBeforeAdvice 可以在被拦截方法之前被拦截,颗粒度更细一些。
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
if (method.getName().equals("query")) {
System.out.println("通过advice拦截查询方法");
}
}
}
public class MyAfterReturningAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
if (method.getName().equals("query")) {
System.out.println("=====保存一条搜索纪录=====");
}
}
}
public class AuthorityInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
String methodName = invocation.getMethod().getName();
if (methodName.equals("query")) {
System.out.println("认证通过====");
//继续执行被拦截的方法
Object retVal = invocation.proceed();
System.out.println("通过 MethodInterceptor 拦截结束");
return retVal;
}
return invocation.proceed();
}
}
public class ProxyMain {
public static void main(String[] args) {
/*OrderServiceProxy orderServiceProxy = new OrderServiceProxy();
orderServiceProxy.query("鸿星尔克");*/
/*OrderService orderService = new OrderService();
IOrder iOrder = (IOrder) Proxy.newProxyInstance(orderService.getClass().getClassLoader(),
orderService.getClass().getInterfaces(), new MyInvocationHandler(orderService));
iOrder.query("鸿星尔克");
iOrder.buy("鸿星尔克");*/
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.addAdvice(new AuthorityInterceptor());
proxyFactory.addAdvice(new MyAfterReturningAdvice());
proxyFactory.addAdvice(new MyMethodBeforeAdvice());
proxyFactory.setTarget(new OrderService());
proxyFactory.setInterfaces(OrderService.class.getInterfaces());
IOrder proxy = (IOrder) proxyFactory.getProxy();
proxy.query("鸿星尔克");
}
}
//执行结果
认证通过====
通过advice拦截查询方法
查询类型为鸿星尔克订单数量
=====保存一条搜索纪录=====
通过 MethodInterceptor 拦截结束
? ? ? ? 通过上面的代码样例,相信大家对代理模式也有了些认识,基本的使用也知道怎么操作了。因为 Spring AOP 就是基于工厂模式生产代理对象的,所以这里跟进一下源码,了解一下工厂模式生成代理,以及怎么进行方法拦截的。 ?
走进ProxyFactory
? ? ? ?先看一下类继承图
????????
? ? ? ? 其中 ProxyConfig 是配置相关的,在创建代理的时候可能会用到一些配置信息,而 Advised 则是拦截方法相关的。Advised 接口包含 Advisor[] getAdvisors() 这个属性,那么 Advisor 又是什么呢?它保存了 Advice 的信息,由此可以得出结论,Advised 包含 Advisor, Advisor 包含 Advice
public interface Advisor {
/**
* Common placeholder for an empty {@code Advice} to be returned from
* {@link #getAdvice()} if no proper advice has been configured (yet).
* @since 5.0
*/
Advice EMPTY_ADVICE = new Advice() {};
/**
* Return the advice part of this aspect. An advice may be an
* interceptor, a before advice, a throws advice, etc.
* @return the advice that should apply if the pointcut matches
* @see org.aopalliance.intercept.MethodInterceptor
* @see BeforeAdvice
* @see ThrowsAdvice
* @see AfterReturningAdvice
*/
Advice getAdvice();
/**
* Return whether this advice is associated with a particular instance
* (for example, creating a mixin) or shared with all instances of
* the advised class obtained from the same Spring bean factory.
* <p><b>Note that this method is not currently used by the framework.</b>
* Typical Advisor implementations always return {@code true}.
* Use singleton/prototype bean definitions or appropriate programmatic
* proxy creation to ensure that Advisors have the correct lifecycle model.
* @return whether this advice is associated with a particular target instance
*/
boolean isPerInstance();
}
? ? ? ? ?我们跟进一下 proxyFactory.addAdvice()方法,从上面的分析其实我们可以得出如下结论,proxyFactory 就是 Advised, 而调用他的addAdvice方法,无非就是把 advice实例加入他的的Advisor这个属性数组里进行保存。可以跟进代码验证一下。
?????????
public void addAdvice(Advice advice) throws AopConfigException {
int pos = this.advisors.size();
addAdvice(pos, advice);
}
//可以看到,到这个方法的代码逻辑里就已经变成 addAdvisor 了,且调用addAdvisor 之前会先把 Advice放入一个实例化好的 Advisor 里
public void addAdvice(int pos, Advice advice) throws AopConfigException {
Assert.notNull(advice, "Advice must not be null");
if (advice instanceof IntroductionInfo) {
// We don't need an IntroductionAdvisor for this kind of introduction:
// It's fully self-describing.
addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));
}
else if (advice instanceof DynamicIntroductionAdvice) {
// We need an IntroductionAdvisor for this kind of introduction.
throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
}
else {
addAdvisor(pos, new DefaultPointcutAdvisor(advice));
}
}
public void addAdvisor(int pos, Advisor advisor) throws AopConfigException {
if (advisor instanceof IntroductionAdvisor) {
validateIntroductionAdvisor((IntroductionAdvisor) advisor);
}
addAdvisorInternal(pos, advisor);
}
private void addAdvisorInternal(int pos, Advisor advisor) throws AopConfigException {
Assert.notNull(advisor, "Advisor must not be null");
if (isFrozen()) {
throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
}
if (pos > this.advisors.size()) {
throw new IllegalArgumentException(
"Illegal position " + pos + " in advisor list with size " + this.advisors.size());
}
//这里就获取到了 advisors 数组,然后把advisor放进数组里
this.advisors.add(pos, advisor);
updateAdvisorArray();
adviceChanged();
}
? ? ? ? 可以看到。Spring 的代码逻辑跟我们猜想的一模一样
? ? ? ? 然后我们跟进一下 proxyFactory.getProxy() 获取代理对象的方法,
public Object getProxy() {
return createAopProxy().getProxy();
}
//首先看一下 createAopProxy()
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
//可以看到直接返回了属性,那么我们看下属性在哪里赋值的
public AopProxyFactory getAopProxyFactory() {
return this.aopProxyFactory;
}
//可以看到,调用构造函数的时候给了默认的实例化对象。
public ProxyCreatorSupport() {
this.aopProxyFactory = new DefaultAopProxyFactory();
}
//此时我们需要看DefaultAopProxyFactory.createAopProxy(this)
//参数传进来的是this,其实也就是实例化的 proxyFactory,从最开始我们看到它实现了AdvisedSupport,所以这里转换也很自然。
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//这三个条件的前两个都是可以在实例化 proxyFactory 的时候设置值的。下面分别解释一下
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
我们解释下 if 的判断逻辑
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.addAdvice(new AuthorityInterceptor());
proxyFactory.addAdvice(new MyAfterReturningAdvice());
proxyFactory.addAdvice(new MyMethodBeforeAdvice());
proxyFactory.setTarget(new OrderService());
proxyFactory.setInterfaces(OrderService.class.getInterfaces());
//可以看到这两个属性,是可以直接设置的
proxyFactory.setOptimize(false);
proxyFactory.setProxyTargetClass(false);
再看一下 Spring 的注释
/**
* Set whether proxies should perform aggressive optimizations.
* The exact meaning of "aggressive optimizations" will differ
* between proxies, but there is usually some tradeoff.
* Default is "false".
* <p>For example, optimization will usually mean that advice changes won't
* take effect after a proxy has been created. For this reason, optimization
* is disabled by default. An optimize value of "true" may be ignored
* if other settings preclude optimization: for example, if "exposeProxy"
* is set to "true" and that's not compatible with the optimization.
*/
public void setOptimize(boolean optimize) {
this.optimize = optimize;
}
大概解释一下就是,是否设置为最优代理,不同的代理模式对于最优的理解不同,但是也都有权衡,比如最优通常意味着,当代理被创建出来之后,切入点就不会再发生更改了。所以出于这个原因,最优代理默认是不生效的,因为如果proxyFactory.setExposeProxy(true);那么该代理就会被暴露在 Spring AOP 上下文中,就可以对 Advice 进行一些操作了。
/**
* Set whether to proxy the target class directly, instead of just proxying
* specific interfaces. Default is "false".
* <p>Set this to "true" to force proxying for the TargetSource's exposed
* target class. If that target class is an interface, a JDK proxy will be
* created for the given interface. If that target class is any other class,
* a CGLIB proxy will be created for the given class.
* <p>Note: Depending on the configuration of the concrete proxy factory,
* the proxy-target-class behavior will also be applied if no interfaces
* have been specified (and no interface autodetection is activated).
* @see org.springframework.aop.TargetSource#getTargetClass()
*/
public void setProxyTargetClass(boolean proxyTargetClass) {
this.proxyTargetClass = proxyTargetClass;
}
这个设置的意义在于,是否直接代理目标类,而不是代理接口。
拿本文的样例举例,如果 proxyFactory.setProxyTargetClass(true),则可以用类也可以用接口来接收代理对象 OrderService proxy = (OrderService) proxyFactory.getProxy();
而如果 proxyFactory.setProxyTargetClass(false),那么只能用接口来接收代理对象了。
IOrder proxy = (IOrder) proxyFactory.getProxy();
? ? ? ? 再看一下前面 if 语句的第三个参数 hasNoUserSuppliedProxyInterfaces(config),?
/**
* Determine whether the supplied {@link AdvisedSupport} has only the
* {@link org.springframework.aop.SpringProxy} interface specified
* (or no proxy interfaces specified at all).
*/
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
@Override
public Class<?>[] getProxiedInterfaces() {
return ClassUtils.toClassArray(this.interfaces);
}
//其实就是看目标类有多少个接口,如果没有接口,或者只有一个 SpringProxy 类型的接口,则返回为 true,这个 SpringProxy 是用来判断是不是已经被代理过了。每一个被代理的对象都会添加这个接口。这个在下文会讲
? ? ? ? 由上可以总结,如果目标类是接口或者已经是一个代理对象,那么就返回 jdk 代理。否则的话,如果设置了 optimize = true ,或者 proxyTargetClass = true,或者没有接口或只有一个SpringProxy 类型的接口,就返回 cglib 代理。如果还是不满足,就默认返回 jdk 代理。由此可见,想创建一个 cglib 代理还是挺难的。
? ? ? ? 我们下面看一下 JdkDynamicAopProxy.getProxy(), 即生成代理对象的方法
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
}
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
//该方法添加了添加了 SpringProxy.class 接口
static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
if (specifiedInterfaces.length == 0) {
// No user-specified interfaces: check whether target class is an interface.
Class<?> targetClass = advised.getTargetClass();
if (targetClass != null) {
if (targetClass.isInterface()) {
advised.setInterfaces(targetClass);
}
else if (Proxy.isProxyClass(targetClass)) {
advised.setInterfaces(targetClass.getInterfaces());
}
specifiedInterfaces = advised.getProxiedInterfaces();
}
}
boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
int nonUserIfcCount = 0;
if (addSpringProxy) {
nonUserIfcCount++;
}
if (addAdvised) {
nonUserIfcCount++;
}
if (addDecoratingProxy) {
nonUserIfcCount++;
}
Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
int index = specifiedInterfaces.length;
if (addSpringProxy) {
//在这里添加了刚刚我们说的 SpringProxy.class 接口
proxiedInterfaces[index] = SpringProxy.class;
index++;
}
if (addAdvised) {
proxiedInterfaces[index] = Advised.class;
index++;
}
if (addDecoratingProxy) {
proxiedInterfaces[index] = DecoratingProxy.class;
}
return proxiedInterfaces;
}
这里我们看到 Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);跟我们前面样例简单的创建代理对象的接口是一样的,我们传入的是 MyInvocationHandler,其中重写的 invoke 方法,会实现对方法的拦截。这里我们看到传入的是 this,也就是传入了 JdkDynamicAopProxy 对象。那么理所当然的我们应该去看 JdkDynamicAopProxy 的 invoke 方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
//这段代码进行一些简单判断,比如equals,hashcode等方法是不需要被拦截的
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
//这就是前面讲的如果设置了 exposeProxy 机会把代理对象放入AOP上下文中。
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
//获取拦截器链,比如本文章的样例就有三个拦截器
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
//如果拦截器为空,直接执行目标方法
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
//获取一个封装的 MethodInvocation 对象
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
//调用proceed()方法,执行拦截器和目标方法
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
? ? ? ? ? 由上面注释可以看到,有两个重要的方法,一个是获取拦截器链,一个是执行拦截器和目标方法的proceed()方法,分别跟进一下
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
//先尝试获取缓存
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
//如果缓存里没有,再通过方法获取拦截器链
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
//获取之后加入缓存
this.methodCache.put(cacheKey, cached);
}
return cached;
}
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
//获取到所有添加进来的advisor
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
//这是我们最常用的类型,基本上都能匹配
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
if (match) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
//引介增强,比较少用,后面再单独讲
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
// PrototypePlaceholderAdvisor,当给多例bean创建代理时才会用到
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
? ? ? ? 所以上面比较常用的是以下这段逻辑
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
if (match) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
? ? ? ? 此时需要引入两个概念,ClassFilter与MethodMatcher 这两个分别对切点进行匹配,如果匹配到了,就进行拦截。只不过匹配的颗粒度不同,ClassFilter 是用于查看类是否匹配,而 MethodMatcher 则用于对比方法是否匹配。此外MethodMatcher接口通过重载定义了两个matches()方法,两个参数的 matches 方法可以理解为粗筛,即不太精确的匹配,但是一般也满足要求了。带有三个参数的方法则为精晒,它可以在运行时对参数的类型进行筛选。此外中间还有一个isRuntime方法,只有该方法返回为true的时候才会进行精晒。MethodMatcher 接口有好多实现接口和实现类,都分别重写了这几个方法,这里暂时先不展开,等到解析Spring AOP 源码的时候再展开。
? ? ? ? 结合本文章前面的例子,我们在调用proxyFactory.addAdvice 的时候,加入的Pointcut.TRUE类型的pointCut,所以得到的MethodMatcher也是TrueMethodMatcher类型的,该类型的方法匹配起isRuntime()返回true,粗筛返回true。所以不会经过精晒,就会把取到的拦截器放入到拦截器链interceptorList中了。那么取到的拦截器是什么呢?跟我们放进去的是一样的吗?我们跟进 registry.getInterceptors(advisor) 看一下
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
//当类型为MethodInterceptor,如我们本例中的AuthorityInterceptor,会直接放入interceptors中返回
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
//如果是Advice类型的拦截器,会进行一层包装,进行转化
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[0]);
}
//拿AfterReturningAdvice举例,他会转化为AfterReturningAdviceInterceptor
class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof AfterReturningAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
return new AfterReturningAdviceInterceptor(advice);
}
}
//转化之后的advice不变,但是多了invoke,这是为了能跟 MethodInterceptor 类型的拦截器同时处理,都通过调用invoke来触发
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
private final AfterReturningAdvice advice;
/**
* Create a new AfterReturningAdviceInterceptor for the given advice.
* @param advice the AfterReturningAdvice to wrap
*/
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
}
????????
? ? ? ? 现在我们拿到拦截器链了,然后再看下 invocation.proceed()方法
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
//拦截器执行完了,才会执行目标方法,注意这里虽然是取得最后一个拦截器的下表,但是下面真正取拦截器的时候还会对这个进行++操作,所以,下面取拦截器的时候是取不到的,即拦截器执行完了。当然,这个下标的初始值为 -1。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//根据下表从连接器链里获取拦截器,每次进入到该方法,下标都会++,所以每次获取的拦截器是不一样的。
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//这里是处理动态匹配的逻辑
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
//如果匹配到则执行拦截器方法
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
//匹配不到的话,就跳过该拦截器接着往下走
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
//非动态匹配的逻辑,执行拦截器,我们本例是因为没有走精晒,所以不是动态拦截,会走这里的逻辑
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
? ? ? ? 执行拦截器之后就会调用拦截器的invoke方法,同时注意这里传入了一个this的参数,即MethodInvocation 对象实例,如果后面的方法再次调用该对象的proceed()方法,又回递归的回到当前这个proceed()方法,获取下一个拦截器继续执行。
? ? ? ? 分别走一下我们自定义个三个拦截器的流程。首先如果当前取到的是 MyAfterReturningAdvice 拦截器,当上面调用invoke(this)方法的时候,会首先来到AfterReturningAdviceInterceptor 的 invoke 方法,
public Object invoke(MethodInvocation mi) throws Throwable {
//递归调用 MethodInvocation 的proceed()方法
Object retVal = mi.proceed();
//调用自己重写的afterReturning()方法
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
//自己重写的方法被调用,实现了后置增强
public class MyAfterReturningAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
if (method.getName().equals("query")) {
System.out.println("=====保存一条搜索纪录=====");
}
}
}
? ? ? ? 这里需要注意的是,调用mi.proceed()方法会回到我们上面分析的proceed()方法,如果还有拦截器的话会继续上面的流程,直到目标方法执行完之后,才会走到这里自己写的增强方法,因为它是后置增强。
? ? ? ? 同理如果调用到 MethodBeforeAdvice 类型的增强器,它首先会进入MethodBeforeAdviceInterceptor 的 invoke 方法
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
private final MethodBeforeAdvice advice;
/**
* Create a new MethodBeforeAdviceInterceptor for the given advice.
* @param advice the MethodBeforeAdvice to wrap
*/
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//这里可以看到,它是先调用拦截器的增强方法,也就实现了前置增强
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
//递归调用拦截器链
return mi.proceed();
}
}
//此时调用了自定义的前置增强器方法实现增强。
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
if (method.getName().equals("query")) {
System.out.println("通过advice拦截查询方法");
}
}
}
? ? ? ? 最后再回到proceed()方法,看一下调用 MethodInterceptor 类型的拦截器。
//直接就会调到自定义的方法,如果你愿意的话,甚至不用写invocation.proceed();他就执行不到目标方法了
public class AuthorityInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
String methodName = invocation.getMethod().getName();
if (methodName.equals("query")) {
System.out.println("认证通过====");
//继续执行被拦截的方法
Object retVal = invocation.proceed();
System.out.println("通过 MethodInterceptor 拦截结束");
return retVal;
}
return invocation.proceed();
}
}
?总结
? ? ? ? 首先理一下几个概念的关系,Advised 包含 Advisor 数组,它是负责管理拦截器的,而Advisor 又是 Advice 的包装,此外它还包含 pointCut, 其中 pointCut 负责寻找切点,即在哪个位置进行增强,Advice 负责具体怎么增强。所以真正干活的是他们两个。然后 Advice 有很多孩子,比如BeforeAdvice, AfterAdvice 等,为了方便处理,他们最后在形成拦截器链的时候,会被转化为MethodInterceptor类型的拦截器,因为他们都有invoke方法,最后在遍历拦截器链的时候,分别调用对应的拦截器的invoke方法,就可以逐个调用各个拦截器的增强方法。
|