Spring扩展点之FactoryBean接口
前言
首先看一下接口定义
public interface FactoryBean<T> {
/**
* 返回对象实例
*/
@Nullable
T getObject() throws Exception;
/**
* 返回对象类型,
*/
@Nullable
Class<?> getObjectType();
/**
* 该工厂管理的对象是否为单例?
*/
default boolean isSingleton() {
return true;
}
}
由接口定义可以看出来,实现这个接口的bean不是主要功能,getObject()创建的对象才是重点。那么在这我们就可以猜到了,可以是使用FactoryBean创建一些实例化过程比较复杂的bean
FactoryBean的注册
FactoryBean的处理逻辑在AbstractBeanFactory.doGetBean方法内
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//获取bean名称
final String beanName = transformedBeanName(name);
Object bean;
//省略部分内容
//这里就是FactoryBean的相关处理,下面会展开说
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
//省略部分内容
return (T) bean;
}
看一下具体的逻辑,这里需要注意Spring关于bean的name有个潜规则,凡是以&开头的bean名称都默认为FactoryBean
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 如果beanName以工厂引用&开头
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
// 如果name以&开头,而beanInstance不是FactoryBean类型,则抛异常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
}
// 如果beanInstance不是FactoryBean类型,则直接返回beanInstance
// 或者name以&开头,也直接返回beanInstance,说明我们就想获取FactoryBean实例
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 此时beanInstance是FactoryBean类型,而name又不是以&开头; 这是我们示例工程的情况,也是最普通、用的最多的情况
// 将beanInstance强转成FactoryBean类型
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// 从缓存中获取我们需要的实例对象
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 调用FactoryBean的getObject方法创建我们需要的实例对象
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
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) {
//通过factory.getObject获取
object = doGetObjectFromFactoryBean(factory, beanName);
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
//将获取到的对象放到factoryBeanObjectCache单例缓存map进行存储
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
//非单例的处理,直接通过factory.getObejct获取,然后再返回给用户
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;
}
}
生成bean对象的方法:
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
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;}
Spring的实现
Spring中实现这个接口的bean有很多,但是我们最熟悉也是最重要的就是在我之前文章中提到过得ProxyFactoryBean这个bean是实现AOP技术的重点,简单回顾一下吧

public Object getObject() throws BeansException {
initializeAdvisorChain();
if (isSingleton()) {
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource();
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
Class<?> targetClass = getTargetClass();
if (targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
}
// Initialize the shared singleton instance.
super.setFrozen(this.freezeProxy);
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
Spring扩展点之FactoryBean接口的更多相关文章
- Spring扩展点之Aware接口族
引言 Spring中提供了各种Aware接口,方便从上下文中获取当前的运行环境,比较常见的几个子接口有:BeanFactoryAware,BeanNameAware,ApplicationContex ...
- Spring扩展点-v5.3.9
Spring 扩展点 **本人博客网站 **IT小神 www.itxiaoshen.com 官网地址****:https://spring.io/projects/spring-framework T ...
- Spring之BeanFactory和FactoryBean接口的区别
目录 一.BeanFactory接口 二.FactoryBean接口 1.简单实现 2.增强实现 3.FactoryBean的实际使用案例 三.总结 @ Spring框架中的BeanFactory ...
- Spring扩展点之BeanPostProcessor
前言 BeanPostProcessor接口是Spring中一个非常重要的接口,它的接口定义如下 public interface BeanPostProcessor { Object postPro ...
- Spring扩展点之BeanFactoryPostProcessor
前言 BeanFactoryPostProcessor接口是Spring中一个非常重要的接口,它的接口定义如下 public interface BeanFactoryPostProcessor { ...
- spring扩展点之PropertyPlaceholderConfigurer
原理机制讲解 https://leokongwq.github.io/2016/12/28/spring-PropertyPlaceholderConfigurer.html 使用时多个配置讲解 ht ...
- spring mvc 提供的几个常用的扩展点
转载 :http://blog.csdn.net/gufachongyang02/article/details/43836105 这是spring3 mvc的核心流程图: SpirngMVC的第 ...
- Spring钩子方法和钩子接口的使用详解
本文转自:http://www.sohu.com/a/166804449_714863 前言 SpringFramework其实具有很高的扩展性,只是很少人喜欢挖掘那些扩展点,而且官方的Refrenc ...
- Spring中的扩展点
Spring作为一个常用的IOC框架,在设计上预留了很多的扩展点,很多第三方开源框架,包括Spring自身也是基于这些扩展点实现的,这很好的体现了对修改关闭.对扩展开放的原则.总的来说Spring的扩 ...
随机推荐
- jenkins如何构建C#代码写的网站
纯粹是因为同事习惯了写C#代码,开发的网站用C#编译, 对于习惯了用Maven编译的测试人员,真是一头雾水.不用jenkins吧,效率特别低,每次收到开发发过来的版本,还要进行数据库相关配置,是非常累 ...
- windows删除桌面右键“英特尔@显卡设置”
运行中输入:regedit 确认运行注册表编辑器,依次单击展开 HKEY_CLASSES_ROOT\Directory\Background\shellex\ContextMenuHandlers键 ...
- Windows | Ubuntu 16.04/18.04 安装Pycharm并永久破解以及安装配置Anaconda3
Ubuntu 18.04下 1.安装python 2._版本,输入 sudo apt install python 命令行输入 python或python3会打开对应的版本. 输入 exit()或C ...
- vue router 导航守卫生命周期
导航守卫 导航守卫主要用来通过跳转或取消的方式守卫导航.有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的.(记住参数或查询的改变并不会触发进入/离开的导航守卫.你可以通过观察$r ...
- 201871010119-帖佼佼《面向对象程序设计(java)》第十七周学习总结
博文正文开头格式:(2分) 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.co ...
- 精通awk系列
安装新版本gawk awk有很多种版本,例如nawk.gawk.gawk是GNU awk,它的功能很丰富. 本教程采用的是gawk 4.2.0版本,4.2.0版本的gawk是一个比较大的改版,新支持的 ...
- (day47)jQuery
目录 一.初识jQuery (一)jQuery介绍 (二)版本介绍 (三)jQuery对象 (四)相关网站 (五)基础语法 二.查找标签 (一)基本选择器 (1)id选择器 (2)标签选择器 (3)c ...
- VMware虚拟机安装使用及系统安装教程
虚拟机是利用软件来模拟出完整计算机系统的工具.具有完整硬件系统功能的.运行在一个完全隔离环境中.虚拟机的使用范围很广,如未知软件评测.运行可疑型工具等,即使这些程序中带有病毒,它能做到的只有破坏您的虚 ...
- java为什么学JavaScript?
就现在的趋势来说,Spring无疑是一家独大的,它有太多利益 现在在Java EE开发中,Spring已经成为和Java核心库一样的基础设备,所以说假如想成为一个合格的Java程序员,Spring必定 ...
- 13 opencv训练器
https://blog.csdn.net/WZZ18191171661/article/details/91305466 https://blog.csdn.net/qq_25352981/arti ...