众所周知,Aop各种切面肯定是通过创建代理(Aop的各种基本概念各位听都应该听会了,这里就不多赘述了)。但是问题随之产生了,我们已经分析了普通bean的解析及创建,aop是在哪边创建代理对象的呢,怎么匹配切点的呢。这篇也是围绕这两个问题进行分析。动态代理的分析上一篇已经分析完了,感兴趣的可以看一下。传送门
本篇研究的问题
- 代理对象的创建
匹配切点
测试代码
@Aspect class AdviceUsingThisJoinPoint { private String lastEntry = ""; public String getLastMethodEntered() { return this.lastEntry; } @Pointcut("execution(int *.getAge())") public void methodExecution() { } @Before("methodExecution()") public void entryTrace(JoinPoint jp) { this.lastEntry = jp.toString(); System.out.println(this.lastEntry); } }
public class TestBean implements BeanNameAware, BeanFactoryAware, ITestBean, IOther, Comparable
@Test public void testAdviceUsingJoinPoint() { ClassPathXmlApplicationContext bf = newContext("usesJoinPointAspect.xml"); ITestBean adrian1 = (ITestBean) bf.getBean("adrian"); adrian1.getAge(); adrian1.getDoctor(); AdviceUsingThisJoinPoint aspectInstance = (AdviceUsingThisJoinPoint) bf.getBean("aspect"); assertThat(aspectInstance.getLastMethodEntered().indexOf("TestBean.getAge())") != 0).isTrue(); }
源码分析
创建代理对象的入口为
AbstractAutoProxyCreator#postProcessBeforeInstantiation
,可以看出核心方法为getAdvicesAndAdvisorsForBean
,后面就是创建代理对象了@Override public Object postProcessBeforeInstantiation(Class> beanClass, String beanName) { Object cacheKey = getCacheKey(beanClass, beanName); if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(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. TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) { if (StringUtils.hasLength(beanName)) { this.targetSourcedBeans.add(beanName); } Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } return null; }
此方法是获取对应的Advisor
protected List
findEligibleAdvisors(Class> beanClass, String beanName) { List candidateAdvisors = findCandidateAdvisors();//获取候选Advisor List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);//获取适用于bean的Advisor: 例如Pointcut匹配 extendAdvisors(eligibleAdvisors);//特殊处理 if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors);//排序 } return eligibleAdvisors; } findCandidateAdvisors
最终会调用buildAspectJAdvisors
获取对应的Advisor
,
第一次进入会找到@Aspect
定义过的方法,生成对应的Advisor
(封装了Advice),后续就会从缓存中取public List
buildAspectJAdvisors() { List aspectNames = this.aspectBeanNames; if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames;//并发问题 if (aspectNames == null) { List advisors = new ArrayList<>(); aspectNames = new ArrayList<>(); String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(// this.beanFactory, Object.class, true, false); for (String beanName : beanNames) { if (!isEligibleBean(beanName)) { continue; } // We must be careful not to instantiate beans eagerly as in this case they // would be cached by the Spring container but would not have been weaved. Class> beanType = this.beanFactory.getType(beanName, false); if (beanType == null) { continue; } if (this.advisorFactory.isAspect(beanType)) {//是否为@Aspect修饰的bean aspectNames.add(beanName); AspectMetadata amd = new AspectMetadata(beanType, beanName); if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); List classAdvisors = this.advisorFactory.getAdvisors(factory);//生成Adivsor if (this.beanFactory.isSingleton(beanName)) { this.advisorsCache.put(beanName, classAdvisors); } else { this.aspectFactoryCache.put(beanName, factory); } advisors.addAll(classAdvisors); } else { // Per target or per this. if (this.beanFactory.isSingleton(beanName)) { throw new IllegalArgumentException("Bean with name '" + beanName + "' is a singleton, but aspect instantiation model is not singleton"); } MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName); this.aspectFactoryCache.put(beanName, factory); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } } this.aspectBeanNames = aspectNames; return advisors; } } } if (aspectNames.isEmpty()) { return Collections.emptyList(); } List advisors = new ArrayList<>(); for (String aspectName : aspectNames) { List cachedAdvisors = this.advisorsCache.get(aspectName); if (cachedAdvisors != null) { advisors.addAll(cachedAdvisors); } else { MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } return advisors; } 上面获取到了所有的Advisor集合接下来就是获取到匹配的Advisor
public static List
findAdvisorsThatCanApply(List candidateAdvisors, Class> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } List eligibleAdvisors = new ArrayList<>(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) {//遍历Advisor找到匹配的 if (candidate instanceof IntroductionAdvisor) { // already processed continue; } if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; } 具体匹配是在
org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class>, boolean)
方法中判断,先判断类是否匹配再判断方法是否匹配public static boolean canApply(Pointcut pc, Class> targetClass, boolean hasIntroductions) { Assert.notNull(pc, "Pointcut must not be null"); if (!pc.getClassFilter().matches(targetClass)) {//匹配class return false; } MethodMatcher methodMatcher = pc.getMethodMatcher(); if (methodMatcher == MethodMatcher.TRUE) { // No need to iterate the methods if we're matching any method anyway... return true; } IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; } Set
> classes = new LinkedHashSet<>(); if (!Proxy.isProxyClass(targetClass)) { classes.add(ClassUtils.getUserClass(targetClass)); } classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); for (Class> clazz : classes) { Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz); for (Method method : methods) { if (introductionAwareMethodMatcher != null ? introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) : methodMatcher.matches(method, targetClass)) { return true; } } } return false; } 后面就会创建代理对象,根据有无接口为主要条件判断是JDK代理还是Cglib动态代理,这两个上篇已经讲过了,这里就不过多赘述了
@Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { 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); } }
总结
先扫描所有
@Aspect
注解的对象,封装成Advisor
对象,缓存起来,创建对象的时候循环判断是否匹配。
随便说两句
至此SpringIoC和Aop的部分已经全部分析完了。
前面几篇也来个传送门
「Spring-IoC」源码分析一获取bean信息
「Spring-IoC」源码分析二依赖注入&依赖循环
「Spring-Aop」源码分析三:JDK动态代理&Cglib