注册Bean到IOC容器大致分为4种:
①、包扫描+组件注解(@Controller、@Service、@Repository、@Component)
针对类是我们自己编写的情况
②、@Bean注解
针对导入第三方包里面的类的情况
③、@Import
针对快速导入某一个类的情况,如仅仅只是调用无参构造创建对象。
1)@Import注解直接导入
2)ImportSelector手动导入Bean到容器中
3)ImportBeanDefinitionRegistrar手动注册bean到容器中
④、FactoryBean(Bean工厂)
- 默认获取到的是工厂bean调用getObject方法创建的对象
- 要获取工厂bean本身,我们需要给id前面加一个&
(&FactoryBean)
实战过Spring的人来说,前两种方式可谓是最常见不过了。而后两种方式在开发中比较少见,因此本文主要介绍@Import
和FactoryBean
这两种方式。
@Import方式
@Import注解源码:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
Class<?>[] value();
}
通过源码我们可以发现,@Import注解只能放置在类上,并且有一个value属性,是一个Class类型的数组,我们将需要导入到IOC容器的Bean的字节码放置这个数组中,spring容器就会通过反射创建对象到ioc容器中。
—测试
—配置类
@Configuration
@Import({Color.class, Red.class})
public class SpringConfig {
}
—单元测试
@Test
public void testApplicationContext2() {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
String[] names = context.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
—测试结果
ImportSelector方式
ImportSelect是一个接口,接口中有一个抽象方法selectImports,返回值为一个String数组,
spring会自动将返回的String数组中的类创建对象到ioc容器中去。
—MyImportSelector代码
public class MyImportSelector implements ImportSelector {
// 返回值就是导入到容器中的组件的全类名
// AnnotationMetadata:封装了当前标注@Import注解的类的所有注解信息
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"org.cjw.pojo.Blue", "org.cjw.pojo.Yellow"};
}
}
—配置类
@Configuration
@Import({Color.class, Red.class, MyImportSelector.class})
public class SpringConfig {
}
—单元测试
同上
—测试结果
ImportBeanDefinitionRegistrar
这种方式和ImportSelector方式很类似,都是实现一个接口,然后在重写的方法中编写bean的导入规则。
—MyImportBeanDefinitionRegistrar代码
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
// 编写注册判断规则
// 指定Bean的类型,作用域等等
RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
// 注册一个bean到ioc容器中,并指定beanName
beanDefinitionRegistry.registerBeanDefinition("rainBow", beanDefinition);
}
}
—配置类
@Configuration
@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class SpringConfig {
—单元测试
同上
—测试结果
FactoryBean
FactoryBean是一个接口,我们需要编写一个类实现它,并重写getObject
、getObejctType
、isSingleton
方法。
- getObject:IOC容器会执行此方法得到Bean,并放到IOC容器中去。
- getObjectType:获取Bean的类型。
- isSingleton:设置Bean是否为单例,返回值为true为单例,false为多例,ioc容器不管理多例的Bean,只负责创建。
Spring与其他框架进行整合的时候使用的就是FactoryBean来创建对象到IOC容器中。
—ColorFactoryBean代码
public class ColorFactoryBean implements FactoryBean<Green> {
@Override
public Green getObject() throws Exception {
return new Green();
}
@Override
public Class<?> getObjectType() {
return Green.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
—SpringConfig代码
@Configuration
public class SpringConfig {
@Bean
public ColorFactoryBean colorFactoryBean() {
return new ColorFactoryBean();
}
}
—单元测试
@Test
public void testApplicationContext2() {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
Object bean = context.getBean("colorFactoryBean");
System.out.println(bean);
System.out.println(bean.getClass());
}
—测试结果
通过结果我们可以发现,ioc容器确实有ColorFactoryBean这个对象,但是这个对象的本质是一个Green,即是我们需要创建到ioc容器中的bean。因此我们可以得出结论,只要实现了FactoryBean接口的类,spring都会执行它的getObject方法,将创建的对象放入到ioc容器中,spring和第三方框架的整合靠的就是FactoryBean。
更多详细内容下一节详细介绍