1つ、準備例
BookDao.java
public class BookDao {
@Autowired
JdbcTemplate jdbcTemplate;
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
/**
* 减去某个用户的余额
* @param userName
* @param price
*/
@Transactional(propagation = Propagation.SUPPORTS)
public void updateBalance(String userName,int price){
String sql = "update account set balance=balance-? where username=?";
jdbcTemplate.update(sql,price,userName);
}
/**
* 按照图书的id来获取图书的价格
* @param id
* @return
*/
@Transactional(propagation = Propagation.REQUIRED)
public int getPrice(int id){
String sql = "select price from book where id=?";
return jdbcTemplate.queryForObject(sql,Integer.class,id);
}
/**
* 减库存,减去某本书的库存
* @param id
*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateStock(int id){
String sql = "update book_stock set stock=stock-1 where id=?";
jdbcTemplate.update(sql,id);
}
}
BookService.java
public class BookService {
@Autowired
BookDao bookDao;
public BookDao getBookDao() {
return bookDao;
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
/**
* 结账:传入哪个用户买了哪本书
* @param username
* @param id
*/
@Transactional(propagation = Propagation.REQUIRED)
public void checkout(String username,int id){
// 减库存
bookDao.updateStock(id);
// 获取图书价格
int price = bookDao.getPrice(id);
// 更新余额
bookDao.updateBalance(username,price);
}
}
TransactionConfig.java
@Configuration
@PropertySource("classpath:dbconfig.properties")
@EnableTransactionManagement
public class TransactionConfig {
@Value("${jdbc.driverClassName}")
private String driverClassname;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource() {
DruidDataSource data = new DruidDataSource();
data.setDriverClassName(driverClassname);
data.setUrl(url);
data.setUsername(username);
data.setPassword(password);
return data;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean
public BookDao bookDao() {
return new BookDao();
}
@Bean
public BookService bookService() {
bookDao();
return new BookService();
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
TransactionTest.java
public class TransactionTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TransactionConfig.class);
BookService bean = applicationContext.getBean(BookService.class);
bean.checkout("小明",1);
}
}
次に、構成構成クラスを解決します
AnnotationConfigApplicationContext
コンテナを作成するときに、いくつかの内部クラスが挿入されます(前述、ここで説明します)。
- ConfigurationClassPostProcessor:@configurationアノテーション(BFPP)のポストプロセッサーを処理するために使用されるBean
- AutowiredAnnotationBeanPostProcessor:@ Autowired、@ Value、@ Inject、および@Lookupアノテーションを処理するためのポストプロセッサBean(BPP)
- CommonAnnotationBeanPostProcessor:
@Resource,@PostConstruct,@PreDestroy
ポストプロセッサBean(BPP)などのJSR-250アノテーションを処理するために使用されます - EventListenerMethodProcessor:@EventListenerアノテーション(BFPP)のポストプロセッサーを処理するために使用されるBean
- DefaultEventListenerFactory:ApplicationListenerオブジェクトの生成に使用されるEventListenerFactoryオブジェクト
注入後、我々はなりますinvokeBeanFactoryPostProcessors(beanFactory)
方法を実行ConfigurationClassPostProcessor
コンフィギュレーションクラスの構成に解析
し、CGLIB增强
1.構成クラスの分析
@Configuration
@PropertySource("classpath:dbconfig.properties")
@EnableTransactionManagement
public class TransactionConfig {
@Value("${jdbc.driverClassName}")
private String driverClassname;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource() {
DruidDataSource data = new DruidDataSource();
data.setDriverClassName(driverClassname);
data.setUrl(url);
data.setUsername(username);
data.setPassword(password);
return data;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean
public BookDao bookDao() {
return new BookDao();
}
@Bean
public BookService bookService() {
bookDao();
return new BookService();
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
1.1、分析@Component
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@Configuration
注釈は注釈を継承するため、@Component
解析する必要があります。
これは主に内部クラスの分析を完了するためです。構成クラスは構成クラスの内部クラスを持つこともできるため、内部クラスの構成クラスを再帰的に分析する必要があります。
次のように:
@Configuration
public class A {
@Configuration
class B{
@Configuration
class C{
}
}
}
1.2、分析@PropertySource("classpath:dbconfig.properties")
解析dbconfig.properties
して、解析したkey,value
キーと値のペアをpropertySourceList
その中に入れます。
後でインスタンス化されるときに、populateBean()
メソッドのプロパティに値を割り当てます。
1.3、分析@Import
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
あるため@EnableTransactionManagement
、@Import
解析する必要があります。
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
/**
* 此处是AdviceMode的作用,默认是用代理,另外一个是ASPECTJ
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {
AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {
determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
ことがわかったTransactionManagementConfigurationSelector
クラスが実装ImportSelector
インターフェイスを、次に実行するselectImports()
方法のインポートをAutoProxyRegistrar
し、ProxyTransactionManagementConfiguration
これAutoProxyRegistrar
はImportBeanDefinitionRegistrar
インターフェースを実装し、注入します:
- InfrastructureAdvisorAutoProxyCreator:
AbstractAdvisorAutoProxyCreator
AOPプロキシオブジェクトの作成に使用されるから継承されます。
その中にProxyTransactionManagementConfiguration
は、@Configuration
3つの重要なクラスをインポートする変更された構成クラスがあります。
- TransactionAttributeSource:トランザクションアノテーション属性を解析するために使用されます
- TransactionInterceptor:メソッドインターセプターを実装するトランザクションインターセプターMethodInterceptor
- BeanFactoryTransactionAttributeSourceAdvisor:AOP拡張通知機能
1.4、@ Beanの解析
インジェクションDataSource
、JdbcTemplate
、BookDao
、BookService
、DataSourceTransactionManager
TransactionConfig
構成クラスを解析した後、次のBeanDefinitionをBeanDefinitionMapに挿入します。
2.構成クラスCGLIBを拡張します
TransactionConfig
プロキシクラスを作成する主な目的は、@ Beanによってインポートされたクラスのシングルトンを確保することです。
3、InfrastructureAdvisorAutoProxyCreatorをインスタンス化します
ではregisterBeanPostProcessors(beanFactory);
この方法は主に、注射に注入され、ここでビーンバックをインスタンス化するために使用される初期化の前に初期化!BeanDefinitionMap
BeanPostProcessor
この例では、次の3つのBeanPostProcessorがインスタンス化されています。
- internalAutowiredAnnotationProcessor:AutowiredAnnotationBeanPostProcessor、@ Autowired、@ Value、@ Inject、および@Lookupアノテーション付きポストプロセッサBean(BPP)の処理に使用されます
- internalCommonAnnotationProcessor:CommonAnnotationBeanPostProcessor、
@Resource,@PostConstruct,@PreDestroy
ポストプロセッサBean(BPP)などのJSR-250アノテーションを処理するために使用されます - internalAutoProxyCreator:InfrastructureAdvisorAutoProxyCreator、プロキシオブジェクトの作成に使用
4、インスタンス化
1、BeanFactoryTransactionAttributeSourceAdvisorの作成
これは、作成される中での方法ではInfrastructureAdvisorAutoProxyCreator
、初めてそれがあるため、工場出荷時のFactoryBeanのは、インスタンス化されている、最初にインスタンス化されなければならないので、豆の注釈付きのファクトリメソッドです。postProcessAfterInitialization()
wrapIfNecessary()
BeanFactoryTransactionAttributeSourceAdvisor
BeanFactoryTransactionAttributeSourceAdvisor
ProxyTransactionManagementConfiguration
以来BeanFactoryTransactionAttributeSourceAdvisor
ファクトリメソッドは、パラメータの依存関係を持って、それが作成し、依存関係を注入する必要があるTransactionAttributeSource
とTransactionInterceptor
パラメータの準備ができたら、最後にリフレクションを使用して作成しますBeanFactoryTransactionAttributeSourceAdvisor
2.プロキシクラスの作成
クラスのすべてのインスタンスはメソッドInfrastructureAdvisorAutoProxyCreator
のpostProcessAfterInitialization()
途中を通過し、wrapIfNecessary()
プロキシクラスを作成する必要があるかどうかを判断します。
ここでは、唯一する必要が作成bookService
し、bookDao
プロキシクラスの作成のために物事を: