今天要记录的是最后两种组件注册的方式:
- Import
- FactoryBean
一、Import方式-快速导入组件
@Import是spring一种导入组件的方式,根据源码:
/**
* Indicates one or more {@link Configuration @Configuration} classes to import.
*
* <p>Provides functionality equivalent to the {@code <import/>} element in Spring XML.
* Allows for importing {@code @Configuration} classes, {@link ImportSelector} and
* {@link ImportBeanDefinitionRegistrar} implementations, as well as regular component
* classes (as of 4.2; analogous to {@link AnnotationConfigApplicationContext#register}).
*
* <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes should be
* accessed by using {@link org.springframework.beans.factory.annotation.Autowired @Autowired}
* injection. Either the bean itself can be autowired, or the configuration class instance
* declaring the bean can be autowired. The latter approach allows for explicit, IDE-friendly
* navigation between {@code @Configuration} class methods.
*
* <p>May be declared at the class level or as a meta-annotation.
*
* <p>If XML or other non-{@code @Configuration} bean definition resources need to be
* imported, use the {@link ImportResource @ImportResource} annotation instead.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.0
* @see Configuration
* @see ImportSelector
* @see ImportResource
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
* {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
* or regular component classes to import.
*/
Class<?>[] value();
}@Import可以用于:
- 导入拥有@Configuration注解的配置类,以及配置类中的bean
- 导入ImportSelector接口selectImports方法返回的相关bean
- 通过实现ImportBeanDefintionRegister接口来注册bean
- 直接导入几个普通类
主要做法,让我们来举几个栗子:
1. 导入一个配置类
//配置类
@Configuration
public class SpringPropertiesValueConfig {
@Bean
public Cat cat() {
return new Cat();
}
}在另一个配置类导入该配置类
@Configuration //告诉spring这是一个配置类
@Import(SpringPropertiesValueConfig.class)
public class SpringConfig {
}此时打印容器中所具有的bean
public class TestBean {
public static void main(String[] args) {
//通过注解的方式获取对应的bean
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
String[] beanNames = applicationContext.getBeanDefinitionNames();
for (String name : beanNames) {
System.out.println(name);
}
}
}运行结果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
springConfig
com.xyr.configure.SpringPropertiesValueConfig
cat
SpringPropertiesValueConfig及配置类中的cat都被注册到了容器中。
2. 实现ImportSelector接口
定义实现类
public class MyImportSelector implements ImportSelector {
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//返回要注入的bean集合
return new String[]{"com.xyr.model.YellowCar"};
}
}配置类
@Configuration //告诉spring这是一个配置类
@Import(MyImportSelector.class)
public class SpringConfig {
}再次调用之前的测试类,获取容器当中的bean,得到结果
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
springConfig
com.xyr.model.YellowCar3. 导入普通类
@Configuration //告诉spring这是一个配置类
@Import(BlueCar.class)
public class SpringConfig {
}此时运行结果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
springConfig
com.xyr.model.BlueCar
当然根据Import的源码可以发现,它也可以导入多个内容:
@Configuration //告诉spring这是一个配置类
@Import({BlueCar.class, RedCar.class})
public class SpringConfig {
}此时再次运行测试类:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
springConfig
com.xyr.model.BlueCar
com.xyr.model.RedCar
4. 实现ImportBeanDefinitionRegister接口
定义一个注册类,实现对应方法,AnnotationMetadata可以用于获取注解相关的信息,BeanDefinitionRegister可以获取到容器中注册的bean信息,也可以用于注册新的组件。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
*
* @param importingClassMetadata 当前配置文件的注解信息
* @param registry 组件定义注册 用于注册组件
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//判断RedCar、BlueCar是否在注册当中
boolean match1 = registry.containsBeanDefinition("com.xyr.model.RedCar");
boolean match2 = registry.containsBeanDefinition("com.xyr.model.BlueCar");
if (match1 && match2) {
//获取RainbowCar的定义
RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBowCar.class);
//注册需要的注解 指定bean名
registry.registerBeanDefinition("rainbowCar", beanDefinition);
}
}
}定义配置类,导入注册类:
@Configuration //告诉spring这是一个配置类
@Import({BlueCar.class, RedCar.class,MyImportBeanDefinitionRegistrar.class})
public class SpringConfig {}那么此时再运行测试类,得到结果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
springConfig
com.xyr.model.BlueCar
com.xyr.model.RedCar
rainbowCar
二、FactoryBean的使用
根据他的名字,工厂bean,用于生成某一类型的bean,和BeanFactory不一样,BeanFactory是spring的容器,适用于创建和管理bean的。
查看FactoryBean对应的源码:
public interface FactoryBean<T> {
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}其具有三个方法,可以用于获取对应的bean、获取bean的类型、获取是否为单例。这些都是在spring中注册一个bean所需要的信息。下面让我们来举个小栗子,来看看他是怎么注册一个bean的:
定义一个实现类
public class ColorCarFactorBean implements FactoryBean<ColorCar> {
public ColorCar getObject() throws Exception {
System.out.println("ColorCarFactorBean...getObject");
return new ColorCar();
}
public Class<?> getObjectType() {
return ColorCar.class;
}
public boolean isSingleton() {
return true;
}
}在配置类中注册该类:
@Configuration //告诉spring这是一个配置类
public class SpringConfig {
@Bean
public ColorCarFactorBean colorCarFactorBean() {
return new ColorCarFactorBean();
}
}运行测试类:
public class TestBean {
public static void main(String[] args) {
//通过注解的方式获取对应的bean
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
Object bean = applicationContext.getBean("colorCarFactorBean");
System.out.println(bean.getClass());
}
}可以发现获取到的是:
ColorCarFactorBean...getObject
class com.xyr.model.ColorCar
也就是说通过获取到的是colorCarFactorBean其getObject返回的bean。
而真正获取colorCarFactorBean对象的方式是通过如下方式进行获取:
public class TestBean {
public static void main(String[] args) {
//通过注解的方式获取对应的bean
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
Object bean = applicationContext.getBean("&colorCarFactorBean");
System.out.println(bean.getClass());
}
}此时获取到的内容为:
class com.xyr.model.ColorCarFactorBean