Spring AOP的实现原理之获取增强器Adivors

来源:互联网 发布:怎么开淘宝网点 编辑:程序博客网 时间:2024/06/05 11:02

在讲解<aop>自定义标签时,提到了AspectJAwareAdvisorAutoProxyCreator的注册,对于AOP的实现基本就靠这个类实现。

AspectJAwareAdvisorAutoProxyCreator的层次结构如图所示,该类实现了BeanPostProcessor与SmartInstantiationAwareBeanPostProcessor这两个接口

ApplicationContext实现的默认行为就是会将所有的单例bean提前进行实例化,即会调用getBean(name),跟踪代码到AbstractAutowireCapableBeanFactory中createBean

此时 resolveBeforeInstantiation(beanName, mbd)就是给实现了SmartInstantiationAwareBeanPostProcessor接口的类的机会去改变bean

AbstractAutowireCapableBeanFactoryprotected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args){......try {// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.Object bean = resolveBeforeInstantiation(beanName, mbd);if (bean != null) {return bean;}}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"BeanPostProcessor before instantiation of bean failed", ex);}Object beanInstance = doCreateBean(beanName, mbd, args);if (logger.isDebugEnabled()) {logger.debug("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {Object bean = null;if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// Make sure bean class is actually resolved at this point.if (mbd.hasBeanClass() && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(), beanName);if (bean != null) {bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);}}mbd.beforeInstantiationResolved = (bean != null);}return bean;}
如最上面的类层次结构图,此时会调用AbstractAutoProxyCreator中的postProcessBeforeInstantiation以及postProcessAfterInstantiation方法
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName)throws BeansException {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);if (result != null) {return result;}}}return null;}
注意shouldSkip(beanClass, beanName),该方法其实已经找到所有的标有@AspectJ类中的增加方法
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {Object cacheKey = getCacheKey(beanClass, beanName);if (beanName == null || !this.targetSourcedBeans.containsKey(beanName)) {if (this.advisedBeans.containsKey(cacheKey)) {return null;}if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return null;}}// Create proxy here if we have a custom TargetSource.// Suppresses unnecessary default instantiation of the target bean:// The TargetSource will handle target instances in a custom fashion.if (beanName != null) {TargetSource targetSource = getCustomTargetSource(beanClass, beanName);if (targetSource != null) {this.targetSourcedBeans.put(beanName, Boolean.TRUE);Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}}return null;}public boolean postProcessAfterInstantiation(Object bean, String beanName) {return true;}

AspectJAwareAdvisorAutoProxyCreator@Overrideprotected boolean shouldSkip(Class beanClass, String beanName) {// TODO: Consider optimization by caching the list of the aspect namesList<Advisor> candidateAdvisors = findCandidateAdvisors();for (Advisor advisor : candidateAdvisors) {if (advisor instanceof AspectJPointcutAdvisor) {if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {return true;}}}return super.shouldSkip(beanClass, beanName);}

findCadidateAdvisors()即是寻找所有的增加方法,即标有@Before,@After,@AfterReturning,@Around等注解的方法,一个增强方法对应Advisor.

下面来看看findCadidateAdvisors()的逻辑

@Overrideprotected List<Advisor> findCandidateAdvisors() {// 这个是寻找xml配置文件的advisorsList<Advisor> advisors = super.findCandidateAdvisors();// 寻找标有注解的advisors,advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());return advisors;}

如上所示,spring把寻找标有注解的advisor委托给了BeanFactoryAspectJAdvisorsBuilder

public List<Advisor> buildAspectJAdvisors() {List<String> aspectNames = null;synchronized (this) {aspectNames = this.aspectBeanNames;if (aspectNames == null) {....//获取所有注册的beanNameString[] beanNames =BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);for (String beanName : beanNames) {....//判断beanType是否存在AspectJ注解if (this.advisorFactory.isAspect(beanType)) {aspectNames.add(beanName);//AspectMetadata代表标有@AspectJ的类AspectMetadata amd = new AspectMetadata(beanType, beanName);if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {....//获取标记AspectJ注解中的增强方法List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);....}....}this.aspectBeanNames = aspectNames;return advisors;}}....}

重点在this.advisorFactory.getAdvisors(factory)

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass();final String aspectName = maaif.getAspectMetadata().getAspectName();...final List<Advisor> advisors = new LinkedList<Advisor>();//getAdvisorMethods()寻找增强方法,即标有注解的方法不过排出了@Poincut//并且是有序的集合,顺序分别是Around, Before, After, AfterReturning, AfterThrowing//这也是5种通知在AOP中的拦截顺序for (Method method : getAdvisorMethods(aspectClass)) {//全部以InstantiationModelAwarePointcutAdvisorImpl返回Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);if (advisor != null) {advisors.add(advisor);}}...return advisors;}

回到文章最开始,AspectJAwareAdvisorAutoProxyCreator实现了BeanPostProcessor接口,那么这个接口的方法在哪儿实现呢?答案在AbstractAutowireCapableBeanFactory类的initializeBean方法中,该方法调用applyBeanPostProcessorsAfterInitialization方法,即是BeanPostProcessor接口方法的调用之处

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {......Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {//BeanPostProcessor接口postProcessBeforeInitialization实现wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {//initMethod方法invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {//BeanPostProcessor接口postProcessAfterInitialization实现wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}


AspectJAwareAdvisorAutoProxyCreator看看是如何实现postProcessAfterInitialization方法的
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);if (!this.earlyProxyReferences.containsKey(cacheKey)) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;}
接下来看看wrapIfNecessary方法,该方法就是创建代理的地方了,匹配切点表达式的增强器就是getAdvicesAndAdvisorsForBean这个方法得来的

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {...// Create proxy if we have advice.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;}
跟踪getAdvicesAndAdvisorsForBean方法

protected List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {//该句代码在上面已做了分析List<Advisor> candidateAdvisors = findCandidateAdvisors();//在candidateAdvisors中寻找匹配目标类的增加器List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);extendAdvisors(eligibleAdvisors);if (!eligibleAdvisors.isEmpty()) {eligibleAdvisors = sortAdvisors(eligibleAdvisors);}return eligibleAdvisors;}
跟踪findAdvisorsThatCanApply方法,其逻辑委托给了AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {if (candidateAdvisors.isEmpty()) {return candidateAdvisors;}...boolean hasIntroductions = !eligibleAdvisors.isEmpty();for (Advisor candidate : candidateAdvisors) {...if (canApply(candidate, clazz, hasIntroductions)) {eligibleAdvisors.add(candidate);}}return eligibleAdvisors;}

当前循环的增强器是否匹配目标类是由canApply()方法判断的。放在编码阶段,就是目标类是否满足切点表达式,比如:execution(* com.uestc.test.aop.*.*(..)),即com.uestc.test.aop包下类的任何方法都应进行增强。

跟踪canApply方法,可以看到是通过MethodMatcher.match()方法来匹配的

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {Assert.notNull(pc, "Pointcut must not be null");if (!pc.getClassFilter().matches(targetClass)) {return false;}MethodMatcher methodMatcher = pc.getMethodMatcher();IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;if (methodMatcher instanceof IntroductionAwareMethodMatcher) {introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;}Set<Class> classes = new HashSet<Class>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));classes.add(targetClass);for (Class<?> clazz : classes) {Method[] methods = clazz.getMethods();for (Method method : methods) {if ((introductionAwareMethodMatcher != null &&introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||methodMatcher.matches(method, targetClass)) {return true;}}}return false;}

其匹配过程大致是通过提取切入点表达式,根据切入点表达式来判断是否匹配,但是前面分析寻找增强方法时对于标有@Poincut注解的方法排除了,也没有看到切点表达式的提取。

我们来看看getClassFilter()

public ClassFilter getClassFilter() {checkReadyToMatch();return this;}
对,切入点表达式的提取就在checkReadyToMacth()方法中

private void checkReadyToMatch() {if (getExpression() == null) {throw new IllegalStateException("Must set property 'expression' before attempting to match");}if (this.pointcutExpression == null) {this.pointcutExpression = buildPointcutExpression();}}
buildPointCutExpression()即是提取切入点表达式,返回的类型是PointcutExpressionImpl,简单描述spring的做法就是通过反射来提取,但是spring的做法远比这复杂的多,这里暂不做分析。

由此,我们就找到了匹配目标类的增强器。








0 0
原创粉丝点击