众所周知,在spring内部,所有的bean都是交由spring来统一管理的,有些bean可能是直接通过BeanDefinitionRegistry定义的,有些是通过FactoryBean注册的(一般用作其他框架与spring整合)
以springboot为例,当一个配置类需要导入另外一个组件的时候,可以使用上面的方式进行导入。当然,spring为我们提供了一系列的注解,在引入其他组件的时候,可以使用@Import注解: 下面是Import注解的源码:
点开@Import注解源码,可以看到
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
* 除了直接在配置类上,还可以实现ImportSelector ,ImportBeanDefinitionRegistrar接口
* {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
*/
Class<?>[] value();
}
看了上面的源码之后,我们现在有了三种选择,分别是下面的三种引入方式
@Import(value = {UserInput.class})
public class MovieApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(MovieApplication.class, args);
}
}
package org.choviwu.movie.config;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotationMetadata;
public class MovieImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//注册一个字符串数组(数组格式为类的全路径),数组不能为null
return new String[]{"org.choviwu.movie.model.Articles"};
}
}
package org.choviwu.movie.config;
public class MovieImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
//利用bean定义注册类注册,可以进行bean的别名设置
boolean flagArticle = registry.containsBeanDefinition("org.choviwu.movie.model.Articles");
if(!flagArticle) {
BeanDefinition definition = new RootBeanDefinition(Articles.class);
registry.registerBeanDefinition("articles",definition);
}
}
}
package org.choviwu.movie.config;
import org.choviwu.movie.model.Config;
import org.springframework.beans.factory.FactoryBean;
//这种方式适合框架与spring整合
public class MovieFactoryBean implements FactoryBean<Config> {
//这个方法是创建定义bean,也是实际执行的方法
@Override
public Config getObject() throws Exception {
Config config = new Config();
return config;
}
//类的类型
@Override
public Class<?> getObjectType() {
return Config.class;
}
//单例模式
@Override
public boolean isSingleton() {
return true;
}
}
编写main方法,执行定义的bean
package org.choviwu.movie;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
@SpringBootApplication
//这里分别引入了上面的三种组件方式
@Import(value = {UserInput.class,
MovieImportSelector.class,
MovieImportBeanDefinitionRegistrar.class})
//
public class MovieApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(MovieApplication.class, args);
UserInput us = context.getBean(UserInput.class);
UserInput us2 = context.getBean(UserInput.class);
Articles articles= context.getBean(Articles.class);
//这里返回的是实际注册的对象,也就是getObject的返回值
Object obj = context.getBean("movieFactoryBean");
//这里返回一个movieFactoryBean对象,为什么加&符号呢? 可以查看BeanFactory源码查看定义
Object obj2 = context.getBean("&movieFactoryBean");
System.out.println(us==us2);
System.out.println(articles);
System.out.println(obj);
System.out.println(obj2);
}
//第四种方式,实现工厂bean方式,
@Bean
public MovieFactoryBean movieFactoryBean(){
return new MovieFactoryBean();
}
@Bean
public UserInput userInput(){
System.out.println(".........................................啊");
return new UserInput();
}
}
执行main方法结果如下:
true
org.choviwu.movie.model.Articles@138aa3cc
org.choviwu.movie.model.Config@5382184b
org.choviwu.movie.config.MovieFactoryBean@36417a54