在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 doGetBean( - String name, @Nullable Class
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
- }
- 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;
- }