详解SpringAOP源码

一. AOP是啥

在这里插入图片描述
AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

二. AOP的核心概念

  1. 横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点
  2. 切面(aspect):类是对物体特征的抽象,切面就是对横切关注点的抽象
  3. 连接点(joinpoint):被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器
  4. 切点(pointcut):对连接点进行拦截的定义,确定在哪些连接点处应用通知
  5. 通知(advice):所谓通知指的就是指拦截到连接点之后要执行的代,通知分为前置、后置、异常、最终、环绕通知五类;也可以解释为定义在连接点处的行为,围绕方法调用而进行注入
  6. 通知器(advisor): 组合advice和pointcut
  7. 目标对象:代理的目标对象
  8. 织入(weave):将切面应用到目标对象并导致代理对象创建的过程
  9. 引入(introduction):在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段

三. JDK动态代理举例

/**
 * Subject 接口
 */
public interface Subject {
    public Integer request(Integer param);
}
/**
 * Subject实现
 */
public class RealSubject implements Subject{

    @Override
    public Integer request(Integer param) {
        System.out.println("real Subject........ -> " + param);
        return param + 1;
    }

}
/**
 * Subject代理
 */
public class DynamicSubject implements InvocationHandler {

    private Object sub;

    public DynamicSubject(Object sub) {
        this.sub = sub;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("proxy before...." + method.toString());
        Object invoke = method.invoke(sub, args);
        System.out.println("proxy after...." + method.toString());
        return invoke;
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * JDK动态代理测试
 */
public class Test {

    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();

        InvocationHandler handler = new DynamicSubject(realSubject);

        Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler);

        System.out.println(subject.getClass());

        Integer request = subject.request(10);

        System.out.println(request);
    }

}

四. CGLIB代理举例

public class Person {

    public Integer request(Integer param){
        return param + 1;
    }

}
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * cjlib代理
 */
public class CjlibProxy implements MethodInterceptor {

    private Enhancer enhancer = new Enhancer();

    public Object getProxy(Class<?> clazz){
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        Object obj = enhancer.create();
        return obj;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理执行前:" + o.getClass().getName() + "----" + method.getName());

        Object result = methodProxy.invokeSuper(o, objects);

        System.out.println("代理执行结束......");

        return result;
    }

    public static void main(String[] args) {
        CjlibProxy cjlibProxy = new CjlibProxy();
        Person person = (Person) cjlibProxy.getProxy(Person.class);
        System.out.println(person.getClass().getName());
        System.out.println(person.getClass().getSuperclass().getName());
        Integer request = person.request(10);
        System.out.println(request);
    }

}

五. 通过一个AOP例子来分析

maven依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.8</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.6.9</version>
</dependency>

接口:

public interface FruitsService {

    String getName(String namePrefix);

}

实现类:

import com.jingchuan.service.FruitsService;

public class FruitsServiceImpl implements FruitsService {


    @Override
    public String getName(String namePrefix) {
        System.out.println("----->想要获取一个" + namePrefix + "的香蕉");
        return namePrefix + "-香蕉";
    }
}

通知类:

import org.aspectj.lang.ProceedingJoinPoint;

/**
 *
 */
public class MyAdvice {

    /**
     * 前置通知
     */
    public void before() {
        System.out.println("这是前置通知!!");
    }

    /**
     * 后置通知
     */
    public void afterReturning() {
        System.out.println("这是后置通知(如果出现异常不会调用)!!");
    }

    /**
     * 环绕通知
     * @param pjp
     * @return
     * @throws Throwable
     */
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("这是环绕通知之前的部分!!");
        //调用目标方法
        Object proceed = pjp.proceed();
        System.out.println("这是环绕通知之后的部分!!");
        return proceed;
    }

    /**
     * 异常通知
     * @param e
     */
    public void afterException(Exception e) {
        System.out.println("出事啦!出现异常了!!");
    }

    /**
     * 后置通知
     */
    public void after() {
        System.out.println("这是后置通知(出现异常也会调用)!!");
    }
}

测试入口类:

import com.jingchuan.service.FruitsService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAop {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationAop.xml");
        FruitsService fruitsService = (FruitsService) context.getBean("fruitsService");
        System.out.println(fruitsService.getName("红色的"));
    }

}

XML配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">


    <bean id="fruitsService" class="com.jingchuan.service.impl.FruitsServiceImpl"/>

    <bean id="myAdvice" class="com.jingchuan.service.MyAdvice" />
    <aop:config>
        <aop:aspect id="aspect" ref="myAdvice">
            <aop:pointcut id="customizePoint" expression="execution(* com.jingchuan.service.*.get*(..))"/>

            <aop:before method="before"  pointcut-ref="customizePoint"/>
            <aop:after method="after"  pointcut-ref="customizePoint"/>
            <aop:around method="around"  pointcut-ref="customizePoint"/>
            <aop:after-returning method="afterReturning"  pointcut-ref="customizePoint"/>
            <aop:after-throwing method="afterException" throwing="e" pointcut-ref="customizePoint"/>

        </aop:aspect>
    </aop:config>
</beans>

六. 通过源码分析Spring的AOP

温馨提示,在看下面的分析时,请尽量先看完这篇IOC源码分析,要了解AOP必须先了解IOC哈。如果已经了解IOC的可以忽略,接下来开始基于上面的AOP例子进行分析,建议在查看本篇文章时自己也根据上面的例子断点一步一步跟着走
了解IOC的都知道Spring可以说是把所有的东西都加载成Bean对象了,那么在我们上面的AOP配置文件中:<aop:config><aop:aspect><aop:pointcut><aop:before><aop:after><aop:around><aop:after-returning><aop:after-throwing>这些标签其实在spring中也会被解析成一个个的BeanDefinition,关于spring如何加载xml中配置的对象成为容器中的一个个BeanDefinition这里就不细说了,之前的IOC源码分析里面已经讲了。

6.1 aop标签的解析注册

org.springframework.context.support.AbstractApplicationContext#refresh中的obtainFreshBeanFactory()方法是初始化BeanDefinition定义的入口,在这一步中就是解析xml文件解析成BeanDefinition把BeanDefinition定义注册到容器中。
这里我们直接来到切入点:

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
	if (delegate.isDefaultNamespace(root)) {
		// 获取根节点(root)的子节点
		NodeList nl = root.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (node instanceof Element) {
				Element ele = (Element) node;
				if (delegate.isDefaultNamespace(ele)) {
					//这里是解析默认的bean标签的  之前ioc的那篇文章就是从这里进入分析的
					parseDefaultElement(ele, delegate);
				}
				else {
					// 本篇aop解析加载的入口就在这里  解析自定义标签元素
					// 比如上面我们的aop的xml配置中<aop:config>这个标签,就会来到这里进行解析
					delegate.parseCustomElement(ele);
				}
			}
		}
	}
	else {
		delegate.parseCustomElement(root);
	}
}

其实springAOP的配置加载就是从delegate.parseCustomElement(ele)这里和普通的bean分开的,网上大多数的资料都是直接从bean实例化后开始创建代理讲,很多都没有将前面的AOP标签定义初始化 和 aop和ioc是怎么结合在一起的,本篇就把这个结合点和代理讲清楚
进入delegate.parseCustomElement(ele)跟进,我们会看到这里:

public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
	String namespaceUri = getNamespaceURI(ele);
	if (namespaceUri == null) {
		return null;
	}
	//这里是根据aop:config标签获取到一个AopNamespaceHandler
	NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
	if (handler == null) {
		error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
		return null;
	}
	return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

这里主要是通过传入的Element 元素获取到对应的xml标签解析器,对于我们本篇的<aop:config>来说就是获取到了AopNamespaceHandler这个处理器,能获取到这个AopNamespaceHandler的原因就是在springaop源码的META_INF包下面的spring.handlers中配置了aop的标签名称解析就是org.springframework.aop.config.AopNamespaceHandler
然后调用handler.parse方法进行解析,跟进代码会来到:org.springframework.beans.factory.xml.NamespaceHandlerSupport#parse

public BeanDefinition parse(Element element, ParserContext parserContext) {
	BeanDefinitionParser parser = findParserForElement(element, parserContext);
	return (parser != null ? parser.parse(element, parserContext) : null);
}

这个方法里面首先根据element找到一个BeanDefinitionParser ,这个其实就是ConfigBeanDefinitionParser,为什么会是这个呢?因为AopNamespaceHandler中定义了config标签的解析器就是ConfigBeanDefinitionParser,这里就是根据标签找到对应的解析器。
然后继续跟进到ConfigBeanDefinitionParserparse方法中:

public BeanDefinition parse(Element element, ParserContext parserContext) {
	CompositeComponentDefinition compositeDef =
			new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
	parserContext.pushContainingComponent(compositeDef);

	configureAutoProxyCreator(parserContext, element);

	List<Element> childElts = DomUtils.getChildElements(element);
	for (Element elt: childElts) {
		String localName = parserContext.getDelegate().getLocalName(elt);
		if (POINTCUT.equals(localName)) {
			parsePointcut(elt, parserContext);
		}
		else if (ADVISOR.equals(localName)) {
			parseAdvisor(elt, parserContext);
		}
		else if (ASPECT.equals(localName)) {
			parseAspect(elt, parserContext);
		}
	}

	parserContext.popAndRegisterContainingComponent();
	return null;
}

在这段源码中,我们先来看跟进去看configureAutoProxyCreator(parserContext, element);

public static void registerAspectJAutoProxyCreatorIfNecessary(
			ParserContext parserContext, Element sourceElement) {
	//下面这行里面的parserContext.getRegistry()其实就是spring容器DefaultListableBeanFactory
	BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
			parserContext.getRegistry(), parserContext.extractSource(sourceElement));
	useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
	registerComponentIfNecessary(beanDefinition, parserContext);
}

先进入AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary看:

public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {
	// 记住这个类AspectJAwareAdvisorAutoProxyCreator 非常重要
	return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}

再继续跟进去:

private static BeanDefinition registerOrEscalateApcAsRequired(
			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

	if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
		BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
		if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
			int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
			int requiredPriority = findPriorityForClass(cls);
			if (currentPriority < requiredPriority) {
				apcDefinition.setBeanClassName(cls.getName());
			}
		}
		return null;
	}

	RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
	beanDefinition.setSource(source);
	beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
	beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	//把AspectJAwareAdvisorAutoProxyCreator包装成一个BeanDefinition并注册到Spring
	registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
	return beanDefinition;
}

从这段代码中我们可以看到,这其实就是通过上面传进来的Spring容器AspectJAwareAdvisorAutoProxyCreator.class,创建了一个BeanDefinition并注册了,这个就是AOP加载并转换成BeanDefinition的一个点,到这里我们要记住一个点,spring在处理AOP标签的时候,定义了一个AspectJAwareAdvisorAutoProxyCreator类的BeanDefinition,他被注册到Bean定义Map中的key是:org.springframework.aop.config.internalAutoProxyCreator,这个点很重要!!!
然后回到org.springframework.aop.config.ConfigBeanDefinitionParser#parse这个方法里面继续往下看:

public BeanDefinition parse(Element element, ParserContext parserContext) {
	CompositeComponentDefinition compositeDef =
			new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
	parserContext.pushContainingComponent(compositeDef);
	// 通过上面的分析我们得知了这一步主要是注册了一个AspectJAwareAdvisorAutoProxyCreator类的BeanDefinition
	configureAutoProxyCreator(parserContext, element);
	//拿到<aop:config>标签下面的子标签 <aop:config>标签下一级有多少个子标签这个list就有多少个
	//所以根据我们上面的例子中的配置,这个list就一个元素也就是<aop:aspect>元素的Element
	List<Element> childElts = DomUtils.getChildElements(element);
	for (Element elt: childElts) {
		String localName = parserContext.getDelegate().getLocalName(elt);
		if (POINTCUT.equals(localName)) {
			parsePointcut(elt, parserContext);
		}
		else if (ADVISOR.equals(localName)) {
			parseAdvisor(elt, parserContext);
		}
		else if (ASPECT.equals(localName)) {
			// 在我们上面的例子就会走到解析Aspect标签这里 因为我们的配置中<aop:config>下就是一个<aop:aspect>
			parseAspect(elt, parserContext);
		}
	}

	parserContext.popAndRegisterContainingComponent();
	return null;
}

大家这里看看代码中的注释就能理解了,我们进入parseAspect(elt, parserContext)看:

private void parseAspect(Element aspectElement, ParserContext parserContext) {
	String aspectId = aspectElement.getAttribute(ID);
	String aspectName = aspectElement.getAttribute(REF);

	try {
		this.parseState.push(new AspectEntry(aspectId, aspectName));
		List<BeanDefinition> beanDefinitions = new ArrayList<>();
		List<BeanReference> beanReferences = new ArrayList<>();
		// 探查<aop:aspect>节点下面有没有declare-parents 这个是用来给添加新方法的,这里不做详细介绍了
		List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
		for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
			Element declareParentsElement = declareParents.get(i);
			beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
		}

		// We have to parse "advice" and all the advice kinds in one loop, to get the
		// ordering semantics right.
		// 拿到<aop:aspect>节点下面的子节点
		NodeList nodeList = aspectElement.getChildNodes();
		boolean adviceFoundAlready = false;
		for (int i = 0; i < nodeList.getLength(); i++) {
			Node node = nodeList.item(i);
			//循环判断每个子节点是不是before、after、after-returning、after-throwing、around中的某一个
			if (isAdviceNode(node, parserContext)) {
				if (!adviceFoundAlready) {
					adviceFoundAlready = true;
					if (!StringUtils.hasText(aspectName)) {
						parserContext.getReaderContext().error(
								"<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
								aspectElement, this.parseState.snapshot());
						return;
					}
					beanReferences.add(new RuntimeBeanReference(aspectName));
				}
				// 循环中把每个子节点都解析成一个BeanDefinition,实际上是创建Pointcut的Advisor
				AbstractBeanDefinition advisorDefinition = parseAdvice(
						aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
				beanDefinitions.add(advisorDefinition);
			}
		}

		AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
				aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
		//创建AspectComponentDefinition 并加入队列
		parserContext.pushContainingComponent(aspectComponentDefinition);
		// 经过上面的循环把增强的点都注册之后,这里获取到<aop:pointcut> 标签元素,然后进行注册
		List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
		// 从aop:aspect标签中找到pointcut标签后循环
		for (Element pointcutElement : pointcuts) {
			// 解析pointcut标签   这里注册的pointcut是prototype类型的  不是单例singleton的
			parsePointcut(pointcutElement, parserContext);
		}

		parserContext.popAndRegisterContainingComponent();
	}
	finally {
		this.parseState.pop();
	}
}

上面这段源码中,我们先跟进去看:AbstractBeanDefinition advisorDefinition = parseAdvice( aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences)这一行:

private AbstractBeanDefinition parseAdvice(
			String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
			List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

	try {
		this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));

		// create the method factory bean
		// 创建一个MethodLocatingFactoryBean的BeanDefinition,用来调用增强的点
		RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
		methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
		methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
		methodDefinition.setSynthetic(true);

		// create instance factory definition
		// 创建一个SimpleBeanFactoryAwareAspectInstanceFactory的BeanDefinition,用来表示增强点所在的类和他的工厂
		RootBeanDefinition aspectFactoryDef =
				new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
		aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
		aspectFactoryDef.setSynthetic(true);

		// register the pointcut
		// 经过上面创建的方法和类的定义,这里把这两个拿着去注册切入点
		// 其实就是根据已经创建好的切入点(类和方法),然后去创建注册真正的切入点
		// 这里创建的其实是before、after、after-returning、after-throwing、around每一个对应的BeanDefinition
		// 这个每一个BeanDefinition的构造函数有三个参数分别是:MethodLocatingFactoryBean、自定义的切入点方法对应的RuntimeBeanReference、SimpleBeanFactoryAwareAspectInstanceFactory
		AbstractBeanDefinition adviceDef = createAdviceDefinition(
				adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
				beanDefinitions, beanReferences);

		// configure the advisor
		// 创建一个advisor的定义
		// 把上面创建的adviceDef加进构造方法
		RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
		advisorDefinition.setSource(parserContext.extractSource(adviceElement));
		advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
		if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
			advisorDefinition.getPropertyValues().add(
					ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
		}

		// register the final advisor
		// 把创建的advisor注册到容器中
		parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);

		return advisorDefinition;
	}
	finally {
		this.parseState.pop();
	}
}

上面这一段代码其实就是在循环中创建beforeafterafter-returningafter-throwingaround对应的AspectJPointcutAdvisor并进行注册。每一个AspectJPointcutAdvisor都有一个三个参数的构造器,三个参数分别是:MethodLocatingFactoryBean、自定义的切入点方法对应的RuntimeBeanReferenceSimpleBeanFactoryAwareAspectInstanceFactory,目的就是为了方便后面进行反射调用。这五个标签在工厂中被注册时,他们的key分别就是:

  1. org.springframework.aop.aspectj.AspectJPointcutAdvisor#0
  2. org.springframework.aop.aspectj.AspectJPointcutAdvisor#1
  3. org.springframework.aop.aspectj.AspectJPointcutAdvisor#2
  4. org.springframework.aop.aspectj.AspectJPointcutAdvisor#3
  5. org.springframework.aop.aspectj.AspectJPointcutAdvisor#4
    这个名字的由来大家可以自行查看org.springframework.beans.factory.xml.XmlReaderContext#registerWithGeneratedNamegenerateBeanName(beanDefinition)查看,内容不复杂并且与本篇不太相干,所以略过

然后我们回到org.springframework.aop.config.ConfigBeanDefinitionParser#parseAspect中看这一行:parsePointcut(pointcutElement, parserContext);当代码走到这里,说明循环已经创建完了beforeafterafter-returningafter-throwingaround中的每一个都有一个对应的AspectJPointcutAdvisor并进行了注册,然后就到了我们例子中剩下的一个标签<aop:pointcut>,这里就是从<aop:aspect>中找到pointcut标签并创建了一个AspectJExpressionPointcutBeanDefinition进行注册,这个AspectJExpressionPointcutBeanDefinition他的scopeprototype(非singleton单例)的,为什么这个是prototype呢?因为pointcut是一个表达式,他可以包括多个Bean,每个Bean创建代理都是一个切入点,所以他需要是prototype的。其实上面循环中处理的都是增强的点bean注册,这个pointcut就是我们需要被增强的方法的一个bean注册(其中包含了重要信息:expression="execution(* com.jingchuan.service.*.get*(..))"

至此,AOP标签的解析就完成了,几个重要的点是:

  • 定义了一个AspectJAwareAdvisorAutoProxyCreator类的BeanDefinition,记住AspectJAwareAdvisorAutoProxyCreator其实是一个BeanPostProcessor
  • beforeafterafter-returningafter-throwingaround对应的AspectJPointcutAdvisor形成了他们的构造方法并注册到Bean工厂,这些事被切入点的增强,便于后面调用时使用
  • 定义了被增强点的<aop:pointcut>AspectJExpressionPointcut并注册到Bean工厂,其中记录了被切入的点

接下来分析AspectJAwareAdvisorAutoProxyCreator这个BeanPostProcessor怎么被使用的

6.2 AspectJAwareAdvisorAutoProxyCreator这个BeanPostProcessor在注册后怎么被使用的

通过上面6.1的分析,我们已经知道了在spring加载AOP标签的时候,会往Bean工厂注册一个AspectJAwareAdvisorAutoProxyCreatorBeanDefinition,那么通过查看这个AspectJAwareAdvisorAutoProxyCreator源码我们发现他其实是实现了BeanPostProcessor的。

知道了这个以后,我们再回到org.springframework.context.support.AbstractApplicationContext#refresh方法里面看registerBeanPostProcessors(beanFactory)。点进去看:

public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

	// WARNING: Although it may appear that the body of this method can be easily
	// refactored to avoid the use of multiple loops and multiple lists, the use
	// of multiple lists and multiple passes over the names of processors is
	// intentional. We must ensure that we honor the contracts for PriorityOrdered
	// and Ordered processors. Specifically, we must NOT cause processors to be
	// instantiated (via getBean() invocations) or registered in the ApplicationContext
	// in the wrong order.
	//
	// Before submitting a pull request (PR) to change this method, please review the
	// list of all declined PRs involving changes to PostProcessorRegistrationDelegate
	// to ensure that your proposal does not result in a breaking change:
	// https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22
	// 查找已经注册到工厂中的BeanPostProcessor  
	String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

	// Register BeanPostProcessorChecker that logs an info message when
	// a bean is created during BeanPostProcessor instantiation, i.e. when
	// a bean is not eligible for getting processed by all BeanPostProcessors.
	// 这里主要是记录BeanPostProcessor实例化是的一些信息  与本篇关系不大 直接忽略
	int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
	beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

	// Separate between BeanPostProcessors that implement PriorityOrdered,
	// Ordered, and the rest.
	// 下面这里是把PostProcessors进行分组
	List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
	List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
	List<String> orderedPostProcessorNames = new ArrayList<>();
	List<String> nonOrderedPostProcessorNames = new ArrayList<>();
	for (String ppName : postProcessorNames) {
		if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			priorityOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
			// 我们例子中的internalAutoProxyCreator就会进入这里
			orderedPostProcessorNames.add(ppName);
		}
		else {
			nonOrderedPostProcessorNames.add(ppName);
		}
	}

	// First, register the BeanPostProcessors that implement PriorityOrdered.
	// 对priorityOrderedPostProcessors排序注册,对于我们的例子来说这个是空的
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

	// Next, register the BeanPostProcessors that implement Ordered.
	List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
	for (String ppName : orderedPostProcessorNames) {
		// 然后这里就是从bean工厂获取之前定义的AspectJAwareAdvisorAutoProxyCreator实例 
		// 这里就不跟进去细看了 再看又得一套IOC
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		orderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	sortPostProcessors(orderedPostProcessors, beanFactory);
	// 然后把这个实例注册到BeanPostProcessors 其实就是添加到list里面存这,实例化之后做后置处理
	registerBeanPostProcessors(beanFactory, orderedPostProcessors);

	// Now, register all regular BeanPostProcessors.
	List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
	for (String ppName : nonOrderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		nonOrderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

	// Finally, re-register all internal BeanPostProcessors.
	sortPostProcessors(internalPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, internalPostProcessors);

	// Re-register post-processor for detecting inner beans as ApplicationListeners,
	// moving it to the end of the processor chain (for picking up proxies etc).
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

在这段代码中我们可以看到首先是用BeanPostProcessor.class去工厂中查找,根据我们上面的例子中,这里查到的结果就是:org.springframework.aop.config.internalAutoProxyCreator,其实就是我们一直在说的AspectJAwareAdvisorAutoProxyCreator
然后在后续代码中,可以看到通过BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);获取到了对应的实例,这里就是之前IOC讲的根据BeanDefinition获取实例的内容,就不细说了。然后再registerBeanPostProcessors(beanFactory, orderedPostProcessors);添加到了org.springframework.beans.factory.support.AbstractBeanFactory#beanPostProcessors

然后我们继续看bean实例化之后如何通过这个AspectJAwareAdvisorAutoProxyCreator来处理代理增强。

6.3 实例化bean时通过后置BeanPostProcessor处理代理增强

从6.1和6.2两个小节,我们知道了所有的xml定义的Bean对被定义好了,其中AspectJAwareAdvisorAutoProxyCreator已经完成了实例化并加入了beanPostProcessors,接下来我们看例子中的fruitsService被实例化的过程,了解IOC的应该都知道是从org.springframework.context.support.AbstractApplicationContext#refreshfinishBeanFactoryInitialization(beanFactory)开始实例化所有的bean对象。
关于这个fruitsService实例化我就不再一步一步跟着分析了,之前的IOC源码分析已经讲过了,大家也可以拿着上面这个例子断点跟一下,这里我们直接跳到fruitsService初始化的org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition),这个方法中有一行wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

	Object result = existingBean;
	for (BeanPostProcessor processor : getBeanPostProcessors()) {
		Object current = processor.postProcessAfterInitialization(result, beanName);
		if (current == null) {
			return result;
		}
		result = current;
	}
	return result;
}

在这个方法中,可以看到是一个for循环,循环的就是:org.springframework.beans.factory.support.AbstractBeanFactory#beanPostProcessors,这个就是6.2小节中把AspectJAwareAdvisorAutoProxyCreator添加到了里面。所以这里这个循环到之后就会进入:org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

这个方法中我们重点看:wrapIfNecessary(bean, beanName, cacheKey)

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
		return bean;
	}
	if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
		return bean;
	}
	if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

	// Create proxy if we have advice.
	// 获取bean实例的增强点的实例
	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(bean.getClass(), beanName, null);这个方法会走到org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean,然后继续跟进org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
	//找到所有的增强点
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
	//对这些增强点进行过滤
	List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
	// 无实现的protected方法,留给扩展使用的
	extendAdvisors(eligibleAdvisors);
	if (!eligibleAdvisors.isEmpty()) {
		eligibleAdvisors = sortAdvisors(eligibleAdvisors);
	}
	// 返回bean对应的所有增强点Advisor
	return eligibleAdvisors;
}

这个方法我们重点看:findCandidateAdvisors()

public List<Advisor> findAdvisorBeans() {
	// Determine list of advisor bean names, if not cached already.
	String[] advisorNames = this.cachedAdvisorBeanNames;
	if (advisorNames == null) {
		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the auto-proxy creator apply to them!
		// 这里实际就会拿到增强点的所有Bean定义的key 就是6.1小节中aop下面的before、after...那么对应的BeanDefinition
		advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
				this.beanFactory, Advisor.class, true, false);
		this.cachedAdvisorBeanNames = advisorNames;
	}
	if (advisorNames.length == 0) {
		return new ArrayList<>();
	}

	List<Advisor> advisors = new ArrayList<>();
	//循环所有的增强点
	for (String name : advisorNames) {
		if (isEligibleBean(name)) {
			if (this.beanFactory.isCurrentlyInCreation(name)) {
				if (logger.isTraceEnabled()) {
					logger.trace("Skipping currently created advisor '" + name + "'");
				}
			}
			else {
				try {
					// 通过工厂的getBean方法加载每个增强点的实例
					advisors.add(this.beanFactory.getBean(name, Advisor.class));
				}
				catch (BeanCreationException ex) {
					Throwable rootCause = ex.getMostSpecificCause();
					if (rootCause instanceof BeanCurrentlyInCreationException) {
						BeanCreationException bce = (BeanCreationException) rootCause;
						String bceBeanName = bce.getBeanName();
						if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
							if (logger.isTraceEnabled()) {
								logger.trace("Skipping advisor '" + name +
										"' with dependency on currently created bean: " + ex.getMessage());
							}
							// Ignore: indicates a reference back to the bean we're trying to advise.
							// We want to find advisors other than the currently created bean itself.
							continue;
						}
					}
					throw ex;
				}
			}
		}
	}
	return advisors;
}

在这个方法中BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);这行实际就是拿到6.1中AOP标签下的beforeafterafter-returningafter-throwingaround这几个标签对应的BeanDefinition,由之前的分析可以知道他们在bean工厂中定义的name分别为:

  1. org.springframework.aop.aspectj.AspectJPointcutAdvisor#0
  2. org.springframework.aop.aspectj.AspectJPointcutAdvisor#1
  3. org.springframework.aop.aspectj.AspectJPointcutAdvisor#2
  4. org.springframework.aop.aspectj.AspectJPointcutAdvisor#3
  5. org.springframework.aop.aspectj.AspectJPointcutAdvisor#4

然后通过advisorNames的循环,依次去BeanFactory里面通过getBean()加载对应的实例,这里的加载也是IOC的一套流程,就不跟进了,当循环结束后,也就获取到了当前这个Bean(在我们例子中就是fruitsService)的所有增强点的实例。
然后就把找到并加载的所有advisors返回到了:org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary。我们再贴一下这个代码:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
		return bean;
	}
	if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
		return bean;
	}
	if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

	// Create proxy if we have advice.
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
	// 获取到bean实例的增强点的实例
	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;
}

如果bean上面有需要增强的地方,那么就开始创建单例对象,所以我们跟进到createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));看代码:

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

	if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
		AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
	}

	ProxyFactory proxyFactory = new ProxyFactory();
	proxyFactory.copyFrom(this);

	if (!proxyFactory.isProxyTargetClass()) {
		if (shouldProxyTargetClass(beanClass, beanName)) {
			proxyFactory.setProxyTargetClass(true);
		}
		else {
			evaluateProxyInterfaces(beanClass, proxyFactory);
		}
	}

	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
	proxyFactory.addAdvisors(advisors);
	proxyFactory.setTargetSource(targetSource);
	customizeProxyFactory(proxyFactory);

	proxyFactory.setFrozen(this.freezeProxy);
	if (advisorsPreFiltered()) {
		proxyFactory.setPreFiltered(true);
	}

	// Use original ClassLoader if bean class not locally loaded in overriding class loader
	ClassLoader classLoader = getProxyClassLoader();
	if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
		classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
	}
	return proxyFactory.getProxy(classLoader);
}

在这个方法中,首先创建了一个ProxyFactory代理工厂,再通过buildAdvisors(beanName, specificInterceptors)包装一个Advisor[] advisors设置到代理工厂中,然后调用扩展点customizeProxyFactory(proxyFactory),设置ClassLoader,最后使用代理工厂创建代理类,所以我们直接跟进到到:proxyFactory.getProxy(classLoader)

public Object getProxy(@Nullable ClassLoader classLoader) {
	return createAopProxy().getProxy(classLoader);
}

可以看到这里是先获取代理工厂,再创建代理类,那么我们跟进看创建代理工厂,代码会跟进到:

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	if (!NativeDetector.inNativeImage() &&
			(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);
	}
}

看到这里相信稍微了解SpringAOP的就知道了,Sping创建代理有两种方式:

  1. Jdk动态代理
  2. Cglib动态代理
    这两个文章开头已经说过了,这里就不在详述了,对于我们的例子中fruitsService是个接口,所以肯定就是用Jdk动态代理了。然后返回到org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)方法看getProxy(classLoader),经过前面分析我们知道这里使用的是Jdk动态代理,所以就来到:
public Object getProxy(@Nullable ClassLoader classLoader) {
	if (logger.isTraceEnabled()) {
		logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
	}
	return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}

然后就可以看到文章第三章里面的举例了,这里就不在详述怎么创建代理类了。创建完成后就把代理对象返回,然后我们回到:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)方法的wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
经过这个BeanPostProcessors的后置处理,我们把一个fruitsService的实例变成了他的代理对象并返回最终加到了Spring容器中,这个Bean的实例话就算完成了。

至此!SpringAOP的大体流程就算分析完成了,非常长的一篇
不过大家根据这个例子看完之后,要总结出来spring在处理AOP代理的大体流程:

  1. 加载AOP的各种标签成为一个个的BeanDefinition,并注册到Spring的Bean工厂中,同时注册了一个AspectJAwareAdvisorAutoProxyCreatorBeanPostProcessors
  2. 然后在registerBeanPostProcessors(beanFactory);里面把上一步的AspectJAwareAdvisorAutoProxyCreator实例化并加入beanPostProcessors
  3. 在实例化需要代理的对象时,根据第二步添加的beanPostProcessors创建代理对象并添加到Spring容器

完事!
个人浅薄理解,欢迎指正

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值