FactoryBean注册组件
文章目录
前面我们了解了三种注册组件的方式, 现在又有了一种方式: FactoryBean注册组件:
- 包扫描 + 组件标注注解
- @Bean注解导入
- @Import注解导入
- FactoryBean注册组件
1. 创建实体类:
package com.ffyc.spring.model;
public class Dog {
}
2. 自定义一个DogFactoryBean, 实现FactoryBean接口
package com.ffyc.spring.model;
import org.springframework.beans.factory.FactoryBean;
public class DogFactoryBean implements FactoryBean<Dog> {
// public DogFactoryBean() {
// System.out.println("哈哈哈");
// }
//返回一个Dog对象, 这个Dog对象会添加到容器中
public Dog getObject() throws Exception {
System.out.println("嘿嘿嘿");
return new Dog();
}
public Class<?> getObjectType() {
return Dog.class;
}
//控制bean是否为单例
/*
1. true : 是单例, 在容器中保存一份
2. false : 是多实例的, 每次获取都会创建一个实例(就是调用BeanFactory的getObject()方法)
*/
public boolean isSingleton() {
return false;
}
}
FactoryBean接口的泛型就是我们要创建的Bean的类型
3. 创建一个配置类, 配置类中闯将DogFactoryBean实例
package com.ffyc.spring.config;
import com.ffyc.spring.condition.LinuxCondition;
import com.ffyc.spring.condition.MyImportBeanDefinitionRegister;
import com.ffyc.spring.condition.MyImportSelector;
import com.ffyc.spring.condition.WindowsCondition;
import com.ffyc.spring.controller.MyTypeFilter;
import com.ffyc.spring.model.DogFactoryBean;
import com.ffyc.spring.model.Person;
import com.ffyc.spring.model.Red;
import org.springframework.context.annotation.*;
@Configuration
//@ComponentScan(value = "com.ffyc.spring" , excludeFilters = {
// @ComponentScan.Filter(classes = Controller.class)
//})
//@ComponentScan(value = "com.ffyc.spring", includeFilters = {
// @ComponentScan.Filter(classes = Controller.class)
//}, useDefaultFilters = false)
@ComponentScan(value = "com.ffyc.spring")
@Import({Red.class, MyImportSelector.class, MyImportBeanDefinitionRegister.class})
public class PersonConfig {
@Bean
public DogFactoryBean dogFactoryBean() {
return new DogFactoryBean();
}
}
4. 测试:
package com.ffyc.spring.test;
import com.ffyc.spring.config.PersonConfig;
import com.ffyc.spring.model.Dog;
import com.ffyc.spring.model.DogFactoryBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test5 {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(PersonConfig.class);
System.out.println(annotationConfigApplicationContext.getBean(DogFactoryBean.class));
System.out.println(annotationConfigApplicationContext.getBean(Dog.class));
System.out.println(annotationConfigApplicationContext.getBean("dogFactoryBean").getClass());
}
}
我们虽然在配置类中创建的是DogFactoryBean类型的实例, 但是我们从IOC容器中获取名为dogFactoryBean的实例的时候调用getClass()方法可以发现获取到的该实例却是一个Dog类型对象
其实是会创建DogFactoryBean实例到IOC容器中, 但是我们每次使用IOC容器通过getBean()方法获取的时候如果不加前缀&, 那么就在底层会调用getObject()方法返回一个Dog类型实例, 如果是单例, 那么会在第一次调用getObject()方法之后将该单例放到IOC容器中, 然后下次获取的时候直接从IOC容器的单例Map中获取即可
- 如果你的FactoryBean中的isSingleton方法返回值为false, 那么就是创建多实例bean, 那么每使用IOC容器获取一次实例, 就创建一个Dog实例
5.测试(扩展 : 获取DogFactoryBean实例)
package com.ffyc.spring.test;
import com.ffyc.spring.config.PersonConfig;
import com.ffyc.spring.model.DogFactoryBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test5 {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(PersonConfig.class);
System.out.println(annotationConfigApplicationContext.getBean(DogFactoryBean.class));
System.out.println(annotationConfigApplicationContext.getBean("&dogFactoryBean").getClass());
}
}
分为以下情况: DogFactoryBean implements FactoryBean< Dog>:
- getBean(“DogFactoryBean id名”) : 获取到的是Dog类型实例
- getBean(Dog.class) : 获取到的是Dog类型实例
- getBean(“& + DogFactoryBean id名”) : 获取到的是DogFactoryBean类型实例
- getBean(DogFactoryBean.class) : 获取到的是DogFactoryBean类型实例
那么在bean id前面加一个&表示什么?
- 该符号其实是定义在BeanFactory类源码中的:
public interface BeanFactory {
/**
* Used to dereference a {@link FactoryBean} instance and distinguish it from
* beans <i>created</i> by the FactoryBean. For example, if the bean named
* {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
* will return the factory, not the instance returned by the factory.
*/
String FACTORY_BEAN_PREFIX = "&";
...
}