简介
说明
本文介绍Spring中的FactoryBean,包括:作用,用法,原理,MyBatis对FactoryBean的应用。
FactoryBean的作用
- 通过一个FactoryBean来生产一个对象
- 可以获取生产出的对象的类型
- 可以判断生产出的对象是不是单例
FactoryBean的来源
在某些情况下,实例化Bean过程比较复杂,若按照传统的方式,则需要在中提供大量的配置信息,不够灵活,这时采用编码的方式能得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。
FactoryBean接口在Spring中占重要地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。
从Spring 3.0 开始, FactoryBean开始支持泛型,即接口声明改为 FactoryBean<T> 的形式。
源码:
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
普通bean与FactoryBean的区别
Spring 容器中有两种bean:普通bean和工厂bean。
普通bean
通过反射来实例化被标记为bean的类。例:@Component指定的类。
FactoryBean
FactoryBean返回的对象不是指定类的一个实例,而是FactoryBean#getObject方法返回的对象。若想获取FactoryBean本身,要在bean的名称添加前缀&来获取FactoryBean对象本身(applicationContext.getBean(“&” + beanName))。
FactoryBean不遵循Spring的生命周期
Spring的作者想要放权给使用者,让使用者自己实现创建一个bean的逻辑,所以Spring并不会过多的插手该Bean的实例化过程,使得一个Bean的实例化完全由使用者本人去实现。
这个类并不会像普通bean那样在Spring容器初始化时进行实例化,而是类似于懒加载,在获取时才进行创建和返回。至于是不是单例,要取决于isSingleton()方法的返回值。
当然,这个创建出来的bean也会被缓存,AOP等逻辑也会对该类生效,当然这都是后话。
简单示例
公共部分
FactoryBean实现类
package com.example.tmp;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.FactoryBean;
@AllArgsConstructor
public class MyFactoryBean implements FactoryBean {
private String myBeanName;
@Override
public Object getObject() throws Exception {
MyBean myBean = new MyBean();
myBean.setName(myBeanName);
return myBean;
}
@Override
public Class<?> getObjectType() {
return MyBean.class;
}
}
bean实体类
package com.example.tmp;
import lombok.Data;
@Data
public class MyBean {
private Integer id;
private String name;
}
注册单个FactoryBean
配置类
package com.example.tmp;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig {
@Bean
public MyFactoryBean getMyBean() {
return new MyFactoryBean("Tony");
}
}
controller
package com.example.controller;
import com.example.tmp.MyBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Autowired
MyBean myBean;
@GetMapping("/test1")
public String test1() {
System.out.println(myBean.getName());
return "test1 success";
}
}
测试
访问:http://localhost:8080/test1
后台结果:
Tony
注册多个FactoryBean
配置类
package com.example.tmp;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig {
@Bean("bean1")
public MyFactoryBean getMyBean1() {
return new MyFactoryBean("Tony");
}
@Bean("bean2")
public MyFactoryBean getMyBean2() {
return new MyFactoryBean("Pepper");
}
}
controller
package com.example.controller;
import com.example.tmp.MyBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Autowired
@Qualifier("bean2")
MyBean myBean;
@GetMapping("/test1")
public String test1() {
System.out.println(myBean.getName());
return "test1 success";
}
}
测试
访问:http://localhost:8080/test1
后台结果:
Pepper

请先 !