@Import 的作用?
1、初始化 Bean,将其添加至容器中
2、加载其他的@Configuration
3、指定实现 ImportSelector (以及 DefferredServiceImportSelector )的类,用于个性化加载
4、指定实现 ImportBeanDefinitionRegistrar 的类,用于个性化加载
注册 Bean 的几种方式
在 @Configuration 配置类中注册
1、包扫描:
@ComponentScan+ 组件注解:@Service、@Controller、Component、@Repository2、
@Bean3、
@Import4、FactoryBean 的
getObject()
这里介绍 @Import 方式
为什么要用 @Import ?
一般地,我们写代码时,想把谁扔到容器里交给 Spring 容器管理,直接在类上添加一个组件注解就完事了(如 @Controller ),那为什么要使用 @Import 呢?
直接@Component 他不香了吗?如果使用这个 @Import,反倒要多敲几个字母的代码?
@Import(User.class) // @Import 导入的默认是全限定类名
public class ConfigurationA {
}
原因是:
导入的组件不只有我们自己写的,有时候要添加第三方包中的类,但第三方包中的类却没标注有 “组件” 注解。这时候就要通过 @Import 注解来完成快速导入
当然地,使用 @Bean也能达到同样的效果,但要多写一个方法,而且这里先谈 @Import
用法一
直接根据类导入:XXX.Class
id 默认是全限定类名
我们看到,@Import 注解里的属性是一个类的集合,注解初始定义源码如下
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
Class<?>[] value();
}
所以说只需要在注解中添加上所需要添加至 Spring 容器的类即可
比如:
@Import(User.class)
public class ConfigurationA { }
这样子就能在容器中获取到这个 User 类的实例对象了
@Test
void testConfiguration() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ConfigurationB.class);
// 注意!这里一定要写全限定类名!
System.out.println(ac.getBean("com.gg.springboot.entity.User"));
}
注意的问题:
在使用
getBean()时,若要获取@Import注解导入的类,则需要写全限定类名!
用法二
使用 ImportSelector
源码注释有说明
1、创建 ImportSelector 的实现类并重写selectImports()方法
public class MyImportSelector implements ImportSelector {
/**
* @param importingClassMetadata : 当前标注了 @Import 注解的类的所有类信息,以及类上的其他注解信息
* @return 返回值,就是要导入容器中的 bean 的全限定类名
*/
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 这里可以写 @Configuration 修饰的类的全限定类名,也可以写普通实体类的全限定类名
return new String[]{"com.gg.springboot.entity.Car"};
}
}
2、@Import 注解引入此实现类
@Configuration
@Import({User.class, MyImportSelector.class}) // @Import 导入的默认是全限定类名
public class ConfigurationA { }
完工
应用场景
有没有很眼熟?没错,在 SpringBoot 的自动配置原理时有提到这个导入方式:SpringBoot自动配置原理解析
@EnableAutoConfiguration里面 Import 了一个 AutoConfigurationImportSelector 的类捋一捋这个类是怎么一回事,这个类的实现关系是这样子的
AutoConfigurationImportSelector ---实现---> DeferredImportSelector ---继承---> ImportSelector
然后再看看 AutoConfigurationImportSelector 方法的源码
// 有没有发现就是这个方法???
// 方法重写
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
// xxxxxxxxxxxxxxxx
}
用法三
使用 ImportBeanDefinitionRegistrar
源码注释有说明
1、创建 ImportBeanDefinitionRegistrar 的实现类并重写registerBeanDefinitions()方法
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// RootBeanDefinition 作为参数的作用:
// 1、指定类名。2、指定类的定义信息(Bean 的类型、scope 作用域等信息......)
registry.registerBeanDefinition("myCar",new RootBeanDefinition(Car.class));
}
}
2、@Import 注解引入此实现类
@Configuration
@Import({MyImportBeanDefinitionRegistrar.class}) // @Import 导入的默认是全限定类名
public class ConfigurationA {
}
应用场景(挖个坑)
SpringBoot 源码中常用