Entrevista preguntada con frecuencia sobre Spring AOP y la anotación de transacciones @Principio transaccional

esquema de contenido

  • Tecnología de proxy dinámico
  • fábrica de proxy
  • Clasificación de consejos
  • Tutor
  • Cómo Spring crea objetos proxy
  • Conceptos de primavera AOP
  • Elección de ProxyFactory de Cglib o JDK Proxy
  • Proceso de creación de objetos proxy
  • @EnableTransactionManagement principio
  • El principio básico de ejecución de la transacción Spring
  • Mecanismo de propagación de transacciones Spring
  • Clase de herramienta TransactionSynchronization

Estoy participando en el reclutamiento del programa de firma de creadores de la Comunidad Tecnológica de Nuggets, haga clic en el enlace para registrarse y enviar .

1. Tecnología de proxy dinámico

1.1.Proxy dinámico JDK

Para obtener el objeto proxy del objeto de destino basado en el método #newInstance( ) de la clase Proxy, se debe 基于接口implementar el proxy dinámico del JDK, porque el lenguaje Java no admite herencia múltiple, pero admite implementaciones múltiples. Mecanismo de implementación:

     1. 编写生成类实现`InvocationHandler接口`,覆盖invoke方法,实现切面逻辑。
     1. 通过Proxy的#newInstance( )静态方法来获取代理对象。
复制代码

1.2.Proxy dinámico Cglib

Cglib es una biblioteca de generación de código de terceros. Es una encapsulación secundaria de la tecnología de código de bytes ASM. Genera dinámicamente objetos proxy en tiempo de ejecución. Sus características se basan en la relación de herencia de subclases. Características: Herencia basada en subclases, incapacidad para representar clases y métodos modificados finales, alta eficiencia e introducción adicional de paquetes Jar. Mecanismo de implementación:

     1. 编写生成类实现`MethodInterceptor接口`,覆盖intercept方法,实现切面逻辑。
     1. new一个Enhancer类来实现父子类的委托。
     1. 将实现了MethodInterceptor的类作为入参放入Enhancer的callbacks属性里。
     1. 通过enhancer对象的#create( )方法得到代理对象。
复制代码

1.3.Tecnología de código de bytes ASM

ASM es un marco de herramientas para manipular bytecodes. ASM puede generar directamente archivos de clase binarios y modificar archivos de clase. Mecanismo de implementación: ASM escanea el contenido del archivo desde el principio hasta el final a través del modo de visitante, y vuelve a llamar al método de procesamiento lógico correspondiente cada vez que se escanea un identificador de contenido específico. En base a esto, el archivo fuente puede mejorarse para realizar el tecnología proxy. Dado que el código de bytes se manipula directamente, la eficiencia es muy alta. Common Groovy y Cglib usan tecnología ASM.

1.4.AspectoJ

AspectJ全称Eclipse AspectJ,是一个简单易用高效的AOP框架,也是一种基于Java平台的语言。Java语言的编译器是javac,AspectJ语言的编译器是ajc。 AspectJ属于是静态织入,也就是说在编译期就织入完成,但是他的效率比Spring的AOP更高。

2.ProxyFactory 代理工厂

Spring不可能直接写Cglib或者JDK的动态代理,而是基于这俩做了封装,封装出来的类叫做ProxyFactory代表是一个代理工厂,专门负责创建代理对象。

UserService target = new UserService(); 
ProxyFactory proxyFactory = new ProxyFactory(); 
proxyFactory.setTarget(target); 
proxyFactory.addAdvice(new MethodInterceptor() { 
    @Override 
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("before...");                                                                                                                   
        Object result = invocation.proceed(); 
        System.out.println("after..."); 
        return result; } }); 
UserInterface userService = (UserInterface) proxyFactory.getProxy(); 
userService.test();
复制代码

ProxyFactory会自动判断使用Cglib还是JDK动态代理。

3.Advice的分类

  • Before Advice:在方法执行之前触发。
  • After returning Advice:在方法return后触发。
  • After throwing Advice:在方法抛出异常后触发。
  • After finally Advice:在方法执行完finally和return后触发。
  • Around Advice:环绕触发模式,自定义触发时机。

4.Advisor

Advisor = Advice + Pointcut。Pointcut就是指需要代理的地方。

5.创建代理对象的方式

5.1 ProxyFactoryBean

利用FactoryBean的机制,通过@Bean给容器返回一个工厂Bean,最后通过工厂返回一个代理对象给容器。

    @Bean
    public ProxyFactoryBean userServiceProxyBean() {
        UserService userService = new UserService();
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(userService);
        proxyFactoryBean.addAdvice((MethodInterceptor) invocation -> {
            log.info("执行方法之前.......");
            Object result = invocation.proceed();
            log.info("执行方法之后.......");
            return result;
        });
        return proxyFactoryBean;
    }
复制代码

5.2 BeanNameAutoProxyCreator

通过BeanNameAutoProxyCreator可以对目标Bean进行模式匹配进行AOP,但是他的缺点就是只能通过Bean的名字来指定目标对象。

    @Bean
    public BeanNameAutoProxyCreator beanNameAutoProxycreator() {
        BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
        beanNameAutoProxyCreator.setBeanNames("被代理的对象名字");
        beanNameAutoProxyCreator.setInterceptorNames("你自己定义的Advise");
        beanNameAutoProxyCreator.setProxyTargetClass(true);
        return beanNameAutoProxyCreator;
    }
复制代码

5.3 DefaultAdvisorAutoProxyCreator

    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor() {
        NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
        pointcut.addMethodName("切点方法名");

        DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
        defaultPointcutAdvisor.setPointcut(pointcut);
        defaultPointcutAdvisor.setAdvice(null);
        return defaultPointcutAdvisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        return new DefaultAdvisorAutoProxyCreator();
    }
复制代码

通过DefaultAdvisorAutoProxyCreator会通过BeanPostProcessor机制检查所有的Advisor类型的Bean,根据Advisor中的Pointcut和Advice逻辑来实现代理功能。常见的注解版本@ASspect、@Before、@Around等就是它的简化版本:

    @Before("execution(com.example.redis.demo.UserService.test())") 
    public void before(JoinPoint joinPoint) {
        log.info("方法执行前......");
    }
复制代码

不过这种方式需要开启:@EnableAspectJAutoProxy注解。

6.Spring Aop概念

AOP本身代表面向切面编程,Spring提供了一套解决方案,可以通过简单的配置就可以实现面向切面的效果。Spring的AOP依赖了AspectJ,使用了AspectJ的一些核心注解,但是具体的解析工作和实现逻辑则是Spring自己处理的,例如常见的@Before、@After等等是AspectJ提供的。 Spring会将AspectJ的五个注解解析为Spring对应的Advice类:

@Before:AspectJMethodBeforeAdvice

@AfterReturning:AspectJAfterReturningAdvice

@AfterThrowing:AspectJAfterThrowingAdvice

@After:AspectJAfterAdvice

@Around:AspectJAroundAdvice 本质上来说就是个MethodInterceptor,当外部调用代理对象的方法时候就会触发方法拦截器来做方法执行前后的增强逻辑。

7.ProxyFactory对Cglib和JDK动态代理的选择

imagen.png

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	/**
	 * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
	 * to standard Java interface-based proxies. The default is {@code false}.
	 */
   // 是否强制开启使用cglib
	boolean proxyTargetClass() default false;

	/**
	 * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
	 * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
	 * Off by default, i.e. no guarantees that {@code AopContext} access will work.
	 * @since 4.3.1
	 */
   // 是否暴露代理对象,使用AopContext.currentProxy()获取
	boolean exposeProxy() default false;

}
复制代码
  - 如果开启了`@EnableAspectJAutoProxy`注解,并且`proxyTargetClass`属性赋予了true,那么无条件使用Cglib。
  - 如果需要代理的对象基于接口,且参数没有指定强制使用cglib则使用JDK的动态代理。
复制代码

8.AbstractAdvisorAutoProxyCreator(AOP核心)

这个抽象类的实现类之一就是DefaultAdvisorAutoProxyCreator,这个抽象代理构建类从某种意义上来说,只要Spring IOC容器中有这个Bean的实现,就相当于是开启了AOP功能。 AbstractAdvisorAutoProxyCreator实现了BeanPostProcessor,所以它本质上来说也是一个Spring的后置处理器,在Spring Bean实例化后,在初始化前后会经过这个后置处理器的加工,从而来实现AOP的代理生成。 大致过程是:AbstractAdvisorAutoProxyCreator通过BeanPostProcessor机制来加工初始化后的Bean,找到容器中所有的Advisor(切点+切面逻辑),然后判断这个Bean是否存在Advisor所匹配的切点,如果匹配就表示当前这个初始化的Bean需要代理,此时就会通过ProxyFactory选择具体的动态代理手段来构建代理对象。

8.1 @EnableAspectJAutoProxy

这个注解的核心原理就是往IOC容器中Import了一个AnnotationAwareAspectJAutoProxyCreator类的Bean实例。这个类继承自AbstractAdvisorAutoProxyCreator,所以它本质上也是一个BeanPostProcessor后置处理器。 AnnotationAwareAspectJAutoProxyCreator除了可以找到所有的Advisor类型的Bean,还可以找到@Aspect注解的Bean,并将其解析为Advisor对象,然后走AOP的逻辑生成代理对象。

@Transactional注解的实现无非也是基于AOP。

9.@EnableTransactionManagement注解原理

这个注解的作用不言而喻,就是开启Spring对事务管理的支持。和其他的Enable注解类似,他的底层原理就是通过ImportSelector接口向IOC容器中放入了2个Bean:

  - AutoProxyRegistrar:开启AOP的支持,底层就是一个PostProcessor。
  
  - ProxyTransactionManagementConfiguration:事务切面功能的具体实现。
复制代码

9.1 AutoProxyRegistrar(AOP的支持)

这个Bean的作用就是向IOC容器中注册了一个AbstractAdvisorAutoProxyCreator的实现类,这个抽象类就是AOP的核心实现。所以这个Bean说白了也就是BeanPostProcessor,在Spring Bean初始化后会进行对Advisor的寻找,然后判断当前Bean是否需要进行AOP并且是否有符合的切点,然后进行AOP的操作。

9.2 ProxyTransactionManagementConfiguration(事务支持)

这也是一个配置类,但是它又定义了3个Bean:

     - `BeanFactoryTransactionAttributeSourceAdvisor`:相当于一个Advisor。
     
     - `AnnotationTransactionAttibuteSource`:用来检查某个类或者方法上是否添加了@Transactional注解。
     
     - `TransactionInterceptor`:具体的事务代理逻辑,如果某个类存在@Transactional注解,那么在运行事务切到的方法时,就会先调用这个TransactionInterceptor的invoke中进行事务的开启。
复制代码

10.Spring事务基本执行原理

  1. Bean的生命周期中,初始化后阶段,通过BeanPostProcessor机制,经过InfrastructureAdvisorAutoProxyCreator的后置处理方法检查当前初始化的Bean是否存在@Transactional注解,随之生成一个代理对象。
  2. 在外部调用这个代理对象的事务方法的时候,命中MethodInterceptor拦截,检查当前方法是否有匹配的Advisor,有则执行对应的invoke方法,在invoke方法里定义了事务的实现原理。
  3. 利用配置好的PlatformTransactionManager事务管理器新建一个数据库连接。
  4. 修改这个Connection的提交模式autoCommit为false,否则每一条SQL都要自动提交。
  5. 执行MethodInvocation.proceed( )方法,这里面就会调用我们自己的方法逻辑,例如SQL的执行。
  6. 执行结束,如果没有抛出异常则提交,否则回滚。

11.Spring事务传播机制

如果需要达到不同方法对事务控制手段的变化,则需要引入事务传播机制的特性。例如A方法调用B方法,如果希望A和B的不处于同一个事务那么原理如下:

  1. 代理对象执行MethodInvocation.proceed()之前会利用事务管理器新建一个数据库连接conn1。
  2. 将conn1的提交模式autoCommit改为false。
  3. 将conn1这个连接设置到ThreadLocal中。
  4. 执行具体的业务逻辑SQL。
  5. Si se llama al método B en el método A (la llamada al objeto proxy):
    1. Antes de que el objeto proxy ejecute el método B, suspende conn1, elimina conn1 de ThreadLocal y lo encapsula en un objeto de suspensión.
    2. El administrador de transacciones crea otra conexión de base de datos conn2.
    3. Repita la acción justo ahora: configure autoCommit = false, coloque conn2 en ThreadLocal.
    4. Ejecute el SQL de lógica de negocios del método B.
    5. Después de la ejecución del método B, obtenga conn2 en ThreadLocal y realice la acción de confirmación.
    6. Después de enviar conn2, restaure el objeto de suspensión de conn1 y vuelva a colocar conn1 en ThreadLocal.
  6. Después de la ejecución del método A, obtenga conn1 de ThreadLocal y realice la acción de confirmación.

La transacción se establece en la conexión de la base de datos Conexión Si los métodos A y B están en la misma conexión, si el método B informa un error, incluso si el método A lo captura, todo se revertirá.

12. TransactionSynchronization sincronizador de transacciones

Este sincronizador de transacciones se puede usar para monitorear el estado de la transacción, y una vez que el estado de la transacción cambie, activará la lógica correspondiente en un modo de devolución de llamada.

    @Transactional(rollbackFor = Exception.class)
    public void transactionSyncDemo() {
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void suspend() {
                
            }

            @Override
            public void resume() {

            }

            @Override
            public void flush() {

            }

            @Override
            public void beforeCommit(boolean readOnly) {
                log.info("准备提交事务");
            }

            @Override
            public void beforeCompletion() {
                log.info("准备提交或准备回滚");
            }

            @Override
            public void afterCommit() {
                log.info("提交事务后");
            }

            @Override
            public void afterCompletion(int status) {
                log.info("提交或回滚成功");
            }
        });
    }
复制代码

Estoy participando en el reclutamiento del programa de firma de creadores de la Comunidad Tecnológica de Nuggets, haga clic en el enlace para registrarse y enviar .

Supongo que te gusta

Origin juejin.im/post/7120070833996824590
Recomendado
Clasificación