2 whm9276 whm9276 于 2017.09.14 10:42 提问

Spring factoryBean加载 框架内部嵌套加载问题

各位大神,最近在研究spring框架bean加载过程,遇到一个棘手问题,我相信研究spring原理的大神肯定对这个问题有兴趣

我的项目框架是spring+rpc,配置文件方式注入bean,非注解

一部分bean是普通的serivce bean配置,spring内部走正常bean的加载过程,没有问题;

还有一部分是自定义标签,通过一个工厂类生成service的代理对象bean,作为消费者/生产者,这个工厂类实现了FactoryBean接口,spring内部走FactoryBean的加载过程
public class RemoteServiceFactory implements FactoryBean, BeanFactoryAware, InitializingBean {
private static final Logger log = LoggerFactory.getLogger(RemoteServiceFactory.class);
 public RemoteServiceFactory(Object bean, String path, int port) {
  this.object = bean; // 自定义标签中配置的service bean的引用(ref属性,引用配置文件bean id)
  this.path = path; // 生产者服务路径(和此问题无关)
  this.port = port; // 生产者服务端口(和此问题无关)
 }
 
 public boolean isSingleton() {
  return true;
 }
 public void afterPropertiesSet() throws Exception {
   // 根据this.object创建相应的生产者/消费者代理对象,用于rpc
 }
}

问题分析,debug spring bean解析后的加载过程
1.spring对配置文件解析后,遍历所有的bean,进行一一实例化
  AbstractApplicationContext:finishBeanFactoryInitialization()
    内部调用beanFactory.preInstantiateSingletons();
      DefaultListableBeanFactory:preInstantiateSingletons()
        内部遍历beanNames,进行一一实例化

2.假如第一个bean是普通的service bean,在初始化时,会解析内部的依赖,然后遍历依赖参数,解析依赖
  DefaultListableBeanFactory:doResolveDependency()
    内部调用findAutowireCandidates() 
      内部调用BeanFactoryUtils.beanNamesForTypeIncludingAncestors()
        内部调用lbf.getBeanNamesForType()
          -> DefaultListableBeanFactory:doGetBeanNamesForType()
  关键就在这里,doGetBeanNamesForType方法内部会遍历所有bean,去判断是否匹配上面的依赖参数的类型,
  当遍历到实现FactoryBean的bean时,会实例化这个bean(因为FactoryBean只是代理,不是真正bean),然后又会解析factoryBean中真实bean中的依赖参数,
  然后就又会走到这里,导致一直嵌套下去的加载过程
  如果程序加载没有问题,则一切正常;一旦某个类加载失败(比如某个类注入的属性在properties中不存在),就会出现大量的异常信息抛出,
  原因就是上面的嵌套加载,某个类加载抛出异常会一直抛出到嵌套的最顶层,每一层的异常信息都会积攒下来,最后爆发似的抛出
  (每层的异常信息都是 当前这层bean的加载失败)

各位大神:
  我一直感觉spring这样嵌套加载在设计上是不应该的,不理解为什么会这样,单纯匹配类型的话,不能通过其他方式获取FactoryBean中真实bean的类型吗?
    为什么非要实例化它呢?有什么方法可以解决这个问题?

1个回答

whm9276
whm9276   2017.09.25 13:57

顶起来,哪位大神帮看下

Csdn user default icon
上传中...
上传图片
插入图片