Spring AOP面向切面编程
1.AOP概览
AOP(Aspect Oriented Programming),什么是面向切面编程?
1)AOP是一种编程范式,不是编程语言
编程范式概览
-
面向过程编程
-
面向对象编程
-
函数式编程
-
事件驱动编程
-
面向切面编程
2)AOP是为了解决特定问题,不是解决所有问题。AOP是OOP的补充,不是替代关系。
AOP的初衷是关注点隔离
切面隔离:将功能性需求和非功能性需求分离开来
做系统设计时,通常将大系统做分解,按业务功能分解成一个个低耦合、高内聚的模块。
分解后发现有趣的事情是,有些东西是公用的,或者跨越了多个模块。
-
日志:对特定的操作输出日志来记录
-
安全:在操作之前进行操作检查
-
性能:统计每个方法的执行时间
-
事务:方法开始前开始事务,方法结束后提交或回滚事务
我们可以将这些通用模块写好,在实现业务模块的时候去调用就好了。
但是,功能是实现了,但是业务代码中大部分都是日志、性能、事务等,几乎把真正的业务代码给淹没了!
最好的方法是将日志、安全、事务这样的代码和业务代码完全隔离开来,因为他们的关注点和业务代码的关注点完全不同。
他们之间的关系应该是正交的。如果把这个业务功能看成一层层面包的话, 这些日志/安全/事务 像不像一个个“切面”(Aspect) ?
如果我们能让这些“切面“能和业务独立, 并且能够非常灵活的“织入”到业务方法中, 那就实现了面向切面编程(AOP)!
AOP的应用场景
-
审计日志:对特定的操作输出日志来记录
-
权限控制:在操作之前进行操作检查
-
性能监控:统计每个方法的执行时间
-
事务控制:方法开始前开始事务,方法结束后提交或回滚事务
-
缓存控制
-
异常处理
根据织入时机的不同,AOP可以分为以下3种实现方式
1)编译期织入(AspectJ)
2)类加载时织入(AspectJ 5+)
3)运行时织入(Spring AOP)
2.Spring AOP的使用举例
Spring AOP实现权限控制:只有管理员可以进行修改操作
@Service public class ProductService { public Product get(Long id) { System.out.println("get product id = " + id); return new Product(id, "aaa"); } @AdminOnly public void insert(Product product) { System.out.println("insert product"); } @AdminOnly public void delete(Long id) { System.out.println("delete product id = " + id); } }
@Aspect //1)表明这个是一个切面类 @Component public class SecurityAspect { //2)切入点 @Pointcut("@annotation(AdminOnly)") public void adminOnly() { } //3)通知 @Before("adminOnly()") public void check() { String user = CurrentUserHolder.get(); if (!"admin".equals(user)) { throw new RuntimeException("operation not allow"); } } }
PointCut切入点
PointCut(切入点):一个方法或一组方法(可以通过通配符支持)。
比如,“对于com.xxx这个包中所有类的execute方法” 。
Advice通知
Advice(通知):方法调用时需要做什么。比如,”在方法调用之前/之后 , 需要执行xxx操作“ 。
具体的通知类型包括:
-
before:前置通知,在方法调用前执行。
-
after returning:方法返回通知,在方法正常返回时执行。
-
throwing:方法异常通知,在方法抛出异常时执行。
-
after:方法结束通知,包含了方法正常返回和方法抛出异常两种情况。
-
around:环绕通知。
3.Spring AOP的实现原理
3.1运行时织入
根据织入时机的不同,AOP可以分为以下3种实现方式
1)编译期织入(AspectJ)
2)类加载时织入(AspectJ 5+)
3)运行时织入(Spring AOP)
Spring中的AOP实现是在运行时织入的。
运行时织入是如何实现的呢?通过动态代理的方式。
3.1.1代理模式
什么是代理模式
调用方Caller通过Proxy代理对象间接地与目标对象Target交互。
两个关键点:
1)Client客户端通过接口引用操作的对象Subject。且RealSubject真实对象和Proxy代理对象实现了同一个接口
2)Proxy代理对象会持有RealSubject真实对象的引用,真正要执行的方法委托给真实对象来执行,自己则执行一些额外的逻辑
public interface Subject { void request() throws Exception; }
public class RealSubject implements Subject { public void request() { System.out.println("RealSubject execute request()"); } }
public class Proxy implements Subject { private RealSubject realSubject; public Proxy(RealSubject realSubject) { this.realSubject = realSubject; } /** * 在真实对象request()方法之前或之后,可以执行一些额外的操作 */ public void request() throws Exception{ System.out.println("before"); try { realSubject.request(); } catch (Exception e) { System.out.println("ex:" + e.getMessage()); throw e; } finally { System.out.println("after"); } } }
public class Client { public static void main(String[] args) throws Exception{ Subject subject = new Proxy(new RealSubject()); subject.request(); } }
运行结果
before RealSubject execute request() after
上面代码展示的是静态代理的实现。
静态代理有如下缺点:
1)假设真实对象有100方法,则代理对象需要对100个方法进行委托。
2)且在这100个方法中代理对象执行的额外逻辑是一样的。
就像下面代码展示的那样。
public interface Subject { void request() throws Exception; void request2() throws Exception; void request3() throws Exception; void request4() throws Exception;
public class RealSubject implements Subject { public void request() { System.out.println("RealSubject execute request()"); } public void request2() { System.out.println("RealSubject execute request2()"); } public void request3() { System.out.println("RealSubject execute request3()"); } public void request4() { System.out.println("RealSubject execute request4()"); } }
public class Proxy implements Subject { private RealSubject realSubject; public Proxy(RealSubject realSubject) { this.realSubject = realSubject; } public void request() throws Exception{ System.out.println("before"); try { realSubject.request(); } catch (Exception e) { System.out.println("ex:" + e.getMessage()); throw e; } finally { System.out.println("after"); } } //静态代理的缺点: //由于Subject添加了request2()、request3()、request4()方法,代理类中也要实现相应的方法 //而且代理对象在request2()、request3()、request4()等方法中额外需要执行的逻辑都是一样的。 public void request2() throws Exception{ System.out.println("before"); try { realSubject.request2(); } catch (Exception e) { System.out.println("ex:" + e.getMessage()); throw e; } finally { System.out.println("after"); } } public void request3() throws Exception{ System.out.println("before"); try { realSubject.request3(); } catch (Exception e) { System.out.println("ex:" + e.getMessage()); throw e; } finally { System.out.println("after"); } } public void request4() throws Exception{ System.out.println("before"); try { realSubject.request4(); } catch (Exception e) { System.out.println("ex:" + e.getMessage()); throw e; } finally { System.out.println("after"); } } }
由于静态代理有上面的缺点,就产生了动态代理技术。
动态代理有两种实现方式
1)基于接口实现:JDK动态代理
2)基于继承实现:cglib动态代理
3.1.2 JDK动态代理
将上面的静态代理实现,改为使用JDK动态代理后,代码如下。
public class JdkProxySubject implements InvocationHandler { private RealSubject realSubject; public JdkProxySubject(RealSubject realSubject) { this.realSubject = realSubject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before"); Object result = null; try { result = method.invoke(realSubject, args); } catch (Exception e) { throw e; } finally { System.out.println("after"); } return result; } }
public class Client { public static void main(String[] args) throws Exception { //通过调用Proxy.newProxyInstance生成代理对象 //方法参数为:1)classLoader 2)要代理的接口 3)代理对象的InvocationHandler //(通过方法参数也可以看出来,JDK代理只能通过代理接口来来实现动态代理) Subject subject = (Subject) Proxy.newProxyInstance(Client.class.getClassLoader(), new Class[]{Subject.class}, new JdkProxySubject(new RealSubject())); //调用代理对象的request方法。 //(根据InvocationHandler接口的定义,可以知道实际调用的是JdkProxySubject里的invoke方法) subject.request(); } }
3.1.3 cglib动态代理
将上面的静态代理实现,改为使用cglib动态代理后,代码如下。
public class DemoMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("before in cglib"); Object result = null; try { //注意:调用的是proxy.invokeSuper来调用目标类的方法 result = methodProxy.invokeSuper(o, args); } catch (Exception e) { System.out.println("ex:" + e.getMessage()); throw e; } finally { System.out.println("after in cglib"); } return null; } }
public class Client { public static void main(String[] args) throws Exception { //创建一个增强器 Enhancer enhancer = new Enhancer(); //设置目标类 enhancer.setSuperclass(RealSubject.class); //设置拦截对象 enhancer.setCallback(new DemoMethodInterceptor()); //生成代理对象 Subject subject = (Subject) enhancer.create(); //调用代理对象的request方法 subject.request(); } }
3.1.4 Spring如何创建代理bean
动态代理有两种实现方式,JDK动态代理和cglib动态代理,那Spring是如何选择的?
ProxyFactoryBean的getObject()方法
@Override public Object getObject() throws BeansException { initializeAdvisorChain(); //对singleton和prototype的类型进行区分,生成对应的proxy if (isSingleton()) { return getSingletonInstance(); } else { if (this.targetName == null) { logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property."); } return newPrototypeInstance(); } }
getSingletonInstance()方法
/** * Return the singleton instance of this class's proxy object, * lazily creating it if it hasn't been created already. * @return the shared singleton proxy */ private synchronized Object getSingletonInstance() { if (this.singletonInstance == null) { this.targetSource = freshTargetSource(); if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) { // Rely on AOP infrastructure to tell us what interfaces to proxy. Class<?> targetClass = getTargetClass(); if (targetClass == null) { throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy"); } setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader)); } // Initialize the shared singleton instance. super.setFrozen(this.freezeProxy); this.singletonInstance = getProxy(createAopProxy()); } return this.singletonInstance; }
其中,生成代理实例的代码是这句。
this.singletonInstance = getProxy(createAopProxy());
可以将这句代码拆成下面两句。
1)aopProxy = createAopProxy()。
2)this.singletonInstance = getProxy(aopProxy) 。
createAopProxy()
createAopProxy()的方法如下。
protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } return getAopProxyFactory().createAopProxy(this); }
其中getAopProxyFactory()返回一个AopProxyFactory。在这里,返回的是AopProxyFactory的默认实现DefaultAopProxyFactory。
DefaultAopProxyFactory的createAopProxy()方法
/** * Default {@link AopProxyFactory} implementation, creating either a CGLIB proxy * or a JDK dynamic proxy. * * <p>Creates a CGLIB proxy if one the following is true for a given * {@link AdvisedSupport} instance: * <ul> * <li>the {@code optimize} flag is set * <li>the {@code proxyTargetClass} flag is set * <li>no proxy interfaces have been specified * </ul> * * <p>In general, specify {@code proxyTargetClass} to enforce a CGLIB proxy, * or specify one or more interfaces to use a JDK dynamic proxy. */ @SuppressWarnings("serial") public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { //如果满足下面3个条件,将使用cglib动态代理 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."); } //以下两种情况除外 //targetClass是接口 或者 targetClass本身就是使用jdk动态代理的proxy if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } //否则,使用jdk动态代理 else { return new JdkDynamicAopProxy(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]))); } }
1)如果目标对象实现了接口,则默认采用JDK动态代理
2)如果目标对象没有实现接口,则采用cglib进行动态代理
3)如果目标对象实现了接口,且强制cglib代理,则使用cglib动态代理
getProxy(aopProxy)
protected Object getProxy(AopProxy aopProxy) { return aopProxy.getProxy(this.proxyClassLoader); }
如果入参中的aopProxy是JdkDynamicAopProxy的实例的话,会调用JdkDynamicAopProxy类中的方法。
如果入参中的aopProxy是ObjenesisCglibAopProxy的实例的话,会调用ObjenesisCglibAopProxy类中的方法。
JdkDynamicAopProxy.getProxy()方法
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { @Override public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); } }
可以看到JdkDynamicAopProxy实现了InvocationHandler接口,并通过Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)生成代理对象。
ObjenesisCglibAopProxy.getProxy()方法
与下面代码逻辑类似。
Enhancer enhancer = new Enhancer(); //设置目标类 enhancer.setSuperclass(RealSubject.class); //设置拦截对象 enhancer.setCallback(new DemoMethodInterceptor()); //生成代理对象 Subject subject = (Subject) enhancer.create(); //调用代理对象的request方法 subject.request();
4.Spring AOP的实现原理
4.1 链式调用
多个AOP 切面是如何叠加起作用的?
public class Proxy implements Subject { private RealSubject realSubject; public Proxy(RealSubject realSubject) { this.realSubject = realSubject; } /** * realSubject.request()是目标方法 * 在目标方法调用前、调用后、发生异常时,都需要被拦截 * aop是如何实现将这些调用串起来的? */ public void request() throws Exception{ //before //记录调用次数 //权限控制,仅管理员可以操作 //开启事务 System.out.println("before:记录调用次数"); System.out.println("before:进行权限控制,仅管理员可以进行后续操作"); System.out.println("before:开启事务"); try { realSubject.request(); } catch (Exception e) { //afterThrowing //事务失败,回滚操作 System.out.println("afterThrowing:事务失败,回滚操作 ex:" + e.getMessage()); throw e; } finally { //afterReturning //事务成功,提交操作 System.out.println("afterReturning:事务成功,提交操作"); } } }
4.1.1 职责链模式
4.1.1.1 V1
public abstract class Handler { private Handler successor; public Handler getSuccessor() { return successor; } public void setSuccessor(Handler successor) { this.successor = successor; } //对外暴露的方法 public void execute() { handleProcess(); if (successor != null) { successor.execute(); } } // 需要子类实现 protected abstract void handleProcess(); }
public class Client { static class HandlerA extends Handler { @Override protected void handleProcess() { System.out.println("handle by a"); } } static class HandlerB extends Handler { @Override protected void handleProcess() { System.out.println("handle by b"); } } static class HandlerC extends Handler { @Override protected void handleProcess() { System.out.println("handle by c"); } } //缺点:各个handler之间的顺序需要显式指定 //handlerA.setSuccessor(handlerB); //handlerB.setSuccessor(handlerC); public static void main(String[] args) { HandlerA handlerA = new HandlerA(); HandlerB handlerB = new HandlerB(); HandlerC handlerC = new HandlerC(); handlerA.setSuccessor(handlerB); handlerB.setSuccessor(handlerC); handlerA.execute(); } }
运行结果
handle by a handle by b handle by c
4.1.1.2 V2
public abstract class ChainHandler { public void execute(Chain chain) { handleProcess(); chain.proceed(); } protected abstract void handleProcess(); }
public class Chain { //将各个handler保存在handlers这个list中 //各个handler之间的执行顺序由chain来维持 private List<ChainHandler> handlers; private int index = 0; public Chain(List<ChainHandler> handlers) { this.handlers = handlers; } public void proceed() { if (index >= handlers.size()) { return; } handlers.get(index++).execute(this); } }
public class ChainClient { static class ChainHandlerA extends ChainHandler { @Override protected void handleProcess() { System.out.println("handle by a"); } } static class ChainHandlerB extends ChainHandler { @Override protected void handleProcess() { System.out.println("handle by b"); } } static class ChainHandlerC extends ChainHandler { @Override protected void handleProcess() { System.out.println("handle by c"); } } public static void main(String[] args) { /** 在list中的顺序决定了handler的执行顺序 */ List<ChainHandler> handlers = Arrays.asList( new ChainHandlerA(), new ChainHandlerB(), new ChainHandlerC() ); Chain chain = new Chain(handlers); chain.proceed(); } }
运行结果
handle by a handle by b handle by c
4.1.2 Spring内部实现
以JDK动态代理为例,调用目标对象的方法时,实际上调用的是代理对象的invoke方法。
JdkDynamicAopProxy的invoke方法
/** * Implementation of {@code InvocationHandler.invoke}. * <p>Callers will see exactly the exception thrown by the target, * unless a hook method throws an exception. */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation; Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Class<?> targetClass = null; Object target = null; 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; if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // May be null. Get as late as possible to minimize the time we "own" the target, // in case it comes from a pool. target = targetSource.getTarget(); if (target != null) { targetClass = target.getClass(); } // 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... invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. retVal = invocation.proceed(); } // Massage return value if necessary. Class<?> returnType = method.getReturnType(); if (retVal != null && retVal == target && 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); } } }
JdkDynamicAopProxy的invoke方法核心代码如下:
//1).得到目标方法的拦截器链 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); //2). 调用拦截器链 //如果chain是空的,直接调用target对象的method if (chain.isEmpty()) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } //如果chain不是空的,进行拦截器链的调用 else { invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. retVal = invocation.proceed(); }
1)拦截器链是如何生成的
我们顺着this.advised.getInterceptorsAndDynamicInterceptionAdvice往下走。
/** * Determine a list of {@link org.aopalliance.intercept.MethodInterceptor} objects * for the given method, based on this configuration. * @param method the proxied method * @param targetClass the target class * @return List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers) */ public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, 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; }
上面的this.advisorChainFactory其实是DefaultAdvisorChainFactory。
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable { @Override public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, Class<?> targetClass) { // This is somewhat tricky... We have to process introductions first, // but we need to preserve order in the ultimate list. List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length); Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); boolean hasIntroductions = hasMatchingIntroductions(config, actualClass); AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); //遍历config.getAdvisors for (Advisor advisor : config.getAdvisors()) { if (advisor instanceof PointcutAdvisor) { // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { //调用registry.getInterceptors得到advisor的MethodInterceptor MethodInterceptor[] interceptors = registry.getInterceptors(advisor); //调用pointcutAdvisor.getPointcut().getMethodMatcher()得到pointcut的MethodMatcher MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); //调用interceptorList.add将拦截器加入到拦截器链中 if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) { 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)); } } else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; } /** * Determine whether the Advisors contain matching introductions. */ private static boolean hasMatchingIntroductions(Advised config, Class<?> actualClass) { for (int i = 0; i < config.getAdvisors().length; i++) { Advisor advisor = config.getAdvisors()[i]; if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (ia.getClassFilter().matches(actualClass)) { return true; } } } return false; } }
List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, Class<?> targetClass)
其实这里的config就是ProxyFactoryBean的实例。(config传入了个AdvisedSupport实例,ProxyFactoryBean继承了AdvisedSupport)
继续找ProxyFactoryBean的代码。
ProxyFactoryBean的getObject方法调用时,会对adviceChain进行初始化(如果未初始化的话)。
@Override public Object getObject() throws BeansException { //adviceChain拦截器链的初始化 initializeAdvisorChain(); if (isSingleton()) { return getSingletonInstance(); } else { if (this.targetName == null) { logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property."); } return newPrototypeInstance(); } }
initializeAdvisorChain的内部实现:
因为ProxyFactoryBean实现了BeanFactoryAware接口,因此可以拿到当前的容器实例beanFactory。
通过调用this.beanFactory.get(beanName)方法将各个advice bean拿出来,然后加入到list中。
initializeAdvisorChain的具体内部实现如下。
/** * Create the advisor (interceptor) chain. Advisors that are sourced * from a BeanFactory will be refreshed each time a new prototype instance * is added. Interceptors added programmatically through the factory API * are unaffected by such changes. */ private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException { if (this.advisorChainInitialized) { return; } if (!ObjectUtils.isEmpty(this.interceptorNames)) { if (this.beanFactory == null) { throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " + "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames)); } // Globals can't be last unless we specified a targetSource using the property... if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) && this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) { throw new AopConfigException("Target required after globals"); } // Materialize interceptor chain from bean names. for (String name : this.interceptorNames) { if (logger.isTraceEnabled()) { logger.trace("Configuring advisor or advice '" + name + "'"); } if (name.endsWith(GLOBAL_SUFFIX)) { if (!(this.beanFactory instanceof ListableBeanFactory)) { throw new AopConfigException( "Can only use global advisors or interceptors with a ListableBeanFactory"); } addGlobalAdvisor((ListableBeanFactory) this.beanFactory, name.substring(0, name.length() - GLOBAL_SUFFIX.length())); } else { // If we get here, we need to add a named interceptor. // We must check if it's a singleton or prototype. Object advice; if (this.singleton || this.beanFactory.isSingleton(name)) { // Add the real Advisor/Advice to the chain advice = this.beanFactory.getBean(name); } else { // It's a prototype Advice or Advisor: replace with a prototype. // Avoid unnecessary creation of prototype bean just for advisor chain initialization. advice = new PrototypePlaceholderAdvisor(name); } addAdvisorOnChainCreation(advice, name); } } } this.advisorChainInitialized = true; }
总结,在ProxyFactoryBean的getObject方法中,会初始化拦截器链,相关的bean是通过调用beanFactory.get(beanName)方法得到的。
2)拦截器链是如何链式调用的
ReflectiveMethodInvocation.proceed执行拦截器链的调用。
下面摘录了ReflectiveMethodInvocation的部分代码。
//ReflectiveMethodInvocation实现了接口ProxyMethodInvocation,而ProxyMethodInvocation是MethodInvocation的子接口。 //因此,ReflectiveMethodInvocation实现了MethodInvocation接口。 public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable { protected final Object proxy; protected final Object target; protected final Method method; protected Object[] arguments; private final Class<?> targetClass; /** * List of MethodInterceptor and InterceptorAndDynamicMethodMatcher * that need dynamic checks. */ //拦截器列表 protected final List<?> interceptorsAndDynamicMethodMatchers; /** * Index from 0 of the current interceptor we're invoking. * -1 until we invoke: then the current interceptor. */ private int currentInterceptorIndex = -1; @Override public Object proceed() throws Throwable { //We start with an index of -1 and increment early. //如果拦截器list到了最后了,运行目标方法 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } //根据currentInterceptorIndex得到list中的拦截器 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); //1.如果拦截器中不仅有Interceptor,还需要进行动态方法匹配DynamicMethodMatcher //InterceptorAndDynamicMethodMatcher包含了Interceptor和DynamicMethodMatcher, //其中DynamicMethodMatcher用于运行时检查,用于在运行时判断方法是否需要拦截 //(说明:MethodMatcher方法匹配分静态和动态两种 //个人理解: //静态检查:比如你要拦截的方法名是精确的,就是某个类的某个方法,可以在程序非运行时,就可判断是否需要拦截 //动态检查:比如你要拦截的某个方法,且要求入参为“aaa”,这种肯定需要运行时判断) if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // Evaluate dynamic method matcher here: static part will already have // been evaluated and found to match. InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; //1.1 如果匹配上了,调用interceptor的invoke方法 if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { //如果匹配上了,调用拦截器方法 //注意:interceptor.invoke(this)传入的是this。 //而ReflectiveMethodInvocation实现了MethodInvocation接口 //因此,传入的是一个MethodInvocation实例。 return dm.interceptor.invoke(this); } //1.2 如果没有匹配上, else { // Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. return proceed(); } } //2. 如果拦截器就是个interceptor,调用invoker方法 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); } } }
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; }
MethodBeforeAdviceInterceptor:会在目标方法运行之前进行拦截。
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable { private 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(); } }
AfterReturningAdviceInterceptor:会在目标方法返回后进行拦截
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; } }
3)Spring使用职责链模式实现拦截器链链式调用
将上面调用拦截器链的简化下,如下。
public interface MethodInterceptor { Object invoke(MethodInvocation mi); }
public class MethodBeforeInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation mi) { before(); return mi.proceed(); } private void before() { System.out.println("Method before"); } }
public class AfterReturningInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation mi) { Object retVal = mi.proceed(); afterReturning(); return retVal; } private void afterReturning() { System.out.println("afterReturning"); } }
public interface MethodInvocation { Object proceed(); }
public class ReflectiveMethodInvocation implements MethodInvocation{ private List<MethodInterceptor> interceptors; public ReflectiveMethodInvocation(List<MethodInterceptor> interceptors) { this.interceptors = interceptors; } private int currentInterceptorIndex = -1; public Object proceed() { if (currentInterceptorIndex == interceptors.size() - 1) { System.out.println("invoke target method"); return "obj after invoke target method"; } return interceptors.get(++currentInterceptorIndex).invoke(this); } }
public class Client { public static void main(String[] args) { List<MethodInterceptor> interceptors = Arrays.asList( new AfterReturningInterceptor(), new MethodBeforeInterceptor() ); ReflectiveMethodInvocation invocation = new ReflectiveMethodInvocation(interceptors); invocation.proceed(); } }
结果如下:
Method before invoke target method afterReturning
(这里抛个思考题:
运行结果与List<MethodInterceptor>中interceptor的顺序有关吗?
把new AfterReturningInterceptor()和new MethodBeforeInterceptor()换下顺序,结果会不同吗?
答案:无关,不会。
)
5. ProxyFactory实现AOP
通过配置的方式使用AOP时,是通过ProxyFactoryBean的getObject()方法得到代理对象的。
Spring 提供ProxyFactory类,可以通过编写代码的方式创建代理对象。
TargetImpl target = new TargetImpl(); ProxyFactory proxyFactory = new ProxyFactory(target); proxyFactory.addAdvisor(yourAdvisor); proxyFactory.addAdvice(yourAdvice); TargetImpl targetProxy = (TargetImpl)proxyFactory.getProxy();
ProxyFactory类提供的方法如下。
/** * Factory for AOP proxies for programmatic use, rather than via a bean * factory. This class provides a simple way of obtaining and configuring * AOP proxies in code. * * @author Rod Johnson * @author Juergen Hoeller * @author Rob Harrop * @since 14.03.2003 */ @SuppressWarnings("serial") public class ProxyFactory extends ProxyCreatorSupport { /** * Create a new ProxyFactory. */ public ProxyFactory() { } public ProxyFactory(Object target) { setTarget(target); setInterfaces(ClassUtils.getAllInterfaces(target)); } public ProxyFactory(Class<?>... proxyInterfaces) { setInterfaces(proxyInterfaces); } public ProxyFactory(Class<?> proxyInterface, Interceptor interceptor) { addInterface(proxyInterface); addAdvice(interceptor); } public ProxyFactory(Class<?> proxyInterface, TargetSource targetSource) { addInterface(proxyInterface); setTargetSource(targetSource); } public Object getProxy() { return createAopProxy().getProxy(); } public Object getProxy(ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); } @SuppressWarnings("unchecked") public static <T> T getProxy(Class<T> proxyInterface, Interceptor interceptor) { return (T) new ProxyFactory(proxyInterface, interceptor).getProxy(); } @SuppressWarnings("unchecked") public static <T> T getProxy(Class<T> proxyInterface, TargetSource targetSource) { return (T) new ProxyFactory(proxyInterface, targetSource).getProxy(); } public static Object getProxy(TargetSource targetSource) { if (targetSource.getTargetClass() == null) { throw new IllegalArgumentException("Cannot create class proxy for TargetSource with null target class"); } ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTargetSource(targetSource); proxyFactory.setProxyTargetClass(true); return proxyFactory.getProxy(); } }