关于 AOP 的概念描述及相关术语可以参考 彻底征服 Spring AOP 之 理论篇 总结的很好; 本文将着重分析下 AOP 的实现过程。
public interface UserService { void say (); }
接口实现类如下:
public class UserServiceImpl implements UserService { public void say() { System.out.println("do say method"); } }
public class UserAdvice implements MethodBeforeAdvice { public void before(Method m, Object[] args, Object target) throws Throwable { System.out.println("do before advice ...."); } }
<beans> <!-- 配置接口实现类 --> <bean id="userService" class="org.springframework.aop.UserServiceImpl" /> <!-- 配置通知类 --> <bean id="userAdvice" class="org.springframework.aop.UserAdvice" /> <!--代理类--> <bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!--要代理的接口 创建代理对象时需要--> <!-- 配置该属性会采用 jdk 动态代理,反之采用 cglib --> <property name="proxyInterfaces"> <value>org.springframework.aop.UserService</value> </property> <!--拦截器名字,也就是我们定义的通知类,可配置多个通知类 --> <property name="interceptorNames"> <list> <value>userAdvice</value> </list> </property> <!--目标类,就是我们业务的实现类--> <property name="target"> <ref bean="userService"/> </property> </bean> </beans>
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/org/springframework/aop/aop.xml"); UserService userService = (UserService) ctx.getBean("userProxy"); userService.say();
执行结果如下:
do before advice .... do say method
从执行结果来看,前置通知对接口方法已经起增强作用。 下面我们将看下 Spring AOP 的具体实现。
从上面的示例可以看出 Spring AOP 的配置主要基于类 ProxyFactoryBean
,那么我们就以此为入口去剖析其实现。
从 ProxyFactoryBean
的类结构,我们发现其实现了接口 BeanFactoryAware
,也就说明在其实例化过程中会调用方法 setBeanFactory
; 源码如下:
public void setBeanFactory(BeanFactory beanFactory) throws BeansException { // 设置 beanFactory this.beanFactory = beanFactory; logger.debug("Set BeanFactory. Will configure interceptor beans..."); // 创建 advisor chain createAdvisorChain(); logger.info("ProxyFactoryBean config: " + this); if (singleton) { // Eagerly initialize the shared singleton instance getSingletonInstance(); // We must listen to superclass advice change events to recache singleton // instance if necessary addListener(this); } }
在 setBeanFactory
方法中除了设置 beanFactory
, 还有一个重要的动作就是 createAdvisorChain
创建 advisor chain (也可以理解为就是切面链)。 那么下面我们将看下具体是怎样创建 advisor chain 的。
private void createAdvisorChain() throws AopConfigException, BeansException { // 检测是否配置了 interceptorNames, 也就是是否配置相关 advice 通知; 若没有配置直接返回 if (this.interceptorNames == null || this.interceptorNames.length == 0) { //throw new AopConfigException("Interceptor names are required"); return; } // Globals can't be last if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX)) { throw new AopConfigException("Target required after globals"); } // Materialize interceptor chain from bean names for (int i = 0; i < this.interceptorNames.length; i++) { String name = this.interceptorNames[i]; logger.debug("Configuring interceptor '" + name + "'"); // 判断 interceptor name 是否以 * 结尾 if (name.endsWith(GLOBAL_SUFFIX)) { if (!(this.beanFactory instanceof ListableBeanFactory)) { throw new AopConfigException("Can only use global advisors or interceptors with a ListableBeanFactory"); } else { addGlobalAdvisor((ListableBeanFactory) this.beanFactory, name.substring(0, name.length() - GLOBAL_SUFFIX.length())); } } else { // add a named interceptor // 获取 advice bean Object advice = this.beanFactory.getBean(this.interceptorNames[i]); // 将 advisor 加入到链表中 addAdvisor(advice, this.interceptorNames[i]); } } }
private void addAdvisor(Object next, String name) { logger.debug("Adding advisor or TargetSource [" + next + "] with name [" + name + "]"); // We need to add a method pointcut so that our source reference matches // what we find from superclass interceptors. // 查找 advice 通知匹配的 pointcut, 并创建一个 advisor Object advisor = namedBeanToAdvisorOrTargetSource(next); if (advisor instanceof Advisor) { // if it wasn't just updating the TargetSource logger.debug("Adding advisor with name [" + name + "]"); addAdvisor((Advisor) advisor); this.sourceMap.put(advisor, name); } else { logger.debug("Adding TargetSource [" + advisor + "] with name [" + name + "]"); setTargetSource((TargetSource) advisor); // save target name this.targetName = name; } }
从 addAdvisor
方法可以看到,在添加 advisor 前,需要先创建 advisor , 会调用方法 namedBeanToAdvisorOrTargetSource
private Object namedBeanToAdvisorOrTargetSource(Object next) { try { // 将 advice 包装成一个 advisor Advisor adv = GlobalAdvisorAdapterRegistry.getInstance().wrap(next); return adv; } catch (UnknownAdviceTypeException ex) { } }
namedBeanToAdvisorOrTargetSource
方法会调用单例模式的 GlobalAdvisorAdapterRegistry
的方法 wrap
将 advice 包装成一个 advisor;
在查看 wrap
的实现之前,我们可以先看下 GlobalAdvisorAdapterRegistry
是做什么的。
public class GlobalAdvisorAdapterRegistry extends DefaultAdvisorAdapterRegistry { private static GlobalAdvisorAdapterRegistry instance = new GlobalAdvisorAdapterRegistry(); public static GlobalAdvisorAdapterRegistry getInstance() { return instance; } private GlobalAdvisorAdapterRegistry() { } } public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry { private List adapters = new LinkedList(); public DefaultAdvisorAdapterRegistry() { // register well-known adapters registerAdvisorAdapter(new BeforeAdviceAdapter()); registerAdvisorAdapter(new AfterReturningAdviceAdapter()); registerAdvisorAdapter(new ThrowsAdviceAdapter()); } }
从上面 GlobalAdvisorAdapterRegistry
的实现可以看出其采用了单例模式并继承了类 DefaultAdvisorAdapterRegistry
在构造的过程中内置了 3 种 advice adapter 用于匹配 advice 。 下面我们在看下它是如何 wrap
包装 advice 的。
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException { if (adviceObject instanceof Advisor) { return (Advisor) adviceObject; } if (!(adviceObject instanceof Advice)) { throw new UnknownAdviceTypeException(adviceObject); } Advice advice = (Advice) adviceObject; if (advice instanceof Interceptor) { // So well-known it doesn't even need an adapter return new DefaultPointcutAdvisor(advice); } // 遍历内置的 advice adapters for (int i = 0; i < this.adapters.size(); i++) { // Check that it is supported AdvisorAdapter adapter = (AdvisorAdapter) this.adapters.get(i); // 判断当前 adapter 是否支付当前 advice if (adapter.supportsAdvice(advice)) { // 如果支持的话,返回一个 DefaultPointcutAdvisor return new DefaultPointcutAdvisor(advice); } } throw new UnknownAdviceTypeException(advice); }
从 wrap
的实现可以发现,若 advice 匹配了某个 adapter 将会创建一个 DefaultPointcutAdvisor
实例并返回;
public class DefaultPointcutAdvisor implements PointcutAdvisor, Ordered { private int order = Integer.MAX_VALUE; private Pointcut pointcut; private Advice advice; public DefaultPointcutAdvisor() { } public DefaultPointcutAdvisor(Advice advice) { this(Pointcut.TRUE, advice); } public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) { this.pointcut = pointcut; this.advice = advice; } } /** * Canonical instance that matches everything. * 默认匹配所有的类及类下的所有方法 */ Pointcut TRUE = new Pointcut() { public ClassFilter getClassFilter() { return ClassFilter.TRUE; } public MethodMatcher getMethodMatcher() { return MethodMatcher.TRUE; } public String toString() { return "Pointcut.TRUE"; } };
从 DefaultPointcutAdvisor
的实例可以看出创建 advisor (切面) 的过程实际就是将 advice (通知) 和 pointcut (切入点) 绑定的过程;同时在 Spring AOP 默认的 pointcut 是拦截所有类下的所有方法。
简单点说也就是当前切面将会拦截哪些类下的哪些方法,拦截过程中会采用哪些增强处理(前置通知,返回通知,异常通知)。
至此 advisor chain 的创建流程结束,其过程大概如下:
从 ProxyFactoryBean
类的名字及类结构,发现其实现接口 FactoryBean
, 也就是说当其 getBean
的时候会调用方法 getObject
, 源码如下:
public Object getObject() throws BeansException { // 默认单例 return (this.singleton) ? getSingletonInstance() : newPrototypeInstance(); } private Object getSingletonInstance() { if (this.singletonInstance == null) { // This object can configure the proxy directly if it's // being used as a singleton. this.singletonInstance = createAopProxy().getProxy(); } return this.singletonInstance; } protected synchronized AopProxy createAopProxy() { if (!isActive) { activate(); } return getAopProxyFactory().createAopProxy(this); }
public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException { // 是否采用 cglib 代理 boolean useCglib = advisedSupport.getOptimize() || advisedSupport.getProxyTargetClass() || advisedSupport.getProxiedInterfaces().length == 0; if (useCglib) { return CglibProxyFactory.createCglibProxy(advisedSupport); } else { // Depends on whether we have expose proxy or frozen or static ts return new JdkDynamicAopProxy(advisedSupport); } }
public Object getProxy(ClassLoader cl) { logger.debug("Creating JDK dynamic proxy"); Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); return Proxy.newProxyInstance(cl, proxiedInterfaces, this); }
ProxyFactoryBean
通过判断 proxyTargetClass , interfaceNames 的配置去选择采用 cglib 或者 jdk 来创建目标代理对象。
上面简单介绍了代理对象的创建,那么在看下当我们调用目标方法的时候,代理是如何执行的,以 jdk 动态代理为例:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation = null; Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = advised.targetSource; Class targetClass = null; Object target = null; try { // Try special rules for equals() method and implementation of the // Advised AOP configuration interface // Short-circuit expensive Method.equals() call, as Object.equals() isn't overloaded if (method.getDeclaringClass() == Object.class && "equals".equals(method.getName())) { // What if equals throws exception!? // This class implements the equals() method itself return new Boolean(equals(args[0])); } else if (Advised.class == method.getDeclaringClass()) { // Service invocations on ProxyConfig with the proxy config return AopProxyUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal = null; // 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(); } if (this.advised.exposeProxy) { // Make invocation available if necessary oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // Get the interception chain for this method // 获取目标类,执行方法的 interception chain List chain = this.advised.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this.advised, proxy, 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 retVal = AopProxyUtils.invokeJoinpointUsingReflection(target, method, args); } else { 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 if (retVal != null && retVal == target) { retVal = proxy; } return retVal; } finally { } }
首先我们看下如何获取匹配当前 method 的拦截器, 参考 calculateInterceptorsAndDynamicInterceptionAdvice
的实现如下:
public static List calculateInterceptorsAndDynamicInterceptionAdvice(Advised config, Object proxy, Method method, Class targetClass) { // 用于存储拦截器 List interceptors = new ArrayList(config.getAdvisors().length); // 遍历 advisor (切面) for (int i = 0; i < config.getAdvisors().length; i++) { Advisor advisor = config.getAdvisors()[i]; if (advisor instanceof PointcutAdvisor) { // Add it conditionally PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; // 判断当前 target class 是否当前 pointcut if (pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) { // 获取 advisor 对应的 method interceptor MethodInterceptor interceptor = (MethodInterceptor) GlobalAdvisorAdapterRegistry.getInstance().getInterceptor(advisor); MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); // 判断当前 method 是否匹配 pointcut if (mm.matches(method, targetClass)) { if (mm.isRuntime()) { // Creating a new object instance in the getInterceptor() method // isn't a problem as we normally cache created chains interceptors.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm) ); } else { // 将拦截器加入链表中 interceptors.add(interceptor); } } } } else if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (ia.getClassFilter().matches(targetClass)) { MethodInterceptor interceptor = (MethodInterceptor) GlobalAdvisorAdapterRegistry.getInstance().getInterceptor(advisor); interceptors.add(interceptor); } } } // for return interceptors; } // calculateInterceptorsAndDynamicInterceptionAdvice
我们在详细看下如何查找 advisor 匹配的拦截器呢,同样与上文中 wrap
类似,如下:
public Interceptor getInterceptor(Advisor advisor) throws UnknownAdviceTypeException { Advice advice = advisor.getAdvice(); if (advice instanceof Interceptor) { return (Interceptor) advice; } // 遍历内置的 advisor adapter for (int i = 0; i < this.adapters.size(); i++) { AdvisorAdapter adapter = (AdvisorAdapter) this.adapters.get(i); // 是否匹配当前 advice if (adapter.supportsAdvice(advice)) { // 匹配的话返回 interceptor return adapter.getInterceptor(advisor); } } throw new UnknownAdviceTypeException(advisor.getAdvice()); }
到目前为止,我们多次发现 AdvisorAdapter
的身影,下面我们看下其具体的实现, 以 BeforeAdviceAdapter
为例:
class BeforeAdviceAdapter implements AdvisorAdapter { /** * @see org.springframework.aop.framework.adapter.AdvisorAdapter#supportsAdvice(java.lang.Object) */ public boolean supportsAdvice(Advice advice) { // 匹配 MethodBeforeAdvice return advice instanceof MethodBeforeAdvice; } /** * @see org.springframework.aop.framework.adapter.AdvisorAdapter#getInterceptor(org.springframework.aop.Advisor) */ public Interceptor getInterceptor(Advisor advisor) { MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice(); // 返回 MethodBeforeAdviceInterceptor return new MethodBeforeAdviceInterceptor(advice) ; } }
通过 AdvisorAdapter
很巧妙的将 Advice 和 Interceptor 结合起来,同时也会发现二者关系是一一对应的
下面在看下方法的真正调用过程, 由 ReflectiveMethodInvocation
的方法 proceed
实现:
public Object proceed() throws Throwable { // We start with an index of -1 and increment early // 当执行到最后一个拦截器的时候将会调用目标方法 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; if (dm.methodMatcher.matches(this.method, this.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); } }
下面具体看下 MethodInterceptor
的实现,分别是前置通知,返回通知,异常通知
public Object invoke(MethodInvocation mi) throws Throwable { // 目标方法前执行 advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); return mi.proceed(); } public Object invoke(MethodInvocation mi) throws Throwable { // 先执行目标方法 Object retval = mi.proceed(); // 后置处理 advice.afterReturning(retval, mi.getMethod(), mi.getArguments(), mi.getThis() ); return retval; } public Object invoke(MethodInvocation mi) throws Throwable { try { // 执行目标方法 return mi.proceed(); } catch (Throwable t) { // 异常处理 Method handlerMethod = getExceptionHandler(t); if (handlerMethod != null) { invokeHandlerMethod(mi, t, handlerMethod); } throw t; } }
至此 Spring AOP 代理对象的执行过程处理结束,其流程可大概总结如下:
获取当前目标方法的 interceptor chain
Spring AOP 中的对象关系小结下:
当我们自定义 Advice 时,可不可以同时支持多种 Advice 呢 ? 譬如:
public class UserAdvice implements MethodBeforeAdvice, AfterReturningAdvice { public void before(Method m, Object[] args, Object target) throws Throwable { System.out.println("do before advice ...."); } public void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable { System.out.println("do after returning ...."); } }
那么当测试后,您会发现只有 before 调用了,而 afterReturning 未调用了;这是为什么呢 ? (好好看源码额)