谈谈spring boot里的@import

使用spring boot时,如果想自己实现一些初始设置比较复杂的bean时,可以在类上用@Configuration注解,然后类内部在返回具体bean的方法上使用@Bean注解。

那么如何让容器找到这个配置类呢?

1.最简单的方法,当然是把它放到程序可以扫描到的package里,也就是@ComponentScan注解所指定的package里。

   平时自己创建的配置类通常用这种方法,简单明了。

2.如果没有在package扫描路径里,比如引入的第三方包,可以通过META-INF/spring.factories里用org.springframework.boot.autoconfigure.EnableAutoConfiguration来制定。

   spring-boot-autoconfigure包里的配置类都是通过这种方式引入的。

   当然,这个方式需要程序使用@EnableAutoConfiguration注解,这个注解是通过AutoConfigurationImportSelector来扫描spring.factories文件,把定义的配置类引入的。

3.使用@Import注解

   这个注解可以引入三种类

   a.使用了@Configuration注解的类

       这个比较简单,如果明确知道需要引入哪个配置类,直接引入就可以。

   b.ImportSelector的子类

       如果并不确定引入哪个配置类,需要根据@Import注解所标识的类或者另一个注解(通常是注解)里的定义信息选择配置类的话,用这种方式。

       实际上上面2种所描述的AutoConfigurationImportSelector就是用的这种方式。

       另外一个比较典型的是注解@EnableTransactionManagement

       

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
	boolean proxyTargetClass() default false;
	AdviceMode mode() default AdviceMode.PROXY;
	int order() default Ordered.LOWEST_PRECEDENCE;

}

      是通过TransactionManagementConfigurationSelector类,根据注解@EnableTransactionManagement所指定的AdviceMode来选择使用哪个配置类的。

     

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
			default:
				return null;
		}
	}

}

   c.ImportBeanDefinitionRegistrar的子类。

      这个其实跟注解@Configuration没啥关系了,因为是注解@Import的功能,所以就放在这儿一并说了。

      一般只要用户确切的知道哪些bean需要放入容器的话,自己便可以通过spring boot里所提供的注解来标识了,比如@Configuration里的@Bean,比如@Component,如果是spring mvc的话,还有一些专用的@Controller,@Service,@Repository。

      但是,如果是第三方包,而且又不是确定的类,并且这些类并不是spring专用,所以不想用spring的注解进行侵入式标识,那么如果找到这些类放到spring的容器呢?

      这时候就用到了用注解@Import引入ImportBeanDefinitionRegistrar子类的方式,最典型的应用就是mybatis,使用工具自动生成了一批mapper和entity,而如何把这些普通的类放入容器,就是通过注解@MapperScan

     

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {
  String[] value() default {};
  String[] basePackages() default {};
  Class<?>[] basePackageClasses() default {};
  Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
  Class<? extends Annotation> annotationClass() default Annotation.class;
  Class<?> markerInterface() default Class.class;
  String sqlSessionTemplateRef() default "";
  String sqlSessionFactoryRef() default "";
  Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;

}

      这个注解用@Import引入了MapperScannerRegistrar类,这个类里会取得注解@MapperScan作设置的package,然后扫描这个package下所有的类,并放入容器中。

      代码就不贴了,有兴趣可以自行查看。

根据上面的描述,可以看出,如果不是制作模块,只是使用的话,通常用第一种就可以了,如果是制作第三方包,并且根据需求想更加灵活的把bean注册到容器的话,可以考虑其它方式。

上一篇文章Spring boot + doma2里所述doma-gen所生成的类没有办法自动注册,其实可以考虑实现ImportBeanDefinitionRegistrar的一个子类来解决这个问题。

猜你喜欢

转载自weiqingfei.iteye.com/blog/2361152