上文中提到了 AOP 建立代理等等的具体操做都是在 AnnotationAwareAspectAutoProxyCreator 类中来成的,经过上文的自动注册,下面让咱们看 AnnotationAwareAspectAutoProxyCreator 是如何工做的,首先是 AnnotationAwareAspectAutoProxyCreator 的继承关系图:
java
而后是 AnnotationAwareAspectAutoProxyCreator 的层次结构图:
web
这里须要特别注意的是 BeanPostProcessor 接口,咱们知道实际运用中,若是你须要对项目中的 Bean 进行代理,在 Spring 的 xml 的配置一个 BeanPostProcessor 就行。由此,咱们能够知道 AnnotationAwareAspectAutoProxyCreator 实现代理也是经过 BeanPostProcessor 接口来完成的,因此咱们对于 AOP 逻辑分析也是由 BeanPostProcessor 实例化前的 postProcessAfterInitialization 方法开始,而 AnnotationAwareAspectAutoProxyCreator 的 postProcessAfterInitialization 具体实现是在其父类 AbstractAutoProxyCreator 中完成的。咱们对 AOP 逻辑的分析也由此开始。
正则表达式
AbstractAutoProxyCreator.javaexpress
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { // 根据给定的 bean 的 class 和 name 构建出个 key,格式:beanClassName_beanName Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { // 若是它适合被代理,则须要封装指定 bean。 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // 是否已经处理过 if (beanName != null && this.targetSourcedBeans.contains(beanName)) { return bean; } // 无需加强 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } // 给定的 bean 类是否表明一个基础设施类,基础设施类不该代理,或者配置了指定 bean 不须要自动代理 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // 若是存在加强方法则建立代理 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); // 若是获取到了加强则须要针对加强建立代理 if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // 建立代理 Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
以上两个方法构成了建立代理的雏形,固然,开始前还有些判断工做。而建立代理的核心逻辑部分是在 AbstractAutoProxyCreator 类中完成的,而建立代理前的准备工做主要分为两步:(1)获取加强方法或者加强器。(2)根据获取的加强进行代理。下面是 AbstractAutoProxyCreator 的时序图:数组
结合时序图,咱们知道真正建立代理地方是从 getAdvicesAndAdvisorsForBean 开始的。虽然看起来很简单,但其实每一步都有大量复杂的逻辑。但在分析源码前,咱们必须先对加强以及其具体逻辑有所了解。app
Advice(也翻做 通知)定义了链接点作什么,为切面加强提供了织入的接口。在 Spring AOP 中,它主要描述 Spring AOP 围绕方法调用而注入的切面行为。Advice 是 AOP 联盟定义的一个接口,具体的接口定义在 org.aopalliance.aop.Advice 中。在 Spring AOP 的实现中,使用了这个统一接口,并经过这个接口,为 AOP 切面加强的注入功能作了更多的细化和扩展,好比前面提到的具体通知类型,如BeforeAdvice、AfterAdvice、ThrowsAdvice等。做为 Spring AOP 定义的接口类,具体的切面加强能够经过这些接口集成到 AOP 框架中去发挥做用。对于这些接口类,下面是他的主要接口继承图:
框架
下面是 Advice 接口继承的层次图:
ide
看一个程序的具体设计思路没有比看接口来的更直接的了,下面咱们就从第一个 BeforeAdvice 的继承接口 MethodBeforeAdvice 开始(BeforeAdvice 里没有任何东西)函数
MthodInterceptor.java源码分析
public interface MethodInterceptor extends Interceptor { void before(Method method, Object[] args, Object target) throws Throwable; }
明显可以看出这是一个回调函数,他的具体参数有:Method 对象,这个参数是目标方法的反射对象,Object[]对象数组,这个对象数组中包含没办法发的输入参数。而咱们根据继承关系看他的具体实现类 AspectJMethodBeforeAdvice。
AspectJMethodBeforeAdvice.java
@Override public void before(Method method, Object[] args, Object target) throws Throwable { invokeAdviceMethod(getJoinPointMatch(), null, null); }
AbstractAspectJAdvice.java
protected Object invokeAdviceMethod(JoinPointMatch jpMatch, Object returnValue, Throwable ex) throws Throwable { return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex)); } protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable { Object[] actualArgs = args; if (this.aspectJAdviceMethod.getParameterTypes().length == 0) { actualArgs = null; } try { ReflectionUtils.makeAccessible(this.aspectJAdviceMethod); // 激活加强 return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs); } catch (IllegalArgumentException ex) { throw new AopInvocationException("Mismatch on arguments to advice method [" + this.aspectJAdviceMethod + "]; pointcut expression [" + this.pointcut.getPointcutExpression() + "]", ex); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } }
invokeAdviceMethodWithGivenArgs 方法中的 aspectJAdviceMethod 正是对于前置加强的方法,在这里实行了调用。下面是 AfterAdvice 的继承接口 AfterReturningAdvice 接口:
AfterReturningAdvice.java
public interface AfterReturningAdvice extends AfterAdvice { void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable; }
而 AfterReturningAdvice 接口的核心逻辑是在其实现父类 AspectJAfterReturningAdvice 中完成的。
AspectJAfterReturningAdvice.java
@Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { if (shouldInvokeOnReturnValueOf(method, returnValue)) { invokeAdviceMethod(getJoinPointMatch(), returnValue, null); } }
后面的和 BeforeAdvice 同样。根据分析咱们能够知道 BeforeAdvice 和 AfterAdvice。尽管,这两个加强行为一致,旦由于它实现的 AOP 通知不一样,因此就被 AOP 编织到不一样的调用场合中了。而其余的加强基本思路都是如此,这里就不展开了。
Pointcut(关注点,也称 切点)用于决定 Advice 加强做用于哪一个链接点,也就是说经过 Pointcut 来定义须要加强的方法集合,而这些集合的选取能够经过必定的规则来完成,例如:这些须要加强的地方能够由某个正则表达式来进行标识,或根据某个方法名来进行匹配等。下面是 Pointcut 的层次结构图:
下面是 Pointcut 接口:
Pointcut.java
public interface Pointcut { ClassFilter getClassFilter(); MethodMatcher getMethodMatcher(); Pointcut TRUE = TruePointcut.INSTANCE; }
经过 Pointcut 接口的基本定义咱们能够看到,须要返回一个 MethodMatcher。对于 Point 的匹配判断功能,具体是由这个返回的 MethodMatcher 来完成的,也就是说,有这个 MethodMatcher 来判断是否须要对当前方法调用进行加强或者配置应用。我接着对 MethodMatcher 接口进行分析:
MethodMatcher.java
public interface MethodMatcher { boolean matches(Method method, Class<?> targetClass); boolean isRuntime(); boolean matches(Method method, Class<?> targetClass, Object[] args); MethodMatcher TRUE = TrueMethodMatcher.INSTANCE; }
经过阅读注释咱们知道了 Pointcut 的核心逻辑是在 matches 方法中完成的,我就以经过方法名匹配的 NameMatchMetchMethodPointcut 类的 matches 方法来讲明:
NameMatchMetchMethodPointcut.java
@Override public boolean matches(Method method, Class<?> targetClass) { for (String mappedName : this.mappedNames) { if (mappedName.equals(method.getName()) || isMatch(method.getName(), mappedName)) { return true; } } return false; }
从源码咱们看到他的实现是很是简单的,匹配条件就是方法名相同或者方法名匹配。
Advisor(通知器)用一个对象将对目标方法的切面加强设计(Advice)和关注点的设计(Pointcut)结合起来。下面是 Advisor 接口的层次继承图:
这是一个 Advisor 接口的设计,咱们从中能够看出经过 Advisor,能够定义应该使用哪一个加强而且在哪一个关注点使用它,也就是经过 Advisor,把 Advice 和 Pointcut 结合起来,这个结合为使用 IOC 容器配置 AOP应用,提供了便利。下面是 Advisor 接口:
Advisor.java
public interface Advisor { Advice getAdvice(); boolean isPerInstance(); }
下面咱们以一个 Advisor 的实现(DefaultPointcutAdvisor)为例,进而了解 Advisor 的工做原理。
DefaultPointcutAdvisor.java
public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable { private Pointcut pointcut = Pointcut.TRUE; public DefaultPointcutAdvisor() { } public DefaultPointcutAdvisor(Advice advice) { this(Pointcut.TRUE, advice); } public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) { this.pointcut = pointcut; setAdvice(advice); } public void setPointcut(Pointcut pointcut) { this.pointcut = (pointcut != null ? pointcut : Pointcut.TRUE); } @Override public Pointcut getPointcut() { return this.pointcut; } @Override public String toString() { return getClass().getName() + ": pointcut [" + getPointcut() + "]; advice [" + getAdvice() + "]"; } }
这个类主要职责是 Pointcut 的设置或者获取,在 DefaultPointcutAdvisor 中,Pointcut 默认被设置为 Pointcut.True,这个 Pointcut.True 接口被定义为 Pointcut True = TruePointcut.INSTANCE。而关于 Advice 部分的设置与获取是由其父类 AbstractGenericPointcutAdvisor 来完成的。
下面就让咱们回到源码分析,前面已经提到了通知器,这里就不冗述了,他的主要做用是用来整合切面加强设计(Advice)和切入点设计(Pointcut)。而对于指定 bean 的加强方法的获取,通常包含获取全部加强以及寻找全部加强中适合于 bean 的加强并应用这两个步骤。
AnnotationAwareAspectAutoProxyCreator.java
@Override protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) { List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); } protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { List<Advisor> candidateAdvisors = findCandidateAdvisors(); List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }
从源码看,这两个步骤必定是由 findCandidateAdvisors 和 findAdvisorsThatCanApply 来完成。还有值得注意的是,若是没法找到对应的通知器便会返回 DO_NOT_PROXY(null)。
——水门(2016年3月于杭州)