Springソースコードを理解する(21):物事の初期化プロセスのためのアノテーション構成方法

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

これAutoProxyRegistrarImportBeanDefinitionRegistrarインターフェース実装し、注入します:

  • InfrastructureAdvisorAutoProxyCreator:AbstractAdvisorAutoProxyCreatorAOPプロキシオブジェクトの作成に使用されるから継承されます。

その中にProxyTransactionManagementConfigurationは、@Configuration3つの重要なクラスをインポートする変更された構成クラスがあります。

  • TransactionAttributeSource:トランザクションアノテーション属性を解析するために使用されます
  • TransactionInterceptor:メソッドインターセプターを実装するトランザクションインターセプターMethodInterceptor
  • BeanFactoryTransactionAttributeSourceAdvisor:AOP拡張通知機能

1.4、@ Beanの解析

インジェクションDataSourceJdbcTemplateBookDaoBookServiceDataSourceTransactionManager

TransactionConfig構成クラスを解析した後、次のBeanDefinitionをBeanDefinitionMapに挿入します。

ここに画像の説明を挿入します

2.構成クラスCGLIBを拡張します

TransactionConfigプロキシクラス作成する主な目的、@ Beanによってインポートされたクラスのシングルトンを確保することです。

3、InfrastructureAdvisorAutoProxyCreatorをインスタンス化します

ではregisterBeanPostProcessors(beanFactory);この方法は主に、注射に注入され、ここでビーンバックをインスタンス化するために使用される初期化の前に初期化!BeanDefinitionMapBeanPostProcessor

この例では、次の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()BeanFactoryTransactionAttributeSourceAdvisorBeanFactoryTransactionAttributeSourceAdvisorProxyTransactionManagementConfiguration

以来BeanFactoryTransactionAttributeSourceAdvisorファクトリメソッドは、パラメータの依存関係を持って、それが作成し、依存関係を注入する必要があるTransactionAttributeSourceTransactionInterceptor

パラメータの準備ができたら、最後にリフレクションを使用して作成しますBeanFactoryTransactionAttributeSourceAdvisor

2.プロキシクラスの作成

クラスのすべてのインスタンスはメソッドInfrastructureAdvisorAutoProxyCreatorpostProcessAfterInitialization()途中を通過しwrapIfNecessary()プロキシクラスを作成する必要があるかどうかを判断します。

ここでは、唯一する必要が作成bookServiceし、bookDaoプロキシクラスの作成のために物事を:

ここに画像の説明を挿入します

五数要約

ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/u013277209/article/details/114886302
おすすめ