众所周知,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