Spring源码-SpringAOP实现原理

SpringAOP实现原理

Spring的切面编程,从织入方式上来看,存在三种织入方式:编译期织入、类加载期织入和运行期织入.aspectJ有两种织入方式:CTW(Compile Time Weaving)编译时织入和LTW(Load Time Weaving)加载时织入,Spring Aop是在运行期通过代理技术动态扩展被增强类(JDK动态代理和cglib动态代理)

通过动态代理在方法运行过程中动态的添加功能,可以更好的降低模块的耦合度、易扩展,在 Spring IOC 容器中在 getBean 时返回的是代理类的实例,是Spring 采用 JDK Proxy 或 CGLIB 动态生成的

开启Aop功能的三种方式:xml配置< aop-config>aop功能,< aspectj-autoproxy>aop注解方式,SpringBoot通过@EnableAspectJAutoProxy注解开启aop,其实本质都是依赖aop包提供的AOP解析器进行处理

Aop解析器

在loadBeanDefinition中parseCustomElement解析非默认标签和自定义namespace会从资源路径下META-INF/spring.handlers找到对应的schema,在aop包中会默认加载AopNamespaceHandler

http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

根据xml标签注册了以下几个解析器,最后调用解析器parse方法解析配置项

public void init() {
    //xml配置pointcut,advisor元素
    this.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
    this.registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
    this.registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
    this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}

ConfigBeanDefinitionParser

对应的是xml配置中aop-config的配置解析器

<!-- 定义增强器的内容(方法) -->
<bean id="transaction" class="com.test.springtest.aop.TransactionDemo"/>
<!--配置AOP proxy-target-class采用代理模式,默认为false也就是JDK代理通过接口进行代理,设置为true时使用cglib代理通过继承目标类实现代理-->
<!--expose-proxy暴露代理用于AopContext.currentProxy()获取当前代理,用于例如在A对象x方法中调用另外一个类的y方法时,y方法不会被切面增强,这时可以配置expose-proxy为true并将this.y()改为获取代理的实例去((A)AopContext.currentProxy()).y(),即可让y方法被切面增强-->
<aop:config proxy-target-class="true" expose-proxy="true">
    <!-- 全局的pointcut -->
    <aop:pointcut id="mycut" expression="execution(* com.pingan.mytest.test..*.*(..))"/>
    <aop:aspect ref="transaction">
        <!--切入点: 匹配service及其子包下的所有类,类中所有方法,不论参数-->
        <aop:pointcut id="demoPointcut" expression="execution(* com.pingan.test.springtest.aop.service..*.*(..))"/>
        <!--目标方法执行前会先执行transaction中的testBefore-->
        <aop:before method="testBefore" pointcut-ref="demoPointcut"/>
        <!--方法执行后-->
        <aop:after method="testAfter" pointcut-ref="demoPointcut"/>
        <!--方法执行环绕-->
        <aop:around method="testAround" pointcut-ref="demoPointcut"/>
        <!--后置返回-->
        <aop:after-returning method="testAfterAround" pointcut-ref="demoPointcut"/>
        <!--异常-->
        <aop:after-throwing method="testEx" pointcut-ref="demoPointcut" throwing="ex"/>
    </aop:aspect>
    <!--和aspect功能一样,advise-ref必须依赖一个Advice接口的实现-->
    <aop:advisor advice-ref="testAdvice" pointcut-ref="mycut"/>
</aop:config>

对应的advise增强方法

//自定义一个切面
public class TransactionDemo {
    //在被切入方法执行前触发,顺序为1
    public void testBefore(){
        System.out.println("方法执行前");
    }
    //最终触发
    public void testAfter(){
        System.out.println("方法执行完");
    }
    //环绕增强:前置+目标方法执行+后置通知
    //ProceedingJoinPoint继承JoinPoint
    public void around(ProceedingJoinPoint point) throws Throwable {
        //如果有前置增强,则顺序为2
        System.out.println("方法环绕前");
        //proceed方法用于启动目标方法执行,顺序为3
        point.proceed();
        //顺序5
        System.out.println("方法环绕后");
    }
    //后置返回增强:当目标方法执行返回之后,顺序为4
    public void testafterAround(){
        System.out.println("方法返回值通知");
    }
    //抛出异常后执行方法,before-环绕前-目标方法-异常通知-after
    public void testThrowAround(Exception ex){
        System.out.println(ex.getMessage());
    }
}

element节点就是aop-config

public BeanDefinition parse(Element element, ParserContext parserContext) {
    //首先会注册一个AspectJAwareAdvisorAutoProxyCreator,处理<aop:config>节点,解析proxy-target-class和expose-proxy的属性值
    //AspectJAwareAdvisorAutoProxyCreator也AbstractAutoProxyCreator的实现
    this.configureAutoProxyCreator(parserContext, element);
    //获取<aop:config>节点的子元素
    List<Element> childElts = DomUtils.getChildElements(element);
    Iterator var5 = childElts.iterator();
    while(var5.hasNext()) {
        Element elt = (Element)var5.next();
        //包括全局的pointcut(aspect子元素也有pointcut),aspect和advisor
        String localName = parserContext.getDelegate().getLocalName(elt);
        if ("pointcut".equals(localName)) {
            this.parsePointcut(elt, parserContext);
        } else if ("advisor".equals(localName)) {
            this.parseAdvisor(elt, parserContext);
        } else if ("aspect".equals(localName)) {
            this.parseAspect(elt, parserContext);
        }
    }...
}

AspectJAutoProxyBeanDefinitionParser

在xml配置中开启注解模式

<!--开启切面注解解析器-->
//对应<aop:config proxy-target-class="true" expose-proxy="true">
<aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true"/>


//标签aspectj-autoproxy对应注册的解析器就是AspectJAutoProxyBeanDefinitionParser
//主要作用是注册一个AnnotationAwareAspectJAutoProxyCreator
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());

//@Aspect对应xml配置中开启一个切面:<aop:aspect ref="transaction">
@Aspect
@Component("transaction")
public class TransactionDemo {
    //配置切入点Pointcut:<aop:pointcut id="demoPointcut" expression="execution(xx)"/>
    @Pointcut("execution(* com.test.springtest.aop.service..*.*(..))")
    public void pointcut(){}
    //前置增强,引入切入点方法 <aop:before method="before" pointcut-ref="pointcut"/>
    @Before(value = "pointcut()")
    public void before(){
        System.out.println("方法执行前");
    }
    @After(value = "pointcut()")
    public void after(){
        System.out.println("方法执行完");
    }
    //ProceedingJoinPoint封装方法中参数
    @Around(value = "pointcut()")
    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("方法环绕前");
        point.proceed();
        System.out.println("方法环绕后");
    }
    @AfterReturning(value = "pointcut()")
    public void afterAround(){
        System.out.println("方法返回值通知");
    }
    //<aop:after-throwing method="throwAround" pointcut-ref="pointcut" throwing="ex"/>
    @AfterThrowing(value = "pointcut()",throwing = "ex")
    public void throwAround(Exception ex){
        System.out.println(ex.getMessage());
    }
}

@EnableAspectJAutoProxy注解开启aop功能本质上也是注册了AnnotationAwareAspectJAutoProxyCreator

//@import等同于给AspectJAutoProxyRegistrar加了一个@Component注解
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
    //对应<aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true"/>
    boolean proxyTargetClass() default false;
    boolean exposeProxy() default false;
}

//实现了ImportBeanDefinitionRegistrar
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    AspectJAutoProxyRegistrar() {
    }
    //在实例化bean时执行这个方法
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //注册AnnotationAwareAspectJAutoProxyCreator
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
        //获取@EnableAspectJAutoProxy注解
        AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        ...
    }
}

然后继续分析一下AnnotationAwareAspectJAutoProxyCreator

//继承的抽象类实现了SmartInstantiationAwareBeanPostProcessor和BeanFactoryAware两个接口
//SmartInstantiationAwareBeanPostProcessor是个InstantiationAwareBeanPostProcessor,实例化bean时会调用其postProcessAfterInitialization方法从而改变包装wrapBean的bean实现增强
//BeanFactoryAware则了解到封装了BeanFactory
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {}

ConfigBeanDefinitionParser中注册了AspectJAwareAdvisorAutoProxyCreator也是AbstractAutoProxyCreator的实现,所以aop的处理都在实例化bean的时候

Advisor增强器

对于advise和advisor其实本质上都类似interceptor,当访问了某个方式时进行拦截并对这个方法进行增强;切点pointcut表示在什么位置进行增强,而Aspect则可以理解为一个拦截器链

切入点Pointcut

AspectJ切入点,标注匹配的方法和类,表达式第一个*表示匹配所有方法的返回值,两个.表示0或多个子包,service包下包括子包的所有的类,及其所有的方法,匹配所有参数,(…)中表示任意参数

//主要是将解析的配置项封装为一个AspectJExpressionPointcut
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
    //获取标签的两个属性值
    String id = pointcutElement.getAttribute("id");
    String expression = pointcutElement.getAttribute("expression");
    /*创建AspectJExpressionPointcut
    	beanDefinition.setBeanClass(AspectJExpressionPointcut.class);
    	beanDefinition.setScope("prototype");
        beanDefinition.setSynthetic(true);
        beanDefinition.getPropertyValues().add("expression", expression);
    */
    AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
    String pointcutBeanName = id;
    //beanDefinitionMap.put(beanName, beanDefinition);beanName就是id
    parserContext.getRegistry().registerBeanDefinition(id, pointcutDefinition);
    return pointcutDefinition;
}

切入点匹配方式:

**execution:**使用"execution(方法表达式)"匹配方法执行;

主要两种方式:

1.根据全限定名去匹配切点的目标方法

2.根据注解去匹配目标方法

<!--切入点: 匹配service及其子包下的所有类,类中所有方法,不论参数-->
<aop:pointcut id="demoPointcut" expression="execution(* com.test.aop.service..*.*(..))"/>

<!--切入点:任何持有@com.pingan.test.springtest.aop.AnnoAspect注解的方法-->
<aop:pointcut id="demoPointcut" expression="execution(@com.test.aop.AnnoAspect * *(..))"/>

注解示例

@Aspect
@Component
public class AspectTest {
  //方法的入参用于value值,returnValue表示方法返回值
  @AfterReturning(value = "@annotation(testAnno)",returning = "returnValue")
  public String processTest(TestAnno testAnno,Object returnValue) {
    String result = (String) returnValue;
    System.out.println(result);
    return result;
  }
}

**within:*使用"within(类型表达式)“或者”@within(注解类型)"匹配持有指定注解类型内的方法,注意没有

<!--注解要贴在实现类上面,类所有的方法都会被织入-->
<aop:pointcut id="demoPointcut" expression="within(@com.test.aop.AnnoAspect *)"/>
<!--@within和上面是一样的作用,区别在于@的位置和最后的*在@within方式不需要-->
<aop:pointcut id="demoPointcut" expression="@within(com.test.aop.AnnoAspect)"/>

**this:**使用"this(类型全限定名)"匹配类型全限定名,不支持通配符,this引用的是当前对象,不是代理对象

**target:**使用"target(类型全限定名)"匹配类型全限定名,不支持通配符,target引用的代理对象

目标对象(Target Object) :被一个或者多个切面所通知的对象。例如,AServcieImpl和BServiceImpl,当然在实际运行时,Spring AOP采用代理实现,实际AOP操作的是TargetObject的代理对象

<aop:pointcut id="demoPointcut" expression="this(com.test.aop.service.SuperService)"/>

**args:**使用"args(参数类型列表)"匹配当前执行的方法传入的参数为指定类型的执行方法;

<!--切入点:匹配传入的参数类型为String的方法-->
<aop:pointcut id="demoPointcut" expression="args(java.lang.String)"/>

public void args(String args){
    System.out.println("测试args语法切入点");
}

增强器链Aspect

可包含多个增强器

<!-- 增强(Advice):通知,在方法执行的什么时机(方法前/方法后/方法前后)做什么(增强的功能)-->
<aop:before method="before" pointcut-ref="demoPointcut"/>
<aop:after method="after" pointcut-ref="demoPointcut"/>

<!--aspect包括pointcut和advise-->
<aop:aspect ref="transaction">
    <!--pointcut-->
    <aop:pointcut id="demoPointcut" expression=""/>
    <!--advice-->
    <aop:before method="" pointcut-ref="demoPointcut"/>
</aop:aspect>

aspect标签包含的pointcut标签和advise标签

private void parseAspect(Element aspectElement, ParserContext parserContext) {
    //解析aspect标签的id和ref属性,ref引用的实例就是封装通知的方法,比如testAfter()
    String aspectId = aspectElement.getAttribute("id");
    String aspectName = aspectElement.getAttribute("ref");
	...
    //获取所有的子节点
    NodeList nodeList = aspectElement.getChildNodes();
    boolean adviceFoundAlready = false;
    for(int i = 0; i < nodeList.getLength(); ++i) {
        Node node = nodeList.item(i);
        //各种advise通知标签:before,after,around等
        if(this.isAdviceNode(node, parserContext)) {
            if(!adviceFoundAlready) {
                adviceFoundAlready = true;
                //封装为RuntimeBeanReference:主要的属性就是beanName表示对bean的引用
                //封装的beanName是ref引用的bean
                beanReferences.add(new RuntimeBeanReference(aspectName));
            }
			//解析advise节点并封装为AspectJPointcutAdvisor的bean
            AbstractBeanDefinition advisorDefinition = this.parseAdvice(aspectName, i, aspectElement, (Element)node, parserContext, beanDefinitions, beanReferences);
            beanDefinitions.add(advisorDefinition);
        }
    }
	
	//处理pointcut子节点
    List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, "pointcut");
    Iterator var21 = pointcuts.iterator();
    while(var21.hasNext()) {
        Element pointcutElement = (Element)var21.next();
        this.parsePointcut(pointcutElement, parserContext);
    }
}

解析advise增强器,主要包含method织入物和pointcut-ref/pointcut切点

private AbstractBeanDefinition parseAdvice(String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext, List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
	//从MethodLocatingFactoryBean通过getObject获取的是method实例
    //public Method getObject() throws Exception {return this.method;}
    RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
    //targetBeanName表示原始的bean,也就是ref标签引用的bean
    methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
    //method属性值引用的是bean的方法名methodName
    methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
    methodDefinition.setSynthetic(true);
    RootBeanDefinition aspectFactoryDef = new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
    aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
    aspectFactoryDef.setSynthetic(true);
    //createAdviceDefinition主要是返回advise封装的bean和解析pointcut
    /* 根据不同的advise封装为对应的bean
        "before" return AspectJMethodBeforeAdvice;
        "after" return AspectJAfterAdvice;
        "after-returning" return AspectJAfterReturningAdvice;
        "after-throwing" return AspectJAfterThrowingAdvice;
        "around" return AspectJAroundAdvice;
    */
    //beanDefinitions.add(pointcut);将pointcut解析封装的bean添加到beanDefinitions
    //将methodDefinition作为bean的构造器参数封装
    AbstractBeanDefinition adviceDef = this.createAdviceDefinition(adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef, beanDefinitions, beanReferences);
    //继续将AdviceDefinition封装到AspectJPointcutAdvisor
    RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
    advisorDefinition.setSource(parserContext.extractSource(adviceElement));
    //AdviceDefinition作为AspectJPointcutAdvisor构造器的参数封装
    advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
    if(aspectElement.hasAttribute("order")) {
        advisorDefinition.getPropertyValues().add("order", aspectElement.getAttribute("order"));
    }
	//注册advisorDefinition
    parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
    return advisorDefinition;
}

实例化Advisor

advisor和aspect区别在于,一个aspect对应多个advise,而每个advisor只处理一个advise

//advisor标签所有属性
<aop:advisor advice-ref="" pointcut="" pointcut-ref="" id="" order=""/>
//一个advisor只能处理一个advise
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.XXX..*.*Service.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.XXX..*.*Rest.*(..))" />

注册一个DefaultBeanFactoryPointcutAdvisor

private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
    // public DefaultBeanFactoryPointcutAdvisor() {this.pointcut = Pointcut.TRUE;}
    // 表示advisor依赖pointcut
     //解析的标签属性添加在PropertyValues中:advice-ref,order
    AbstractBeanDefinition advisorDef = this.createAdvisorBeanDefinition(advisorElement, parserContext);
    //获取id标签,和上面一样可以定义DefaultBeanFactoryPointcutAdvisor实例的beanName
    String id = advisorElement.getAttribute("id");
    String advisorBeanName = id;
    parserContext.getRegistry().registerBeanDefinition(id, advisorDef);
    //解析pointcut和pointcut-ref属性并返回有效的pointcut添加到PropertyValues属性中
    Object pointcut = this.parsePointcutProperty(advisorElement, parserContext);
    advisorDef.getPropertyValues().add("pointcut", pointcut);
}

实例化的工作在doCreateBean进行到initializeBean即将完成初始化时调用所有后置处理器,包括AbstractAutoProxyCreator的applyBeanPostProcessorsAfterInitialization方法对aop的实例进行处理

public Object postProcessAfterInitialization(Object bean, String beanName) {
    return wrapIfNecessary(bean, beanName, cacheKey);
}
//如果被增强则将返回代理实例
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // Create proxy if we have advice.
    //获取所有的advisor增强器(拦截器)
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   	//通过动态代理返回代理实例
    if (specificInterceptors != null) {
        Object proxy = createProxy(
            bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        return proxy;
    }
	//否则返回原bean
    return bean;
}

getAdvicesAndAdvisorsForBean方法获取用于实现aop的配置项,xml配置在解析阶段就将配置项封装为各个类型的beanDefinition,而注解模式只是注册了AspectJAwareAdvisorAutoProxyCreator,并没有对注解配置项进行解析

//getAdvicesAndAdvisorsForBean主要获取合格的advisors
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    //获取候选的advisor,也就是aspect解析之后的advisor实例
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    //开启aop之后每个bean初始化都会匹配适合自己的advisor,简单理解就是是否匹配pointCut的advisor
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

//AnnotationAwareAspectJAutoProxyCreator是注解配置项的代理生成器
protected List<Advisor> findCandidateAdvisors() {
    //获取xml配置项的advisor并进行实例化为Advisor:beanFactory.getBean(name, Advisor.class);
    List<Advisor> advisors = this.advisorRetrievalHelper.findAdvisorBeans();
    //将注解配置项bean实例化并添加到advisors
    advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    return advisors;
}

主要了解一下aspect注解项解析并实例化为Advisor

public List<Advisor> buildAspectJAdvisors() {
    //遍历所有的bean
    for (String beanName : beanNames) {
        //类实例
        Class<?> beanType = this.beanFactory.getType(beanName);
        //类实例是否包含@Aspect注解
        if (this.advisorFactory.isAspect(beanType)) {
            aspectNames.add(beanName);	
            //AspectInstanceFactory切面实例工厂
            MetadataAwareAspectInstanceFactory factory =
                new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
            //AspectJAdvisorFactory advisorFactory
            //初始化Advisor实例
            List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
            advisors.addAll(classAdvisors);
        }
    }
    this.aspectBeanNames = aspectNames;
    return advisors;
}

//获取advise注解的方法,比如@After等,除了@PointCut之外
/*Advice类型
    1.前置通知(Before advice):在连接点(JoinPoint)之前执行,但这个通知不能阻止连接点前的执行
    2.后置通知(After advice):当某连接点退出的时候执行的通知,抛出异常时,returnAfter方法仍然执行。
    3.返回后通知(After return advice):在某连接点正常完成后执行的通知,不包括抛出异常的情况。
    4.环绕通知(Around advice):环绕连接点增强,ProceedingJoinPoint的proceed()用于目标方法执行
    5.抛出异常后通知(After throwing advice):在方法抛出异常退出时执行,在配置时需要添加方法异常参数
    <aop:after-throwing method="throwAround" pointcut-ref="demoPointcut" throwing="ex"/>
*/
for (Method method : getAdvisorMethods(aspectClass)) {
   //解析advise注解的value值(表示切点),并将切点AspectJExpressionPointcut封装到advise中,和xml解析一样,再将advice封装到advisor中
   Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
   if (advisor != null) {
      advisors.add(advisor);
   }
}

每个bean初始化时都需要访问postProcessAfterInitialization方法,首先会判断是否是Aspect类(有@Aspect注解),如果是Aspect类则不是aspect类则返回原始的bean,再通过findAdvisorsThatCanApply判断当前bean是否匹配pointcut从而进行拦截增强

动态代理

被aop拦截的bean则开始创建代理类进行增强

//首先是createAopProxy()创建一个aopProxy
public Object getProxy(ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader);
}

//默认使用jdk动态代理
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   	//如果proxyTargetClass设置为true
    if (config.isProxyTargetClass()) {
        Class<?> targetClass = config.getTargetClass();
        //被代理的类是个接口还是使用jdk动态代理
        if (targetClass.isInterface()) {
            return new JdkDynamicAopProxy(config);
        }
        //否则使用的是cglib代理
        return new ObjenesisCglibAopProxy(config);
    }    
    return new JdkDynamicAopProxy(config);
}
JDK动态代理

代理的对象必须要实现接口,实际上也可以看作是代理类动态的实现了被代理对象的接口,JDK的Proxy类提供了一组静态方法来为一组接口动态地生成代理类及其对象:

//Proxy.newProxyInstance(类加载器,被代理的接口,代理处理器)
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler hanlder);

//实现InvocationHandler接口,创建增强代码的处理器
public Object invoke(Object proxy, Method method, Object[] args)    

类是单继承的,所以jdk动态代理在继承proxy之后无法再继承一个实现类,所以只能通过实现接口的方式

//代理类继承Proxy代理类,实现接口的实现类代理
public class $ServerProxy extends Proxy implements IServer {
    //实现InvocationHandler接口的invoke方法
    protected $ServerProxy(InvocationHandler h) {
        super(h);
    }
    //动态重写接口的方法
    @Override
    public void test() throws Throwable {
        //获取方法对象
        Method test = IServer.class.getMethod("test");
        //调用代理处理器,真正的被代理的实现类在处理器中处理
        h.invoke(this, test, null);
    }
    //依次类推重写其他接口的方法和Object对象的方法
}

动态代理的接口为IServer

//被代理的实现类,内部类调用局部变量时需要final标识
final Class<ServerImpl> serverClass = ServerImpl.class;
//interfaces:被代理的接口,hanlder:代理执行处理器,返回proxyInstance动态生成的代理对象
Object proxyInstance = Proxy.newProxyInstance(serverClass.getClassLoader(), serverClass.getInterfaces()
        //实现InvocationHandler接口,在处理器中实现增强操作
        , new InvocationHandler() {
            // proxy:生成的代理对象,method:当前调用的真实方法对象,args:当前调用方法的实参
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("有没有被动态代理啊!");
                Object invoke = method.invoke(serverClass.newInstance(), args);
                //返回被代理的方法返回值
                return invoke;
            }
        });
//虽然被代理的真实实现类为ServerImpl,但是底层的代理对象实现也是IServer接口
IServer server = (IServer) proxyInstance;
server.test();
//包括Object方法也被增强了
server.hashCode();
CGLIB动态代理

通过继承的方式实现动态代理,生成目标类的子类,并重写父类非final、非static、非private的修饰符的方法实现增强;动态代理的最小单位是类(所有类中的方法都会被处理)

//cglib是通过继承的方式实现动态代理
final Class<ServerImpl> serverClass = ServerImpl.class;
//创建代理类构造器对象
Enhancer enhancer = new Enhancer();
//设置要继承的父类
enhancer.setSuperclass(serverClass);
//添加增强处理器,InvocationHandler类是org.springframework.cglib.proxy.InvocationHandler
enhancer.setCallback(new InvocationHandler() {
    // proxy:生成的代理对象,method	:当前调用的真实方法对象,args:当前调用方法的实参
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("CGLIB动态代理!");
        Object invoke = method.invoke(serverClass.newInstance(), args);
        //返回被代理的方法返回值
        return invoke;
    }
});
//创建cglib动态代理对象
Object proxyInstance = enhancer.create();
//虽然被代理的真实实现类为ServerImpl,但是底层的代理对象实现也是IServer接口
IServer server = (IServer) proxyInstance;
server.test();

示例:打印post请求日志

@Pointcut("execution(public * cn.test.rest..*.*(..)) || execution(public * cn.test.controller..*.*(..))")
public void requestLog() {
}

@Around(value = "@annotation(postMapping)")
public Object requestLog(ProceedingJoinPoint joinPoint,PostMapping postMapping) throws Throwable {
    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = attributes.getRequest();
    //获取切入的类
    Class<?> restClass = joinPoint.getTarget().getClass();
    MethodSignature signature = (MethodSignature)joinPoint.getSignature();
    //获取切入方法
    Method method = signature.getMethod();
    //获取切入方法的参数
    Object[] args = joinPoint.getArgs();
    //获取请求url
    String url = request.getRequestURL().toString();
    String requestParam = "";
    if ("post".equalsIgnoreCase(request.getMethod())){
        StringBuilder sb = new StringBuilder();
        Arrays.stream(args).filter(object -> !(object instanceof HttpServletResponse) && !(object instanceof HttpServletRequest) && !(object instanceof MultipartFile) && !(object instanceof BeanPropertyBindingResult)).forEach((object) -> {
            Object jsonObject = JSON.toJSON(object);
            if (jsonObject != null) {
                sb.append(JSON.toJSONString(jsonObject)).append("|");
            }else {
                sb.append(object).append("|");
            }
        });
        requestParam = sb.append("flag").toString().replace("|flag", "");
    }else {
        requestParam = request.getQueryString();
    }

    log.info("requestUrl:{} requestParam is {}",url ,requestParam);
    Object proceed = joinPoint.proceed();
    log.info("response:{}",JSON.toJSONString(proceed));
    return proceed;
}

Spring事务机制

Spring事务功能在spring-tx模块中,在SpringBoot项目中事务需要依赖mybatis-spring-boot-starter包从而引入spring-tx,开启Spring事务方式有三种:

第一种xml配置< tx:advice>增强器

<!--引入tx命名空间-->
xmlns:tx="http://www.springframework.org/schema/tx"

<!--配置事务管理器 使用JDBC,MyBatis的事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!--依赖的也是数据源-->
    <property name="dataSource" ref="dataSources"/>
</bean>
<!--通过AOP对方法做事务增强-->
<aop:config>
    <aop:pointcut id="pc" expression="execution(* cn.mywork.service..*(..))"/>
    <!--advisor只持有一个Pointcut和一个advice-->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
</aop:config>
<!--配置事务管理的切面-->
<!--transaction-manager默认值为transactionManager,不注册transactionManager则默认为PlatformTransactionManager -->
<!--如果注册的beanName为transactionManager则使用注册的bean-->
<tx:advice id="myAdvice" transaction-manager="txManager">
    <tx:attributes>
        <!--name指匹配的方法名 read-only只读 isolation事务的隔离性 propagation传播性-->
        <!--rollback-for/no-rollback-for 回滚/不回滚的异常类数组 timeout 超时时间-->
        <tx:method name="*" read-only="true" isolation="READ_UNCOMMITTED" propagation="REQUIRED" rollback-for="Exception.class" timeout="-1" no-rollback-for=""/>
    </tx:attributes>
</tx:advice>

第二种xml开启事务注解支持< tx:annotation-driven>

<!--transaction-manager事务管理器默认PlatformTransactionManager  mode默认proxy-->
<!--MVC框架也有此类开启注解的节点 mvc:annotation-driven节点的解析器-->
<tx:annotation-driven proxy-target-class="" transaction-manager="" mode="aspectj"/>

@Transactional(
        rollbackFor = {Exception.class,RuntimeException.class},
        noRollbackFor = RuntimeException.class,
        rollbackForClassName = "Exception")

第三种SpringBoot配置@EnableTransactionManagement

@SpringBootApplication
@EnableTransactionManagement(mode = AdviceMode.PROXY)
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class,args);
    }
}

事务解析器TxAdviceBeanDefinitionParser

在xml文件解析阶段,获取所有META-INF/spring.handlers文件中对应的字节码全限定名对xml文件的标签初始化

//TxNamespaceHandler解析xml对应的3个节点
public void init() {
    //本质上注册了一个Advice事务增强器TransactionInterceptor
    registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
    //注解方式事务解析器
    registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
    //分布式事务的应用 <tx:jta-transaction-manager/>
    registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}

TxAdviceBeanDefinitionParser解析器对应< tx:advice>标签,继承了AbstractSingleBeanDefinitionParser,但是parse()解析节点的方法在AbstractSingleBeanDefinitionParser的父类AbstractBeanDefinitionParser中

//AbstractBeanDefinitionParser 主要是解析节点的id和name属性
public final BeanDefinition parse(Element element, ParserContext parserContext) {
    //交给子类解析内部属性并构建为beanDefinition
    AbstractBeanDefinition definition = parseInternal(element, parserContext);
    //解析id属性
    String id = resolveId(element, definition, parserContext);
    BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
    //将id作为beanName添加到beanDefinition并注册到BeanFactory中
    registerBeanDefinition(holder, parserContext.getRegistry());
    return definition;
}

//AbstractSingleBeanDefinitionParser 这一步可以知道注册的是一个TransactionInterceptor
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
    //构建一个空的Definition封装在builder中
    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
	//模板方法模式,通过子类TxAdviceBeanDefinitionParser获取一个TransactionInterceptor
    Class<?> beanClass = getBeanClass(element);
    if (beanClass != null) {
        //添加到上面那个未加工的beanDefinition中
        builder.getRawBeanDefinition().setBeanClass(beanClass);
    }
    //交给子类实现属性的解析
    doParse(element, parserContext, builder);
    return builder.getBeanDefinition();
}

//TxAdviceBeanDefinitionParser 将attributes解析作为属性添加到TransactionInterceptor中
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
    //将transaction-manager属性值,也就是管理器的beanName封装到RuntimeBeanReference
    builder.addPropertyReference("transactionManager", TxNamespaceHandler.getTransactionManagerName(element));
    // 解析<tx:attributes>节点
    List<Element> attributes = DomUtils.getChildElementsByTagName(element, "attributes");
    if (attributes.size() == 1) {
        Element attributeSourceElement = attributes.get(0);
        //1.解析每个method节点,获取method方法的name
        //2.构建一个attribute(TransactionDefinition)封装其他属性
        //3.将name作为key,添加attribute到transactionAttributeMap
        //4.构建一个NameMatchTransactionAttributeSource(包含一个nameMap缓存属性)的bean
        //5.将transactionAttributeMap添加到Source的PropertyValues中(key:"nameMap")
        RootBeanDefinition attributeSourceDefinition = parseAttributeSource(attributeSourceElement, parserContext);
        //将bean添加到builder.beanDefinition的PropertyValue中
        builder.addPropertyValue("transactionAttributeSource", attributeSourceDefinition);
    } else if(attributes.size() == 0) {
        // 若没有attributes节点则注册一个注解事务属性
        //也就是说只需要当<tx:advice id="myAdvice"/>存在时就可以使用@Transactional注解
        builder.addPropertyValue("transactionAttributeSource",
                                 new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"));
    }
}

事务增强器TransactionInterceptor

实现事务机制的主要接口包括:

1. TransactionDefinition:封装事务属性,比如传播行为,隔离级别和超时时间,是否为只读事务等
2. PlatformTransactionManager:根据TransactionDefinition提供的事务属性配置信息,创建事务管理器
3. TransactionStatus:封装了事务的具体运行状态,比如,是否是新开启事务,是否已经提交事务,设置当前事务为rollback-only等

因为TransactionInterceptor是一个Interceptor,从而也是一个Advice,所以在实现aop时作为切面的增强器;其实和普通的aop没有什么区别,在初始化Advisor之后对切点匹配的方法进行事务增强;和其他advise的配置一样,都是通过的MethodInterceptor的invoke方法实现增强

//引用的txAdvice通过TransactionInterceptor实现增强
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
//MethodBeforeAdviceInterceptor实现Before方法的增强
<aop:before method="testBefore" pointcut-ref="demoPointcut"/>

public Object invoke(final MethodInvocation invocation) throws Throwable {
	//获取需要增强的目标类
    Class<?> targetClass = (invocation.getThis() != ...;
    //交给父类TransactionAspectSupport实现增强
    return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
        @Override
        public Object proceedWithInvocation() throws Throwable {
            return invocation.proceed();
        }
    });
}

继续深入invokeWithinTransaction()方法

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation) throws Throwable {
    //如果是注解则通过AnnotationTransactionAttributeSource获取,否则获取的是NameMatchTransactionAttributeSource
    final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
    //获取TransactionManager属性,比如配置的DataSourceTransactionManager
    final PlatformTransactionManager tm = determineTransactionManager(txAttr);
    //开启手动事务
    TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
    //执行目标方法,如果异常则根据匹配rollback等配置确定是否执行事务回滚con.rollback();
    Object retVal = null;
    try {
        retVal = invocation.proceedWithInvocation();
    } catch (Throwable ex) {
        completeTransactionAfterThrowing(txInfo, ex);
        throw ex;
    }  
}

propagation事务的传播性

//获取propagation事务的传播行为,开启事务
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
    // 配置的timeout如果小于-1则报错
    if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
        throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
    }
    int propagation = definition.getPropagationBehavior()//因为当前并没有开启事务,所以PROPAGATION_MANDATORY行为时会报异常
    if (propagation == TransactionDefinition.PROPAGATION_MANDATORY) {
        throw new IllegalTransactionStateException("");
    } else if (propagation == TransactionDefinition.PROPAGATION_REQUIRED ||
               propagation == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
               propagation == TransactionDefinition.PROPAGATION_NESTED) {;
        DefaultTransactionStatus status = newTransactionStatus(..);
        //获取数据库连接connection,取消自动提交con.setAutoCommit(false)         
        doBegin(transaction, definition);
        return status;
    }
}

//示例开启一个事务
Connection conn = DriverManager.getConnection(...);
try{
  con.setAutoCommit(false);
  Statement stmt = con.createStatement();
  con.commit();
}catch(Exception e){
  con.rollback();
}

Spring提供了7种事务传播级别,默认的是REQUIRED

@Transactional(propagation = Propagation.REQUIRED)
public void testTx(){
}

//事务级别定义全部以B方法有事务为例
ServiceA {
    void methodA() {
        ServiceB.methodB();
    }
}

ServiceB {
    void methodB() {
    }
} 

PROPAGATION_REQUIRED:如果A有事务则B加入到A的事务中,在methodA和methodB内的任何地方出现异常都要回滚,如果A没有事务则B进行自己的事务

PROPAGATION_REQUIRES_NEW:新建事务,比如设置A的事务级别为PROPAGATION_REQUIRED,B的事务级别为PROPAGATION_REQUIRES_NEW,那么当执行到B的时候,A所在的事务就会挂起,B会起一个新的事务,等待B的事务完成以后,A才继续执行。因为B是新起一个事务,那么就是存在两个不同的事务。如果B已经提交,那么A失败回滚,B是不会回滚的。如果B失败回滚,且抛出的异常被A捕获,A事务仍然可以提交。

PROPAGATION_SUPPORTS:如果当前A没有事务,B就以非事务方式执行,若A有事务则B加入到事务中

PROPAGATION_NOT_SUPPORTED:如果A的事务级别是PROPAGATION_REQUIRED ,那么当执行到B时,A的事务挂起,而B以非事务的状态运行完,再继续A的事务,即使A有异常B也不会回滚

PROPAGATION_MANDATORY:B方法运行在A方法中,A方法必须有事务,如果A没有事务,就抛出异常

PROPAGATION_NEVER:B不能不能在事务中运行,如果A存在事务,则抛出异常

PROPAGATION_NESTED :如果A存在事务,则在嵌套事务内执行,如果A没有事务,则执行自己的事务

与PROPAGATION_REQUIRES_NEW的区别是,PROPAGATION_REQUIRES_NEW另起一个事务,两个事务相互独立,而Nested的B事务提交时是要等A事务一块提交

isolation隔离级别:默认为Default

注解@Transactional实现原理

AnnotationDrivenBeanDefinitionParser解析器对应annotation-driven标签

//AnnotationDrivenBeanDefinitionParser.parse()方法节选
if ("aspectj".equals(mode)) {
    // mode="aspectj"表示使用aspectj的方式比如CTW和LTW
    registerTransactionAspect(element, parserContext);
}
else {
    // mode="proxy"动态代理的方式
    AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}

//configureAutoProxyCreator()方法的节选
//@Transactional注解对应的事务属性
RootBeanDefinition sourceDef = new RootBeanDefinition(
    "org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
//注册一个TransactionInterceptor
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);

回到TransactionInterceptor获取TransactionAttribute,AnnotationTransactionAttributeSource是注解的事务属性资源实例

//获取事务属性
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);


// 不支持非public类型方法
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
    return null;
}
// 首先从specificMethod,也就是方法上获取@Transactional注解
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
    return txAttr;
}
// 如果方法上没有则从方法所在的类上获取注解
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
    return txAttr;
}
//目标类和方法上都没有注解则从类的接口上找注解
if (specificMethod != method) {
    //接口的方法上
    txAttr = findTransactionAttribute(method);
    if (txAttr != null) {
        return txAttr;
    }
    // 接口的类上
    txAttr = findTransactionAttribute(method.getDeclaringClass());
    if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
        return txAttr;
    }
}

剩下的步骤和xml配置方式一样,对于@EnableTransactionManagement开启@Transactional注解使用

@EnableTransactionManagement(mode = AdviceMode.PROXY)

//通过@Import引用的ImportSelector会执行selectImports方法
protected String[] selectImports(AdviceMode adviceMode) {
    switch (adviceMode) {
        case PROXY:
            //所以注册了两个组件:AutoProxyRegistrar,ProxyTransactionManagementConfiguration
            return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
    }
}

//而ProxyTransactionManagementConfiguration组件又注册了几个熟悉的组件
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

    //注册一个切面
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource());
		advisor.setAdvice(transactionInterceptor());
		return advisor;
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor() {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource());
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值