docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(一):认识事务组件.md
ǰ spring aop عܺĽ spring aop һӦ
ʽǰ˼£Լ spring aop һƣʵأû springǵһ㳤
public void fun() {
//
start();
try {
// ҵ
xxx();
// ύ
commit();
} catch(Exception e) {
// ع
rollback();
throw e;
}
}
ĴύعҵأЩʹ spring aop ʵ֣˾ demo.
@Around עʵǿʹ @Around ע£
@MyTransactional@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyTransactional {
}
@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("ִк....");
}
}
}
@Configuration
@ComponentScan("org.springframework.learn.tx.demo02")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class TxDemo02Config {
}
@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
advisor ʵǻ spring aop @Around עĴʵ @Around ջװΪ InstantiationModelAwarePointcutAdvisorImpl Ĵ @Around ˣ@Around InstantiationModelAwarePointcutAdvisorImpl Ḷ́ɲο spring aop ֮ AnnotationAwareAspectJAutoProxyCreator ϣ.
InstantiationModelAwarePointcutAdvisorImpl ǸʲôأǸ advisor˵ǿڷǿ spring aop ҵӦڵǰ advisor ģɲο spring aop ֮ AnnotationAwareAspectJAutoProxyCreator £
ͨϷṩһ˼·ǿʵ advisor ӿڣƻԼ£
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("ִк....");
}
}
}
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);
}
}
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ͬעʵַʽĴעһˡ
@MyTransactional@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyTransactional {
}
@Configuration
@ComponentScan("org.springframework.learn.tx.demo01")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class TxDemo01Config {
}
@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
ǰС 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);
}
}
@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 ̡
@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Ǿࡣ
AutoProxyRegistrarAutoProxyRegistrar һעǵǰ 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 ע
InfrastructureAdvisorAutoProxyCreatorAspectJAwareAdvisorAutoProxyCreator xml aopAnnotationAwareAspectJAutoProxyCreatorע 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)
ProxyTransactionManagementConfigurationProxyTransactionManagementConfiguration ࡣǸࣺ
@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 transactionInterceptorProxyTransactionManagementConfiguration ̳ 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 ͿԽˣЩƪٷ
Ǵ 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 ߸ˮƽд֮ӭָԭףҵתϵȨҵתע