一. AOP是啥
AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
二. AOP的核心概念
- 横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点
- 切面(aspect):类是对物体特征的抽象,切面就是对横切关注点的抽象
- 连接点(joinpoint):被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器
- 切点(pointcut):对连接点进行拦截的定义,确定在哪些连接点处应用通知
- 通知(advice):所谓通知指的就是指拦截到连接点之后要执行的代,通知分为前置、后置、异常、最终、环绕通知五类;也可以解释为定义在连接点处的行为,围绕方法调用而进行注入
- 通知器(advisor): 组合advice和pointcut
- 目标对象:代理的目标对象
- 织入(weave):将切面应用到目标对象并导致代理对象创建的过程
- 引入(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
,这里就是根据标签找到对应的解析器。
然后继续跟进到ConfigBeanDefinitionParser
的parse
方法中:
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();
}
}
上面这一段代码其实就是在循环中创建before
、after
、after-returning
、after-throwing
、around
对应的AspectJPointcutAdvisor
并进行注册。每一个AspectJPointcutAdvisor
都有一个三个参数的构造器,三个参数分别是:MethodLocatingFactoryBean
、自定义的切入点方法对应的RuntimeBeanReference
、SimpleBeanFactoryAwareAspectInstanceFactory
,目的就是为了方便后面进行反射调用。这五个标签在工厂中被注册时,他们的key分别就是:
- org.springframework.aop.aspectj.AspectJPointcutAdvisor#0
- org.springframework.aop.aspectj.AspectJPointcutAdvisor#1
- org.springframework.aop.aspectj.AspectJPointcutAdvisor#2
- org.springframework.aop.aspectj.AspectJPointcutAdvisor#3
- org.springframework.aop.aspectj.AspectJPointcutAdvisor#4
这个名字的由来大家可以自行查看org.springframework.beans.factory.xml.XmlReaderContext#registerWithGeneratedName
的generateBeanName(beanDefinition)
查看,内容不复杂并且与本篇不太相干,所以略过
然后我们回到org.springframework.aop.config.ConfigBeanDefinitionParser#parseAspect
中看这一行:parsePointcut(pointcutElement, parserContext);
当代码走到这里,说明循环已经创建完了before
、after
、after-returning
、after-throwing
、around
中的每一个都有一个对应的AspectJPointcutAdvisor
并进行了注册,然后就到了我们例子中剩下的一个标签<aop:pointcut>
,这里就是从<aop:aspect>
中找到pointcut标签并创建了一个AspectJExpressionPointcut
的BeanDefinition进行注册,这个AspectJExpressionPointcut
的BeanDefinition他的scope
是prototype
(非singleton
单例)的,为什么这个是prototype
呢?因为pointcut是一个表达式,他可以包括多个Bean,每个Bean创建代理都是一个切入点,所以他需要是prototype
的。其实上面循环中处理的都是增强的点bean注册,这个pointcut就是我们需要被增强的方法的一个bean注册(其中包含了重要信息:expression="execution(* com.jingchuan.service.*.get*(..))"
)
至此,AOP标签的解析就完成了,几个重要的点是:
- 定义了一个
AspectJAwareAdvisorAutoProxyCreator
类的BeanDefinition
,记住AspectJAwareAdvisorAutoProxyCreator
其实是一个BeanPostProcessor
- 把
before
、after
、after-returning
、after-throwing
、around
对应的AspectJPointcutAdvisor
形成了他们的构造方法并注册到Bean工厂,这些事被切入点的增强,便于后面调用时使用 - 定义了被增强点的
<aop:pointcut>
的AspectJExpressionPointcut
并注册到Bean工厂,其中记录了被切入的点
接下来分析AspectJAwareAdvisorAutoProxyCreator
这个BeanPostProcessor
怎么被使用的
6.2 AspectJAwareAdvisorAutoProxyCreator这个BeanPostProcessor在注册后怎么被使用的
通过上面6.1的分析,我们已经知道了在spring加载AOP标签的时候,会往Bean工厂注册一个AspectJAwareAdvisorAutoProxyCreator
的BeanDefinition
,那么通过查看这个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#refresh
的finishBeanFactoryInitialization(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标签下的before
、after
、after-returning
、after-throwing
、around
这几个标签对应的BeanDefinition,由之前的分析可以知道他们在bean工厂中定义的name分别为:
- org.springframework.aop.aspectj.AspectJPointcutAdvisor#0
- org.springframework.aop.aspectj.AspectJPointcutAdvisor#1
- org.springframework.aop.aspectj.AspectJPointcutAdvisor#2
- org.springframework.aop.aspectj.AspectJPointcutAdvisor#3
- 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创建代理有两种方式:
- Jdk动态代理
- 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代理的大体流程:
- 加载AOP的各种标签成为一个个的BeanDefinition,并注册到Spring的Bean工厂中,同时注册了一个
AspectJAwareAdvisorAutoProxyCreator
的BeanPostProcessors
- 然后在registerBeanPostProcessors(beanFactory);里面把上一步的
AspectJAwareAdvisorAutoProxyCreator
实例化并加入beanPostProcessors
- 在实例化需要代理的对象时,根据第二步添加的
beanPostProcessors
创建代理对象并添加到Spring容器
完事!
个人浅薄理解,欢迎指正