在spring中,如果一个bean的创建过程很复杂,我们可以使用FactoryBean。
比如像下面的情况,我定义一套webService框架。
public interface WebService {
void service();
}
public class DefaultWebService implements WebService {
private String serviceName;
public DefaultWebService(String serviceName) {
this.serviceName = serviceName;
}
@Override
public void service() {
System.out.println(serviceName + ": current support service for you....");
}
}
public class WebServiceWrapper implements WebService {
private WebService webService;
public WebServiceWrapper(WebService webService) {
this.webService = webService;
}
@Override
public void service() {
System.out.println("befor service, we need do something....");
webService.service();
}
}
WebService接口定义服务的标准,DefaultWebService是一个默认实现,WebServiceWrapper的主要作用是在实际服务之前,做一些检查,准备等工作。
因此当我们使用WebService,实际上是希望使用的是WebServiceWrapper。
现在webService框架实现好了,并打包出来了,现在我需要在项目中利用使用spring注解特性去使用。
那该怎么办呢?我可以实现spring提供的FactoryBean接口,就像下面这样:
@Component
public class WebServiceFactoryBean implements FactoryBean {
@Override
public boolean isSingleton() {
return true;
}
@Override
public Object getObject() throws Exception {
return this.createWebService();
}
@Override
public Class<?> getObjectType() {
return WebService.class;
}
private Object createWebService() {
DefaultWebService webService = new DefaultWebService("Backend Service");
// create a proxy
WebServiceWrapper webServiceWrapper = new WebServiceWrapper(webService);
return webServiceWrapper;
}
}
@Component
public class WebServiceFactoryBean implements FactoryBean {
@Override
public boolean isSingleton() {
return true;
}
@Override
public Object getObject() throws Exception {
return this.createWebService();
}
@Override
public Class<?> getObjectType() {
return WebService.class;
}
private Object createWebService() {
DefaultWebService webService = new DefaultWebService("Backend Service");
// create a proxy
WebServiceWrapper webServiceWrapper = new WebServiceWrapper(webService);
return webServiceWrapper;
}
}
紧接着,就可以利用spring的功能去使用了
@RestController
public class TestController {
@Autowired
private WebService webService;
@GetMapping(value = "webService")
public void webService() {
webService.service();
}
}
http://localhost:8080/webService,控制台会输出:
befor service, we need do something....
Backend Service: current support service for you....
通过输出我们知道,该webService,注入的应该是WebServiceWrapper。
这里的主要疑问是,我们使用@Component托管spring的bean是WebServiceFactoryBean。但是最后在TestController中,WebServiceWrapper的相关信息,只有是怎么被注入的呢?也就是spring是怎么利用FactoryBean来实现特定bean工厂的呢?
spring托管一个bean大概的流程是:
bean信息扫描->实例化->依赖注入->初始化
首先看下bean扫描阶段,在所有扫描出来的BeanDefinition中,没有发现WebServiceWrapper的相关信息,只有WebServiceFactoryBean的相关信息。所以spring不是在扫描阶段解析出WebServiceFactoryBean相关信息的。
再看下WebServiceFactoryBean的实例化过程:
public void preInstantiateSingletons() throws BeansException {
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
}
else {
getBean(beanName);
}
}
}
}
这段源码中,有个判断是说如果当前bean是FactoryBean,那么获取该FactoryBean本身时,beanName要加上一个特殊的前缀“&”。由于WebServiceFactoryBean是一个FactoryBean,所以此时调用的是:Object bean = getBean(FACTORY_BEAN_PREFIX + beanName),入参是:&webServiceFactoryBean
spring中getBean会去调用doGetBean():
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
先创建一个bean实例,然后通过getObjectForBeanInstance()返回一个实例。
这里疑问是,我明明都创建好了一个实例,我直接返回不就好了吗,为什么还要通过getObjectForBeanInstance()返回呢?下面看看该方法得描述:
/**
获取给定bean实例的对象,可以是bean实例本身,也可以是FactoryBean所创建的对象。
*/
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 判断beanName是否以FactoryBean "&"特殊前缀开头,如果是以"&"开头
// 说明当前获取的是FactoryBean本身
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// 如果该bean不是FactoryBean那么直接返回
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
// 否则就利用FactoryBean返回该bean
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
上面的逻辑也是很清晰了,最后看下
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
**object = factory.getObject();**
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}