FactoryBean不是注解,但是使用它可以直接向容器中注册bean,所以这里也介绍一下
这里直接上例子,然后通过例子来讲解其实用。
例子
首先创建FactoryBean的实现类
// 这个类就不单独占用地方了,就写在这里了
public class Animal {
}
public class AnimalFactoryBean implements FactoryBean<Animal> {
// 当调用getBean这样的方法从容器中后去bean时,就会调用这个方法
// 非单例模式下调用getBean时,就会执行这个方法来创建bean
// 单例模式下,会先先调用这个方法生成bean,然后放到容器中,在调用getBean时直接从容器中拿,因为不会在调用这个方法,多以就是单例了
@Override
public Animal getObject() throws Exception {
System.out.println("获取bean....");
return new Animal();
}
@Override
public Class<?> getObjectType() {
return Animal.class;
}
// 设置是否为单例,true:单例,容器中是保存一份;false:非单例,每次获取时都创建一个新的实例
@Override
public boolean isSingleton() {
return true;
}
}
然后,在配置类中将FactoryBean的实现类生成的bean放到容器中
@Configuration // 相当于写了一个spring的xml配置文件
public class MyConfig {
// 创建一个FactoryBean,虽然是将AnimalFactoryBean放到了容器中,但是当调用getBean时,获取的不是AnimalFactoryBean,而是会调用AnimalFactoryBean中的getObject方法生成的bean。具体看main方法给出的注释。
@Bean
public AnimalFactoryBean animalFactoryBean(){
return new AnimalFactoryBean();
}
}
最后,从容器中获取bean,这里注意观察截图中【1】【2】标注,下面会有解说
public class AppliactionRunner {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
String[] names = applicationContext.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name); //【1】打印出容器中所有的bean名字,
}
//【2】getBean时会调用容器中animalFactgoryBean的getObjec,然后返回方法中生成的对象
Object animalFactgoryBean = applicationContext.getBean("animalFactoryBean");
System.out.println("bean的类型" + animalFactgoryBean.getClass());
}
}
运行结果:
上面我们就完成了一个FactoryBean的使用。它的作用就是可以让我们自定义bean的创建过程,如下场景:
//Animal是个接口
@Override
public Animal getObject() throws Exception {
// return的都是Animal的实现类
if(今天周一){
return new 小狗();
}
if(今天周二){
return new 小猫();
}
}
这样我们就可以自定义bean的创建过程,根据条件返回不同的bean,当然必须是返回一个接口的实现类才行。然后当调用getBean的时候,就可以获取到这里根据业务返回的不同的实现类了,然后再用接口接收一下就行了。
另外,大家可能注意到打印结果和main方法中标注了【1】【2】两个地方,这也是使用FactoryBean的要注意的地方。下面我说明一下:
当在配置类通过@Bean向容器放入我们写的FactoryBean的实现类后,这个Bean会被放到容器中,这个通过【1】处的打印可得知。但是,当我们通过getBean获取这个bean时,有意思的事情发生了,注意观察【2】打印的结果,这个我们获取到的bean确实Animal这个类,这就是FactoryBean的特点和作用,虽然放到容器中的时FactoryBean的实现了,但是当getBean获取bean时,会调用这个实现类中的getObject方法,然后把里面return的对象返回。这个一定要记住昂。
那么有人会说,如果我就想用getBean获取FactoryBean的实现类,也就是我们例子中的AnimalFactoryBean的对象怎么办呢,其实很简单,方法如下:
// 将【2】改成这么写就行,加个&就行了
Object animalFactgoryBean = applicationContext.getBean("&animalFactoryBean");
为什么&就会拿到FactoryBean本身的那个实现类的对象呢,这是BeanFactory这个接口的作用,看源码
这里定义了一个&,如果使用一个&前缀,spring容器就会知道要拿FactoryBean(工程bean)的本身。
提示:一定要分清FactoryBean和BeanFactory的区别,别混了