众所周知,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<Object> { //多余部分删除了 private String name; private int age; public TestBean() { } public TestBean(String name) { this.name = name; } @Override public String getName() { return name; } @Override public void setName(String name) { this.name = name; } @Override public int getAge() { return age; } @Override public void setAge(int age) { this.age = age; } /** * @see org.springframework.beans.testfixture.beans.ITestBean#exceptional(Throwable) */ @Override public void exceptional(Throwable t) throws Throwable { if (t != null) { throw t; } } @Override public void unreliableFileOperation() throws IOException { throw new IOException(); } /** * @see org.springframework.beans.testfixture.beans.ITestBean#returnsThis() */ @Override public Object returnsThis() { return this; } /** * @see org.springframework.beans.testfixture.beans.IOther#absquatulate() */ @Override public void absquatulate() { } @Override public int haveBirthday() { return age++; } @Override public boolean equals(Object other) { if (this == other) { return true; } if (other == null || !(other instanceof TestBean)) { return false; } TestBean tb2 = (TestBean) other; return (ObjectUtils.nullSafeEquals(this.name, tb2.name) && this.age == tb2.age); } @Override public int hashCode() { return this.age; } @Override public int compareTo(Object other) { if (this.name != null && other instanceof TestBean) { return this.name.compareTo(((TestBean) other).getName()); } else { return 1; } } @Override public String toString() { return this.name; } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd"> <beans> <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/> <bean id="aspect" class="org.springframework.aop.aspectj.autoproxy.AdviceUsingThisJoinPoint"/> <bean id="adrian" class="org.springframework.beans.testfixture.beans.TestBean" scope="prototype"> <property name="name" value="adrian"/> <property name="age" value="34"/> </bean> </beans>
@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<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { List<Advisor> candidateAdvisors = findCandidateAdvisors();//获取候选Advisor List<Advisor> 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<Advisor> buildAspectJAdvisors() { List<String> aspectNames = this.aspectBeanNames; if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames;//并发问题 if (aspectNames == null) { List<Advisor> 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<Advisor> 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<Advisor> advisors = new ArrayList<>(); for (String aspectName : aspectNames) { List<Advisor> 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<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } List<Advisor> 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<Class<?>> 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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。