共计 9148 个字符,预计需要花费 23 分钟才能阅读完成。
家喻户晓,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