- 前言
- 第一部分 核心实现
- 第 1 章 Spring 整体架构和环境搭建
- 第 2 章 容器的基本实现
- 第 3 章 默认标签的解析
- 第 4 章 自定义标签的解析
- 第 5 章 bean 的加载
- 第 6 章 容器的功能扩展
- 第 7 章 AOP
- 第二部分 企业应用
- 第 8 章 数据库连接 JDBC
- 第 9 章 整合 MyBatis
- 第 10 章 事务
- 第 11 章 SpringMVC
- 第 12 章 远程服务
- 第 13 章 Spring 消息
5.3 从 bean 的实例中获取对象
在 getBean 方法中,getObjectForBeanInstance 是个高频率使用的方法,无论是从缓存中获得 bean 还是根据不同的 scope 策略加载 bean。总之,我们得到 bean 的实例后要做的第一步就是调用这个方法来检测一下正确性,其实就是用于检测当前 bean 是否是 FactoryBean 类型的 bean,如果是,那么需要调用该 bean 对应的 FactoryBean 实例中的 getObject() 作为返回值。
无论是从缓存中获取到的 bean 还是通过不同的 scope 策略加载的 bean 都只是最原始的 bean 状态,并不一定是我们最终想要的 bean。举个例子,假如我们需要对工厂 bean 进行处理,那么这里得到的其实是工厂 bean 的初始状态,但是我们真正需要的是工厂 bean 中定义的 factory-method 方法中返回的 bean,而 getObjectForBeanInstance 方法就是完成这个工作的。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
//如果指定的 name 是工厂相关(以&为前缀) 且 beanInstance 又不是 FactoryBean 类型则验证不通过
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof
FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.
getClass());
}
//现在我们有了个 bean 的实例,这个实例可能会是正常的 bean 或者是 FactoryBean
//如果是 FactoryBean 我们使用它创建实例,但是如果用户想要直接获取工厂实例而不是工厂的
getObject 方法对应的实例那么传入的 name 应该加入前缀&
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils. IsFactory
Dereference(name)) {
return beanInstance;
}
//加载 FactoryBean
Object object = null;
if (mbd == null) {
//尝试从缓存中加载 bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
//到这里已经明确知道 beanInstance 一定是 FactoryBean 类型
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
//containsBeanDefinition 检测 beanDefinitionMap 中也就是在所有已经加载的类中检测
是否定义 beanName
if (mbd == null && containsBeanDefinition(beanName)) {
//将存储 XML 配置文件的 GernericBeanDefinition 转换为 RootBeanDefinition,
如果指定 BeanName 是子 Bean 的话同时会合并父类的相关属性
mbd = getMergedLocalBeanDefinition(beanName);
}
//是否是用户定义的而不是应用程序本身定义的
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
从上面的代码来看,其实这个方法并没有什么重要的信息,大多是些辅助代码以及一些功能性的判断,而真正的核心代码却委托给了 getObjectFromFactoryBean ,我们来看看 getObjectForBeanInstance 中的所做的工作。
(1)对 FactoryBean 正确性的验证。
(2)对非 FactoryBean 不做任何处理。
(3)对 bean 进行转换。
(4)将从 Factory 中解析 bean 的工作委托给 getObjectFromFactoryBean。
protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean
shouldPostProcess) {
//如果是单例模式
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
shouldPostProcess);
object = doGetObjectFromFactoryBean(factory, beanName,
this.factoryBeanObjectCache.put(beanName, (object != null ? object :
NULL_OBJECT));
}
return (object != NULL_OBJECT ? object : null);
}
}
else {
return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
}
}
很遗憾,在这个代码中我们还是没有看到想要看到的代码,在这个方法里只做了一件事情,就是返回的 bean 如果是单例的,那就必须要保证全局唯一,同时,也因为是单例的,所以不必重复创建,可以使用缓存来提高性能,也就是说已经加载过就要记录下来以便于下次复用,否则的话就直接获取了。
在 doGetObjectFromFactoryBean 方法中我们终于看到了我们想要看到的方法,也就是 object =factory.getObject(),是的,就是这句代码,我们的历程犹如剥洋葱一样,一层一层的直到最内部的代码实现,虽然很简单。
private Object doGetObjectFromFactoryBean(
final FactoryBean factory, final String beanName, final boolean shouldPostProcess)
throws BeanCreationException {
Object object;
try {
//需要权限验证
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
Object>() {
object = AccessController.doPrivileged(new PrivilegedExceptionAction<
public Object run() throws Exception {
return factory.getObject();
}
}, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//直接调用 getObject 方法
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);
}
if (object == null && isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null
from getObject");
}
if (object != null && shouldPostProcess) {
try {
//调用 ObjectFactory 的后处理器
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of the
FactoryBean's object failed", ex);
}
}
return object;
}
上面我们已经讲述了 FactoryBean 的调用方法,如果 bean 声明为 FactoryBean 类型,则当提取 bean 时提取的并不是 FactoryBean,而是 FactoryBean 中对应的 getObject 方法返回的 bean,而 doGetObjectFromFactoryBean 正是实现这个功能的。但是,我们看到在上面的方法中除了调用 object = factory.getObject() 得到我们想要的结果后并没有直接返回,而是接下来又做了些后处理的操作,这个又是做什么用的呢?于是我们跟踪进入 AbstractAutowireCapableBeanFactory 类的 postProcessObjectFromFactoryBean 方法:
AbstractAutowireCapableBeanFactory.java
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
return applyBeanPostProcessorsAfterInitialization(object, beanName);
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
对于后处理器的使用我们还未过多接触,后续章节会使用大量篇幅介绍,这里,我们只需了解在 Spring 获取 bean 的规则中有这样一条:尽可能保证所有 bean 初始化后都会调用注册的 BeanPostProcessor 的 postProcessAfterInitialization 方法进行处理,在实际开发过程中大可以针对此特性设计自己的业务逻辑。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论