springBoot如何加载类(以atomikos框架中的事务类为例)
最近在研究多数据源事务框架atomikos如何使用,但是很容易和单数据源事务框架发生加载冲突。于是就研究了一下springBoot如何加载类。
springBoot加载步骤。
一、自动装配入口
spring-boot-autoconfigure.jar/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 这个文件中加载所有的Configuration。
二、以TransactionAutoConfiguration类为例
这个类中有3个注解:
@AutoConfiguration(after = { JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class })
@ConditionalOnClass(PlatformTransactionManager.class)
@EnableConfigurationProperties(TransactionProperties.class)
public class TransactionAutoConfiguration {
...
}
@AutoConfiguration:声明当前类是一个自动装配类,并且在指定它必须在某些其他自动装配类加载完成之后才会执行。
@ConditionalOnClass:如果类路径下是否存在PlatformTransactionManager类。如果存在那么加载被注解的配置或Bean,否则不加载。很显然PlatformTransactionManager类是springBoot基础包中的类,所以当前类一定被加载。
@EnableConfigurationProperties:一般来说TransactionProperties类上方还有一个注解@ConfigurationProperties(prefix = "spring.transaction")用于定义类字段和配置文件的映射。@EnableConfigurationProperties用于激活属性绑定,并注册属性类为 Bean。在其他类中可以直接引用注入,比如:
@Autowiredprivate TransactionProperties properties; // 直接注入配置
按照加载顺序,需要先加载after后面的类,以JtaAutoConfiguration类为例继续。
三、以JtaAutoConfiguration类为例
@AutoConfiguration(before = { XADataSourceAutoConfiguration.class, ActiveMQAutoConfiguration.class,ArtemisAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
@ConditionalOnClass(javax.transaction.Transaction.class)
@ConditionalOnProperty(prefix = "spring.jta", value = "enabled", matchIfMissing = true)
@Import({ JndiJtaConfiguration.class, AtomikosJtaConfiguration.class })
public class JtaAutoConfiguration {}
从代码中可以看出加载这个类的条件是:类路径下存在Transaction类,并且spring.jta.enabled=true或者没有这个配置。
所有JtaAutoConfiguration类一定会被加载。
这个类在加载的同时还加载了这两个类:
JndiJtaConfiguration 和 AtomikosJtaConfiguration
四、以AtomikosJtaConfiguration类为例
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ AtomikosProperties.class, JtaProperties.class })
@ConditionalOnClass({ JtaTransactionManager.class, UserTransactionManager.class })
@ConditionalOnMissingBean(org.springframework.transaction.TransactionManager.class)
class AtomikosJtaConfiguration {@Bean(initMethod = "init", destroyMethod = "shutdownWait")@ConditionalOnMissingBean(UserTransactionService.class)UserTransactionServiceImp userTransactionService(AtomikosProperties atomikosProperties,JtaProperties jtaProperties) {Properties properties = new Properties();if (StringUtils.hasText(jtaProperties.getTransactionManagerId())) {properties.setProperty("com.atomikos.icatch.tm_unique_name", jtaProperties.getTransactionManagerId());}properties.setProperty("com.atomikos.icatch.log_base_dir", getLogBaseDir(jtaProperties));properties.putAll(atomikosProperties.asProperties());return new UserTransactionServiceImp(properties);}
........
}
加载这个自动装配类的条件是:类路径中存在这两个类:JtaTransactionManager和UserTransactionManager,并且spring容器中没有 TransactionManager对象。
加载类时,也根据配置信息实例化了AtomikosProperties和JtaProperties。
自动装配时会实例化UserTransactionServiceImp类,同时会调用这个类的init()方法。在这个方法中就能看到相应的业务逻辑了。
五、其他疑问
Q:AtomikosJtaConfiguration类是springBoot基础包中的类,却引入了atomikos jar中的类(比如:UserTransactionManager)。如果我的项目中只引入了springBoot基础包,但是没有引入atomikos jar,我的项目为什么没有编译报错?
A:自动配置类通常通过 @ConditionalOnClass
注解来控制是否生效。如果项目中未引入 Atomikos 相关的依赖, @ConditionalOnClass
会阻止该配置类的加载。
Q:编译时为什么没有报错?
A:编译时,Java 编译器只会检查类路径中是否存在类的引用,但不会强制要求所有引用的类都必须存在。
运行时,如果尝试加载一个不存在的类,才会抛出 ClassNotFoundException
。