FactoryBean
作为一个生产或修饰对象的工厂Bean
,那是如何生产Bean
的呢,咱们通过实例来进行分析,这里就使用工厂Bean
来生产Color
对象
// 启动类
public class MainTest {
@Test
public void TestMain(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
String[] beanNames = applicationContext.getBeanDefinitionNames();
for (String beanName : beanNames) {
System.out.println(beanName);
}
// 工厂Bean获取的是getObject创建的对象
Object factoryBean = applicationContext.getBean(“colorFactoryBean”);
System.out.println(“Bean的类型” + factoryBean.getClass());
// 测试isSingleton控制单例多例
Object factoryBean2 = applicationContext.getBean(“colorFactoryBean”);
System.out.println(“Bean的类型” + factoryBean.getClass());
System.out.println(factoryBean == factoryBean2);
// 通过加“&”获取ColorFactoryBean对象
Object factoryBean3 = applicationContext.getBean(“&colorFactoryBean”);
System.out.println(factoryBean3.getClass());
}
}
// 待生产的Color对象
public class Color {
}
// 创建一个spring定义的工厂Bean
public class ColorFactoryBean implements FactoryBean {
// 返回一个color对象,这个对象会添加到容器中
public Object getObject() throws Exception {
return new Color();
}
// Bean的类型
public Class<?> getObjectType() {
return Color.class;
}
// 控制是否是单例,返回true为单例(容器中保存一份),返回false为多例(每次获取调用getObject()创建新的)
public boolean isSingleton() {
return false;
}
}
// 配置类
@Configuration
public class AppConfig {
/**
-
1.默认获取的是工厂Bean调用getObject创建的对象
-
2.要获取工厂Bean本身,需要给ID前面加一个“&”
*/
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
}
运行启动类,可以看到,已经将Bean对象给生产出来了,根据打印信息,可以得出以下结论:
-
工厂
Bean
获取的是getObject
所创建的对象,这也就是所谓的生产Bean
-
通过改变工厂类的
isSingleton
方法返回值可以改变创建Bean
的单例还是多例 -
如果要将
FactoryBean
本身注入进spring
容器中,获取的时候需要给ID前面加一个“&”
三、源码追踪
参考:https://www.cnblogs.com/guitu18/p/11284894.html
FactoryBean
是怎么让Spring
容器管理调用它的getObject
所生成的Bean
的,咱们通过源码来看看FactorBean
是如何生产Bean
的,
在启动类中通过调用:AnnotationConfigApplicationContext
——> refresh()
方法——> getBean()
方法,再到AbstractBeanFactory
实现类,在这个类中,又调用了doGetBean
方法,doGetBean
可以说是Spring
容器中一个很核心的一个类,里面的功能很多很复杂,我们在这篇文章中只关注和FactoryBean
相关的内容。截取部分代码:
【1】doGetBean
方法中调用getSingleton
方法 从Spring容器中获取单例Bean
protected T doGetBean(String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
String beanName = this.transformedBeanName(name);
// 调用getSingleton方法 从Spring容器中获取单例Bean
Object sharedInstance = this.getSingleton(beanName);
Object bean;
if (sharedInstance != null && args == null) {
if (this.logger.isTraceEnabled()) {
if (this.isSingletonCurrentlyInCreation(beanName)) {
this.logger.trace(“Returning eagerly cached instance of singleton bean '” + beanName + “’ that is not fully initialized yet - a consequence of a circular reference”);
} else {
this.logger.trace(“Returning cached instance of singleton bean '” + beanName + “'”);
}
}
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
}
…
}
getSingleton
从Spring容器中获取单例Bean
@Nullable
public Object getSingleton(String beanName) {
return this.getSingleton(beanName, true);
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 先从singletonObjects中获取单例Bean singletonObjects是一个ConcurrentHashMap
// key是beanName value是单例Bean
Object singletonObject = this.singletonObjects.get(beanName);
// 如果没有获取到,则判断是不是当前在创建中的单例Bean
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized(this.singletonObjects) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
【2】doGetBean
方法中调用getObjectForBeanInstance
,关键代码就从这里开始,查看源码:
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 这里判断 name是不是以&开头,不是经过处理的beanName 并且这个bean实例 不是FactoryBean类型的
// 如果是&开头并且不是FactoryBean类型 则抛出异常
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
// 不是FactoryBean类型 或者name以&开头 直接返回bean实例,要根据beanName获取真正的FactoryBean实例的时候,在beanName前面加上&
} else if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
} else {
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
} else if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
} else {
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
} else {
// factoryBeanObjectCache 看看是不是在缓存中存在
object = this.getCachedObjectForFactoryBean(beanName);
}
// 如果没有
if (object == null) {
// 如果能走到这里来 这个bean实例是FactoryBean类型的
FactoryBean<?> factory = (FactoryBean)beanInstance;
if (mbd == null && this.containsBeanDefinition(beanName)) {
mbd = this.getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = mbd != null && mbd.isSynthetic();
//从这个方法的名字我们可以看到这个方法的意思是:从FactoryBean中获取对象
object = this.getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
}
分析如下:
- 第一个判断
BeanFactoryUtils.isFactoryDereference
:判断name是否不为空且以&
开头,如果是&开头并且不是FactoryBean类型 则抛出异常
- 后面的判断
beanInstance instanceof FactoryBean
:不是FactoryBean
类型 或者name以&开头 直接返回bean实例,要根据beanName获取真正的FactoryBean
实例的时候,在beanName前面加上&
public static boolean isFactoryDereference(@Nullable String name) {
return name != null && name.startsWith(“&”);
}
如果beanInstance不属于FactoryBean或其子类的实例,或者name是以&
开头就直接返回实例对象beanInstance,否则进入到if分支中。在if分支里的各种if .. ==null
判断是为了提高性能,咱们只挑关键部分看:object = this.getObjectFromFactoryBean(factory, beanName, !synthetic);
继续跟踪进去看代码。
【3】getObjectFromFactoryBean
调用doGetObjectFromFactoryBean
方法
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// FactoryBean类型的实例 调用isSingleton方法返回的是true,所传入的bean实例也要求是单例类型的
if (factory.isSingleton() && this.containsSingleton(beanName)) {
synchronized(this.getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 调用doGetObjectFromFactoryBean方法从FactoryBean中获取bean对象,这里是调用的FactoryBean的getObject方法来获取的
object = this.doGetObjectFromFactoryBean(factory, beanName);
// 再从缓存中获取一次
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
// 如果上一步的缓存中获取到了则用缓存中的替代我们从FactoryBean中获取的bean
if (alreadyThere != null) {
object = alreadyThere;
} else {
if (shouldPostProcess) {
if (this.isSingletonCurrentlyInCreation(beanName)) {
return object;
}
this.beforeSingletonCreation(beanName);
try {
object = this.postProcessObjectFromFactoryBean(object, beanName);
} catch (Throwable var14) {
throw new BeanCreationException(beanName, “Post-processing of FactoryBean’s singleton object failed”, var14);
} finally {
this.afterSingletonCreation(beanName);
}
}
if (this.containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
} else {
Object object = this.doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = this.postProcessObjectFromFactoryBean(object, beanName);
} catch (Throwable var17) {
言尽于此,完结
无论是一个初级的 coder,高级的程序员,还是顶级的系统架构师,应该都有深刻的领会到设计模式的重要性。
- 第一,设计模式能让专业人之间交流方便,如下:
程序员A:这里我用了XXX设计模式
程序员B:那我大致了解你程序的设计思路了
- 第二,易维护
项目经理:今天客户有这样一个需求…
程序员:明白了,这里我使用了XXX设计模式,所以改起来很快
- 第三,设计模式是编程经验的总结
程序员A:B,你怎么想到要这样去构建你的代码
程序员B:在我学习了XXX设计模式之后,好像自然而然就感觉这样写能避免一些问题
- 第四,学习设计模式并不是必须的
程序员A:B,你这段代码使用的是XXX设计模式对吗?
程序员B:不好意思,我没有学习过设计模式,但是我的经验告诉我是这样写的
从设计思想解读开源框架,一步一步到Spring、Spring5、SpringMVC、MyBatis等源码解读,我都已收集整理全套,篇幅有限,这块只是详细的解说了23种设计模式,整理的文件如下图一览无余!
搜集费时费力,能看到此处的都是真爱!
。
- 第一,设计模式能让专业人之间交流方便,如下:
程序员A:这里我用了XXX设计模式
程序员B:那我大致了解你程序的设计思路了
- 第二,易维护
项目经理:今天客户有这样一个需求…
程序员:明白了,这里我使用了XXX设计模式,所以改起来很快
- 第三,设计模式是编程经验的总结
程序员A:B,你怎么想到要这样去构建你的代码
程序员B:在我学习了XXX设计模式之后,好像自然而然就感觉这样写能避免一些问题
- 第四,学习设计模式并不是必须的
程序员A:B,你这段代码使用的是XXX设计模式对吗?
程序员B:不好意思,我没有学习过设计模式,但是我的经验告诉我是这样写的
[外链图片转存中…(img-aRbqZOiW-1723199879805)]
从设计思想解读开源框架,一步一步到Spring、Spring5、SpringMVC、MyBatis等源码解读,我都已收集整理全套,篇幅有限,这块只是详细的解说了23种设计模式,整理的文件如下图一览无余!
[外链图片转存中…(img-EzQy7gOQ-1723199879806)]
搜集费时费力,能看到此处的都是真爱!
标签:object,Spring,beanName,null,Bean,FactoryBean,设计模式,底层 From: https://blog.csdn.net/2401_85819474/article/details/141069074