admin管理员组文章数量:1531792
FactoryBean的使用
FactoryBean
FactoryBean是一个接口,接口声明如下:
package org.springframework.beans.factory;
import org.springframework.lang.Nullable;
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
FactoryBean是一种工厂bean,与普通的bean不一样,FactoryBean是一种可以产生bean的 bean。
FactoryBean的示例
package com.morris.spring.entity;
public class Dog {
private String name;
public Dog(String name) {
System.out.println("new dog");
this.name = name;
}
}
package com.morris.spring.entity;
import org.springframework.beans.factory.FactoryBean;
public class DogFactoryBean implements FactoryBean<Dog> {
@Override
public Dog getObject() throws Exception {
return new Dog("WangWang");
}
@Override
public Class<?> getObjectType() {
return Dog.class;
}
}
package com.morris.spring.demo.annotation;
import com.morris.spring.entity.DogFactoryBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class FactoryBeanDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(DogFactoryBean.class);
applicationContext.refresh();
System.out.println(applicationContext.getBean("&dogFactoryBean"));
System.out.println(applicationContext.getBean("dogFactoryBean"));
}
}
运行结果如下:
com.morris.spring.entity.DogFactoryBean@1814d18
new dog
com.morris.spring.entity.Dog@5a1b69
从运行结果可以得出以下两个结论:
-
DogFactoryBean会向Springring器中注入两个对象,一个名为&dogFactoryBean,代表FactoryBean本身,一个名为dogFactoryBean,代表FactoryBean的getObject()方法返回的对象。
-
DogFactoryBean的getObject()方法只有在使用时才会被调用,也就是只有在使用时才会完成实例化,然后添加到Spring容器中进行管理,有点类似于Bean的懒加载。
从上面的现象很容易会认为Spring的一级缓存singletonObjects容器中会存有两个对象,一个名为&dogFactoryBean的FactoryBean对象,一个名为dogFactoryBean的Dog对象,真的是这样吗?
FactoryBean的用途
我们常规的Bean都是使用Class的反射获取具体实例,如果Bean的获取过程比较复杂,那么常规的xml配置需要配置大量属性值,这个时候我们就可以使用FactoryBean,实现这个接口,在其getObject()方法中初始化这个bean。
使用场景:
- mybatis的MybatisSqlSessionFactoryBean
与BeanFactory的比较
-
BeanFactory是个bean工厂,是一个工厂类(接口), 它负责生产和管理bean的一个工厂,是ioc容器最底层的接口,是个ioc容器,是spring用来管理和装配普通bean的ioc容器(这些bean称为普通bean)。
-
FactoryBean是个bean,在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,是一个可以生产对象和装饰对象的工厂bean,由spring管理后,生产的对象是由getObject()方法决定的。
源码阅读
FactoryBean的初始化
Spring启动过程中会使用BeanFactoryPostProcesser收集要被Spring管理的类,封装为一个BeanDefinition,FactoryBean类也不例外。然后会遍历所有的BeanDefinition进行实例化和初始化。
org.springframework.beans.factory.support.DefaultListableBeanFactory#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...
// 遍历所有的BD,开始实例化
for (String beanName : beanNames) {
// 把父BD中的属性复制到子BD中
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
/**
* 不是抽象的,是单例的,不是懒加载的才能被实例化
*/
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// factoryBean的实例化
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 {
// 普通bean的实例化
getBean(beanName);
}
}
}
... ...
如果一个Bean实现了FactoryBean接口,跟普通Bean一样会调用getBean(),只不过会在beanName前面加上&。
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// 如果beanName是FactoryBean,那么beanName前面一定以&开头
// transformedBeanName会把name中的&去掉
String beanName = transformedBeanName(name);
... ...
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
org.springframework.beans.factory.BeanFactoryUtils#transformedBeanName
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
// 去掉&
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
从上面的源码中可以发现FactoryBean的初始化与普通的Bean的初始化流程基本一致,最后DogFactoryBean会缓存在Spring的一级缓存容器singletonObjects,beanName为dogFactoryBean,而不是&dogFactoryBean(在调用的过程中判断Bean是一个FactoryBean就会给beanName加上前缀&,但是在底层的调用过程中又将beanName中的&去除了)。
getObject()方法的调用
FactoryBean所生产的Bean只有在调用FactoryBean.getObject()方法时才会被初始化。
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// 如果beanName是FactoryBean,那么beanName前面一定以&开头
// transformedBeanName会把name中的&去掉
String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 查询缓存
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 这里会对factoryBean进行特殊处理
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
... ...
当我们调用applicationContext.getBean(“dogFactoryBean”),执行到上面的方法中时,会先根据dogFactoryBean拿到一级缓存中的DogFactoryBean,然后执行getObjectForBeanInstance()方法,这里会对factoryBean进行特殊处理,而普通的bean就会直接返回。
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.
// 判断name是否已&开头
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// 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直接返回
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
// 这里会从factoryBeanObjectCache中拿factorybean产生的对象
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 这里面会直接调用factorybean对象的getObject()
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
分析上面的代码:
-
此时参数为name=dogFactoryBean,beanName=dogFactoryBean,beanInstance=DogFactoryBean
-
所以前面的两个if都会进入。
-
factoryBeanObjectCache中目前也没有,只有执行过一次getObject()方法后才会被缓存到factoryBeanObjectCache。
-
最后会调用DogFactoryBean.getObject()方法来实例化Bean,并缓存到factoryBeanObjectCache。
本文标签: FactoryBeanBeanFactory
版权声明:本文标题:FactoryBean与BeanFactory 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dianzi/1726826698a1086154.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论