前言
在日常利用SpringBoot开发的过程中,我们开发的Bean大部分都是依赖于spring容器进行管理,这样很方便日常Bean的注入。
大家都知道对象的创建必须通过构造方法创建,构造方法分为两种,一种时无参(此方法只是创建了个空对象,后续使用属性时还需要set/get),另外一种时重载的有参构造器(此方法创建后的对象,对于已经赋值的属性当然可以立马使用),所以Spring在创建Bean的时候也无非就这两种(默认时无参构造创建),基于spring体系的疮痈创建Bean注解有:比如@Configuration里的@Bean,比如@Component,如果是spring mvc的话,还有一些专用的@Controller,@Service,@Repository。
引入
那么,使用spring boot时,如果想自己实现一些初始设置比较复杂的bean时,可以在类上用@Configuration注解,然后类内部在返回具体bean的方法上使用@Bean注解。
那么,要让容器找到这个配置类,并让容器进行管理的话,方法有这么几种:
方法一:@ComponentScan注解
将配置类放到@ComponentScan注解所指定的package里。
以下是截取springboot Guide中的一段话:
方法二:使用@Import注解
首先,@Import是spring中的内置注解,所以spring会对此注解进行管理。
这个注解的主要用途截取spring的源码说明,然后逐一讲解:
a.允许使用@Configuration注解的类
这个比较简单,如果明确知道需要引入哪个配置类,直接引入就可以。
b.允许是实现ImportSelector接口的类
如果并不确定引入哪个配置类,需要根据@Import注解所标识的类或者另一个注解(通常是注解)里的定义信息选择配置类的话,用这种方式。
比较典型的是注解@EnableTransactionManagement
java代码:
@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 2147483647;
}
是通过TransactionManagementConfigurationSelector类,根据注解@EnableTransactionManagement所指定的AdviceMode来选择使用哪个配置类的。
java代码:
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:
return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
c.允许是实现了ImportBeanDefinitionRegistrar接口的类
一般只要用户确切的知道哪些bean需要放入容器的话,自己便可以通过spring boot里所提供的注解来标识了,比如@Configuration里的@Bean,比如@Component,如果是spring mvc的话,还有一些专用的@Controller,@Service,@Repository。
但是,如果是第三方包,而且又不是确定的类,并且这些类并不是spring专用,所以不想用spring的注解进行侵入式标识,那么如果找到这些类放到spring的容器呢?
这时候就用到了用注解@Import引入ImportBeanDefinitionRegistrar子类的方式,最典型的应用就是mybatis,使用工具自动生成了一批mapper和entity,而如何把这些普通的类放入容器,就是通过注解
典型代表@MapperScan
java代码:
@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下所有的类,并放入容器中。
d.正如源码中的备注一样,"as well as regular component",说明,Import可以像类似于@Component此功能的注解一样,在容器启动的时候将此类定义为一个bean,并将此bean交于容器管理,但此用法较少。