各位大神,最近在研究spring框架bean加载过程,遇到一个棘手问题,我相信研究spring原理的大神肯定对这个问题有兴趣
我的项目框架是spring+rpc,配置文件方式注入bean,非注解
一部分bean是普通的serivce bean配置,spring内部走正常bean的加载过程,没有问题;
还有一部分是自定义标签,通过一个工厂类生成service的代理对象bean,作为消费者/生产者,这个工厂类实现了FactoryBean接口,spring内部走FactoryBean的加载过程
public class RemoteServiceFactory implements FactoryBean<Object>, 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的类型吗?
为什么非要实例化它呢?有什么方法可以解决这个问题?