IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring源码解析 (FactoryBean的一些事情) (十) -> 正文阅读

[Java知识库]Spring源码解析 (FactoryBean的一些事情) (十)

FactoryBean就是生成Bean的, 其目的就是为了创建对象

FactoryBean 就是一个工厂Bean,相当于将工厂类放到了Spring中管理、当获取此Bean的时候返回的是此工厂生成的Bean。需要经过完整的一系列过程才可以创建出Bean

1.测试

public class Cat {
}
@Component
public class CatFactory implements FactoryBean<Cat> {
    @Override
    public Cat getObject() throws Exception {
        return new Cat();
    }

    @Override
    public Class<?> getObjectType() {
        return Cat.class;
    }
}

@Configuration
@ComponentScan("com.zzz.a8")
public class MainConfig {
    @Bean
    public CatFactory catFactory(){
        return new CatFactory();
    }

}
public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        Object bean = context.getBean("catFactory");
        System.out.println(bean.getClass());
        Object bean1 = context.getBean("&catFactory");
        System.out.println(bean1.getClass());
    }
}

在这里插入图片描述

当创建对象的过程复杂时可使用BeanFactory,调用方只需要注入就可使用

FactoryBean使创建对象操作 更加语义化

2.使用FactoryBean与 自己创建对象对比

既然factoryBean目的就是创建对象, 那如果我们自己写一个方法也可以完成同样的操作, 那为什么要使用factoryBean呢

使用方法创建对象

public class Cat {
}
@Component
public class CatFactory {
    public Cat getCat(){
        return new Cat();
    }
}
public class Main {
    @Autowired
    private CatFactory catFactory;

    public void main(String[] args) throws Exception{
        Cat cat = catFactory.getCat();
    }
}

总结:

  • 对于调用方只需要知道对象即可, 不需要管生产方式, 符合迪米特法则, 知道的越少越好
  • 通过FactoryBean创建对象与其他正常对象, 使用起来无差别
  • 将操作复杂化, 全部封装到FactoryBean接口中, 使得类更具体化, 与Spring风格统一
  • 但是, 单用这个类效果不大, 常常都是同时继承其他类, 实现其他接口协同
    创建对象时需要依赖于 别的接口 监听数据,推送数据过来的接口 做一些数据处理时, 可以使用FactoryBean.
    需要搭配其他接口协作, 依赖于Spring的某个生命周期内, 某个时间节点 来生成对象

3.FactoryBean 流程分析

DefaultListableBeanFactory.java

preInstantiateSingletons()

	public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				if (isFactoryBean(beanName)) {
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged(
									(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					getBean(beanName);
				}
			}
		}

在这里插入图片描述

FactoryBeanRegistrySupport
doGetObjectFromFactoryBean()
在这里插入图片描述
AbstractBeanFactory
getBean() -> doGetBean() -> getObjectForBeanInstance()

	protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd)
    {

		// Don't let calling code try to dereference the factory if the bean isn't a factory.
		// 容器已经得到了Bean实例对象(这个实例对象可能是一个普通的Bean,也可能是一个工厂Bean)
		// 如果是一个工厂Bean,则使用它创建一个Bean实例对象,
		// 如果调用本身就想获得一个容器的引用,则指定返回这个工厂Bean实例对象
		// 如果指定的名称是容器的解引用(dereference,即是对象本身而非内存地址),且Bean实例也不是创建Bean实例对象的工厂Bean
		if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
		}

		// Now we have the bean instance, which may be a normal bean or a FactoryBean.
		// If it's a FactoryBean, we use it to create a bean instance, unless the caller actually wants a reference to the factory.
		// 如果Bean实例不是工厂Bean,或者指定名称是容器的解引用,调用者向获取对容器的引用,则直接返回当前的Bean实例
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}

		// 处理指定名称不是容器的解引用,或者根据名称获取的Bean实例对象是一个工厂Bean
		// 使用工厂Bean创建一个Bean的实例对象
		Object object = null;
		if (mbd == null) {
			// 从Bean工厂缓存中获取给定名称的Bean实例对象
			object = getCachedObjectForFactoryBean(beanName);
		}
		// 让Bean工厂生产给定名称的Bean对象实例
		if (object == null) {
			// Return bean instance from factory.
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// Caches object obtained from FactoryBean if it is a singleton.
			// 如果从Bean工厂生产的Bean是单态模式的,则缓存
			if (mbd == null && containsBeanDefinition(beanName)) {
				// 从容器中获取指定名称的Bean定义,如果继承基类,则合并基类相关属性
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			// 如果从容器得到Bean定义信息,并且Bean定义信息不是虚构的,则让工厂Bean生产Bean实例对象
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			// 调用FactoryBeanRegistrySupport类的getObjectFromFactoryBean方法,实现工厂Bean生产Bean对象实例的过程
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

FactoryBeanRegistrySupport
getObjectFromFactoryBean() -> doGetObjectFromFactoryBean()
在这里插入图片描述

调用 Bean工厂的 getObject() 方法生产指定Bean的实例对象

	private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, 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;
	}

BeanFactory 接口调用其实现类的 getObject 方法来实现创建 Bean实例对象功能

4.总结

FactoryBean 的实现类有非常多,比如:Proxy、RMI、JNDI、ServletContextFactoryBean 等等。FactoryBean 接口为 Spring 容器提供了一个很好的封装机制,具体的 getObject()有不同的实现类根据不同的实现策略来具体提供。

  • BeanFactory 是一个大工厂,是IOC容器的根基,有繁琐的 bean 生命周期处理过程,可以生成出各种各样的 Bean
  • FactoryBean 是一个小工厂,它自己也是一个 Bean ,但是可以生成其他 Bean
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-04 07:25:22  更:2022-05-04 07:25:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:51:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码