Back to Javatutorial

Spring事务(一):认识事务组件

docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(一):认识事务组件.md

1.0.022.9 KB
Original Source

ǰ spring aop عܺ󣬱Ľ spring aop һӦ

1. demo

ʽǰ˼£Լ spring aop һƣʵأû springǵһ㳤

public void fun() {
    // 
    start();
    try {
        // ҵ
        xxx();
        // ύ
        commit();
    } catch(Exception e) {
        // ع
        rollback();
        throw e;
    }
}

Ĵύ񡢻ع񣬶ҵ޹أЩʹ spring aop ʵ֣˾ demo.

demo01 @Around עʵ

ǿʹ @Around ע£

  1. һע⣺@MyTransactional
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyTransactional {
}

  1. aop
@Aspect
@Component
public class MyAopAspectj {
    @Pointcut("@annotation(org.springframework.learn.tx.demo02.MyTransactional)")
    public void testAop(){

    }

    @Around("testAop()")
    public Object around(ProceedingJoinPoint p) throws Throwable {
        System.out.println("ִǰ....");
        try {
            Object o = p.proceed();
            System.out.println("ִɣύ....");
            return o;
        } catch (Throwable e) {
            System.out.println("쳣쳣ͻع....");
            throw e;
        } finally {
            System.out.println("ִк....");
        }
    }

}

  1. configһЩҪ
@Configuration
@ComponentScan("org.springframework.learn.tx.demo02")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class TxDemo02Config {

}

  1. һ service ࣬һ @MyTransactional ע
@Service
public class TxTestService {

    @MyTransactional
    public void test01() {
        System.out.println("ִtest01");
    }

    public void test02() {
        System.out.println("ִtest02");
    }

}

public class TxDemo02Main {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext
                = new AnnotationConfigApplicationContext(TxDemo02Config.class);
        TxTestService service = applicationContext.getBean(TxTestService.class);
        System.out.println("-------------------");
        service.test01();
        System.out.println("-------------------");
        service.test02();

    }
}

У£

-------------------
ִǰ....
ִtest01
ִɣύ....
ִк....
-------------------
ִtest02

demo Уʹ @Around עҵִǰԿ@Around עڴǰdz쳣ʱһЩIJ

demo02Զ advisor ʵ

ǻ spring aop @Around עĴʵ @Around ջװΪ InstantiationModelAwarePointcutAdvisorImpl 󣬺Ĵ͸ @Around ޹ˣ@Around InstantiationModelAwarePointcutAdvisorImpl Ḷ́ɲο spring aop ֮ AnnotationAwareAspectJAutoProxyCreator ϣ.

InstantiationModelAwarePointcutAdvisorImpl ǸʲôأǸ advisor˵ǿڷǿ spring aop ҵӦڵǰ advisor ģɲο spring aop ֮ AnnotationAwareAspectJAutoProxyCreator £

ͨϷṩһ˼·ǿʵ advisor ӿڣƻԼ߼£

  1. ׼ advice
/**
 * adviceadvisorһԣ߼ﴦ
 */
public class MyAdvice implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("ִǰ....");
        try {
            Object val = invocation.proceed();
            System.out.println("ִɣύ....");
            return val;
        } catch (Throwable e) {
            System.out.println("쳣쳣ͻع....");
            throw e;
        } finally {
            System.out.println("ִк....");
        }
    }
}

  1. ׼ pointcut
/**
 * е
 * жЩڸadvisor
 */
public class MyPointcut extends StaticMethodMatcherPointcut {
    /**
     * ƥ䷽ @MyTransactional 򷽷ͷtrue
     */
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        return null != AnnotationUtils.getAnnotation(method, MyTransactional.class)
                || null != AnnotationUtils.getAnnotation(targetClass, MyTransactional.class);
    }
}

  1. ׼ advisor
/**
 * advisor ɿ advice  pointcut İװ
 */
@Component
public class MyAdvisor extends AbstractBeanFactoryPointcutAdvisor {

    private static final long serialVersionUID = 2651364800145442305L;

    private MyPointcut pointcut;

    public MyAdvisor() {
        this.pointcut = new MyPointcut();
        this.setAdvice(new MyAdvice());
    }

    @Override
    public Pointcut getPointcut() {
        return this.pointcut;
    }

}

DzͬעʵַʽĴעһˡ

  1. ׼һע⣺@MyTransactional
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyTransactional {
}

  1. Ŀ
@Configuration
@ComponentScan("org.springframework.learn.tx.demo01")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class TxDemo01Config {

}

  1. ׼һ service
@Service
public class TxTestService {

    @MyTransactional
    public void test01() {
        System.out.println("ִtest01");
    }

    public void test02() {
        System.out.println("ִtest02");
    }

}

public class TxDemo01Main {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext
                = new AnnotationConfigApplicationContext(TxDemo01Config.class);
        TxTestService service = applicationContext.getBean(TxTestService.class);
        System.out.println("-------------------");
        service.test01();
        System.out.println("-------------------");
        service.test02();

    }
}

У£

-------------------
ִǰ....
ִtest01
ִɣύ....
ִк....
-------------------
ִtest02

2. ʹ spring

ǰС demo Ϊθˣ spring һʶspring ڴʱʹõľǵڶַʽԶһ advisor ӵ spring С spring ʵľϸڣǴһ demoƽʱôʹġ

Ϊ˽ݿӣҪݿӳأʹõ mysqlҪ spring-learn.gradle

optional("mysql:mysql-connector-java:5.1.48")

žǴˡ

@Configuration
@ComponentScan("org.springframework.learn.tx.demo03")
@EnableTransactionManagement(proxyTargetClass = true)
public class TxDemo01Config {

    /**
     * Դ
     * @return
     * @throws Exception
     */
    @Bean
    public DataSource dataSource() throws Exception {
        Driver driver = new com.mysql.jdbc.Driver();
        String url = "jdbc:mysql://localhost:3306/test";
        String username = "root";
        String password = "123";
        return new SimpleDriverDataSource(driver, url, username, password);
    }

    /**
     * jdbcTemplateݿIJ
     * @param dataSource
     * @return
     */
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    /**
     * 
     * @param dataSource
     * @return
     */
    @Bean
    public DataSourceTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

}

  1. ݿ
@Service
public class UserService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * ݿʹ @Transactional 
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public int insert() {
        String sql = "insert into `user`(`login_name`, `nick`, `create_time`, `update_time`)"
                + "values (?, ?, ?, ?)";
        int result = jdbcTemplate.update(sql, "test", "test", new Date(), new Date());
        if(true) {
            //throw new RuntimeException("׳쳣");
        }
        System.out.println(result);
        return result;
    }

}

public class TxDemo01Main {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext
                = new AnnotationConfigApplicationContext(TxDemo01Config.class);
        UserService userService = applicationContext.getBean(UserService.class);
        userService.insert();

    }
}

demo УDataSource ʹ spring Դ SimpleDriverDataSource``orm Ҳ spring ṩ jdbcTemplateʹõ user sql £

CREATE TABLE `user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  `login_name` varchar(32) NOT NULL DEFAULT '0' COMMENT '¼',
  `nick` varchar(32) NOT NULL DEFAULT '0' COMMENT 'dz',
  `create_time` datetime DEFAULT NULL COMMENT 'ʱ',
  `update_time` datetime DEFAULT NULL COMMENT 'ʱ',
  PRIMARY KEY (`id`),
  KEY `create_time` (`create_time`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='û';

ִн£

һβ׳쳣ݿ

ڶ׳쳣ݿ

β׳쳣ݿ

Կڶ׳쳣ʱعˡ

demoйصĴ

  • @EnableTransactionManagement(proxyTargetClass = true)
  • DataSourceTransactionManager
  • @Transactionalָķ

aop @EnableAspectJAutoProxy``@EnableTransactionManagement ڣǾʹע֣ spring ̡

3. @EnableTransactionManagement ע

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

    /**
     * ѧaopضѾϤ
     * true: ʾǿʹcglib
     * falseĿʵ˽ӿڣʹjdk̬ʹcglib
     *  mode Ϊ PROXY Ч
     */
    boolean proxyTargetClass() default false;

    /**
     * adviceģʽʹôʹ aspectJ
     */
    AdviceMode mode() default AdviceMode.PROXY;

    /**
     * ִ˳򣬵һжǿʱʲô˳ִ
     */
    int order() default Ordered.LOWEST_PRECEDENCE;

}

עⱾûʲôԣעѾȷˣǹؼǿעࣺTransactionManagementConfigurationSelector

public class TransactionManagementConfigurationSelector extends 
        AdviceModeImportSelector<EnableTransactionManagement> {
    @Override
    protected String[] selectImports(AdviceMode adviceMode) {
        switch (adviceMode) {
            case PROXY:
                // ڴ
                return new String[] {AutoProxyRegistrar.class.getName(),
                        ProxyTransactionManagementConfiguration.class.getName()};
            case ASPECTJ:
                // aspectJ࣬IJ
                return new String[] {determineTransactionAspectClass()};
            default:
                return null;
        }
    }
    // ʡ
    ...

}

ڴࣺAutoProxyRegistrar``ProxyTransactionManagementConfigurationǾࡣ

3.1 AutoProxyRegistrar

AutoProxyRegistrar һעǵǰ aop ע AspectJAutoProxyRegistrar һ·

澿ɶ

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    private final Log logger = LogFactory.getLog(getClass());

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, 
            BeanDefinitionRegistry registry) {
        boolean candidateFound = false;
        Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
        for (String annType : annTypes) {
            AnnotationAttributes candidate = AnnotationConfigUtils
                    .attributesFor(importingClassMetadata, annType);
            if (candidate == null) {
                continue;
            }
            Object mode = candidate.get("mode");
            Object proxyTargetClass = candidate.get("proxyTargetClass");
            // ifģ @EnableTransactionManagement ע
            if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
                    Boolean.class == proxyTargetClass.getClass()) {
                candidateFound = true;
                if (mode == AdviceMode.PROXY) {
                    // עע InfrastructureAdvisorAutoProxyCreator ࣬
                    AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                    if ((Boolean) proxyTargetClass) {
                        // ʹcglib
                        AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                        return;
                    }
                }
            }
        }
        if (!candidateFound && logger.isInfoEnabled()) {
            String name = getClass().getSimpleName();
            logger.info(...);
        }
    }
}

дؼľֻ if ļУ˵ if mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&Boolean.class == proxyTargetClass.getClass()ͨĶ @EnableTransactionManagement˵ľˣ mode == AdviceMode.PROXY AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)ĵãǽȻ proxyTargetClassԵ @EnableAspectJAutoProxy е proxyTargetClass һ£Ҳǿǿʹ cglib

AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry) Ḷ́룺

AopConfigUtils

    @Nullable
    public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
        // ¿
        return registerAutoProxyCreatorIfNecessary(registry, null);
    }

    @Nullable
    public static BeanDefinition registerAutoProxyCreatorIfNecessary(
            BeanDefinitionRegistry registry, @Nullable Object source) {
        //  InfrastructureAdvisorAutoProxyCreator ࣬
        return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, 
            registry, source);
    }

DzϤУaop е AspectJAnnotationAutoProxyCreator Ҳ ôעģ AopConfigUtils#registerOrEscalateApcAsRequired

// AopConfigUtils ע඼
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);

static {
    APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
    APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
    APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}

/**
 * ע
 */
private static BeanDefinition registerOrEscalateApcAsRequired(
        Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    //Ѵbean
    if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
        BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
        //жȼȼϸ滻ԭȵbean
        if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
            int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
            int requiredPriority = findPriorityForClass(cls);
            // Ѵ ȼ СעģʹעģѴڵȼΪ
            // 0: InfrastructureAdvisorAutoProxyCreator()
            // 1: AspectJAwareAdvisorAutoProxyCreator(xmlaop)
            // 2: AnnotationAwareAspectJAutoProxyCreator(עaop)
            if (currentPriority < requiredPriority) {
                apcDefinition.setBeanClassName(cls.getName());
            }
        }
        return null;
    }
    //עXxxAutoProxyCreator
    RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
    beanDefinition.setSource(source);
    beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
    beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
    return beanDefinition;
}

/**
 * עȼ
 */
private static int findPriorityForClass(@Nullable String className) {
    for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
        Class<?> clazz = APC_PRIORITY_LIST.get(i);
        if (clazz.getName().equals(className)) {
            return i;
        }
    }
    throw new IllegalArgumentException(
            "Class name [" + className + "] is not a known auto-proxy creator class");
}

AopConfigUtils ע

  • InfrastructureAdvisorAutoProxyCreator
  • AspectJAwareAdvisorAutoProxyCreator xml aop
  • AnnotationAwareAspectJAutoProxyCreatorע aop

ߵȼΪ AnnotationAwareAspectJAutoProxyCreator > AspectJAwareAdvisorAutoProxyCreator > InfrastructureAdvisorAutoProxyCreatorעʱжעȼȼߵջᱻע뵽 spring С͵һ⣺Ŀͬʱ aop (@EnableAspectJAutoProxy) (@EnableTransactionManagement)ôע뵽Ľ AnnotationAwareAspectJAutoProxyCreatorҲ˵AnnotationAwareAspectJAutoProxyCreator Ҳܴ 仰dzؼζĴ̣ʵϾͰǰ aop Ĺˣ

Ҳ InfrastructureAdvisorAutoProxyCreator

// ̳ AbstractAdvisorAutoProxyCreatordzؼ
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {

    @Nullable
    private ConfigurableListableBeanFactory beanFactory;

    @Override
    protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        super.initBeanFactory(beanFactory);
        this.beanFactory = beanFactory;
    }

    @Override
    protected boolean isEligibleAdvisorBean(String beanName) {
        return (this.beanFactory != null && 
                this.beanFactory.containsBeanDefinition(beanName) 
                &&  this.beanFactory.getBeanDefinition(beanName).getRole() 
                                == BeanDefinition.ROLE_INFRASTRUCTURE);
    }

}

InfrastructureAdvisorAutoProxyCreator ʵûʲô aop ص£̳һؼࣺAbstractAdvisorAutoProxyCreatorǴͷ

Ӽ̳йϵ̳ AbstractAutoProxyCreator AbstractAutoProxyCreator - spring aop ֮ AnnotationAwareAspectJAutoProxyCreator ϣ spring aop ֮ AnnotationAwareAspectJAutoProxyCreator £صġIJڣ

AnnotationAwareAspectJAutoProxyCreator``AspectJAwareAdvisorAutoProxyCreator InfrastructureAdvisorAutoProxyCreator ߵĹϵ

ԿAspectJAwareAdvisorAutoProxyCreator InfrastructureAdvisorAutoProxyCreator ̳ AbstractAdvisorAutoProxyCreator``AnnotationAwareAspectJAutoProxyCreator ּ̳ AspectJAwareAdvisorAutoProxyCreator

ͨϷAutoProxyRegistrar spring ע InfrastructureAdvisorAutoProxyCreator(aop δõ) aopע AspectJAwareAdvisorAutoProxyCreator( xml aop) AnnotationAwareAspectJAutoProxyCreator( annotation aop)

3.2 ProxyTransactionManagementConfiguration

ProxyTransactionManagementConfiguration ࡣǸࣺ

@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration 
        extends AbstractTransactionManagementConfiguration {

    /**
     * ȡSpring @Transactional ע⣬ӦԹSpringṹ
     */
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionAttributeSource transactionAttributeSource() {
        return new AnnotationTransactionAttributeSource();
    }

    /**
     * TransactionInterceptor̳AdviceǸadviceִв
     * @param transactionAttributeSource transactionAttributeSource() 
     */
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionInterceptor transactionInterceptor(
            TransactionAttributeSource transactionAttributeSource) {
        TransactionInterceptor interceptor = new TransactionInterceptor();
        // Դ󣬾 @Transactional ע Ķȡ
        interceptor.setTransactionAttributeSource(transactionAttributeSource);
        if (this.txManager != null) {
            interceptor.setTransactionManager(this.txManager);
        }
        return interceptor;
    }

    /**
     * ǿ.
     * @param transactionAttributeSource transactionAttributeSource() 
     * @param transactionInterceptor transactionInterceptor(...) 
     */
    @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
            TransactionAttributeSource transactionAttributeSource,
            TransactionInterceptor transactionInterceptor) {
        BeanFactoryTransactionAttributeSourceAdvisor advisor 
                = new BeanFactoryTransactionAttributeSourceAdvisor();
        // ࣬ @Transactional 
        advisor.setTransactionAttributeSource(transactionAttributeSource);
        // adviceadviceﴦ
        advisor.setAdvice(transactionInterceptor);
        if (this.enableTx != null) {
            advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
        }
        return advisor;
    }

}

Կһ Щ bean

  • transactionAttributeSourceΪ AnnotationTransactionAttributeSource @Transactional ע⣻
  • transactionInterceptorΪ TransactionInterceptor``Advice ࣬߼
  • transactionAdvisorΪ BeanFactoryTransactionAttributeSourceAdvisorǸ Advisor߼ڲtransactionAttributeSource transactionInterceptor

ProxyTransactionManagementConfiguration ̳ AbstractTransactionManagementConfiguration AbstractTransactionManagementConfiguration ҲһЩ bean

@Configuration
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {

    @Nullable
    protected AnnotationAttributes enableTx;

    /**
     * 
     */
    @Nullable
    protected TransactionManager txManager;

    /**
     *  ImportAware ӿڵķ
     */
    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        this.enableTx = AnnotationAttributes.fromMap(importMetadata
                .getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
        if (this.enableTx == null) {
            throw new IllegalArgumentException(
                    "@EnableTransactionManagement is not present on importing class " 
                    + importMetadata.getClassName());
        }
    }

    /**
     * .
     * עspringе TransactionManagementConfigurer 
     * TransactionManagementConfigurerֻһ
     *  TransactionManager annotationDrivenTransactionManager()
     * һ
     */
    @Autowired(required = false)
    void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
        if (CollectionUtils.isEmpty(configurers)) {
            return;
        }
        if (configurers.size() > 1) {
            throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
        }
        TransactionManagementConfigurer configurer = configurers.iterator().next();
        this.txManager = configurer.annotationDrivenTransactionManager();
    }

    /**
     * ¼ @TransactionalEventListener עķ.
     */
    @Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
        return new TransactionalEventListenerFactory();
    }

}

  • void setConfigurers(Collection<TransactionManagementConfigurer> configurers)ע TransactionManagementConfigurer 󣬾ڴע˵
  • TransactionalEventListenerFactoryΪ TransactionalEventListenerFactory¼Ҫ @TransactionalEventListener עķⲿֵݣľͲչˣ

ˣЩspring ͿԽˣЩƪٷ

4. ܽ

Ǵ demo ֣ʾԼһ spring aop νеģһ demo ʾʹ spring ṩܣȻ; spring ע @EnableTransactionManagement Ĺܡ

@EnableTransactionManagement spring ܵģ AdviceMode Ϊ proxy ģʽ£ע spring ࣺAutoProxyRegistrar``ProxyTransactionManagementConfiguration£

  • AutoProxyRegistrar``aop δõ£ spring ע InfrastructureAdvisorAutoProxyCreator aopע AspectJAwareAdvisorAutoProxyCreator( xml aop) AnnotationAwareAspectJAutoProxyCreator( annotation aop)඼ AbstractAdvisorAutoProxyCreator ࣬ɴ

  • ProxyTransactionManagementConfigurationһ࣬ͨ @Bean עķһϵе bean߼Щ beanֻ˽⼴ɡ

ľȵˣƪ¼ơ


ԭӣhttps://my.oschina.net/funcy/blog/4773454 ߸ˮƽд֮ӭָԭףҵתϵ߻Ȩҵתע