这俩在Spring中压根就完全不一样。在一些框架和Spring融合的时候使用FactoryBean。BeanFactory在日常用到的不多,取而代之的是ApplicationContext对象。
BeanFactory看这个名字就知道这是一个创建bean的工厂,还记得我很早很早之前看过的一本书《Spring in Action》第一版的时候,就介绍了BeanFactory和ApplicationContext的关系。有兴趣的可以去找找这本书,第一版对Spring的核心功能说的很完整。
建议直接看官方的文档BeanFactory。
他是访问Spring Bean container的顶级接口,从这个接口可以获取bean。作为一个bean来说,只要交给Spring管理,Spring就会把这个bean放在他的container里面。
首先,FactoryBean是一个bean。但是他不是一个普通的bean,是可以创建对象的bean。最终的暴露给外面的是他getObject()
返回的对象,并且它的这个创建的对象,不会受Spring的管理。
此外,这个接口还提供了创建这个对象是单例还是多例。他的子接口SmartFactoryBean
还能提供更加详细的控制。官方文档 FactoryBean
这都是他的实现类。
接口本身没有什么可说的。下面分析分析在Spring中,FactoryBean是怎么解析和使用的。
public class MyFirstTestFactoryBean implements SmartFactoryBean<Test> {
@Override
public Test getObject() throws Exception {
Test test = new Test();
test.setAge(12);
test.setName("name");
return test;
}
@Override
public Class<?> getObjectType() {
return Test.class;
}
@Override
public String toString() {
return "toString-lc";
}
}
Bean
public class Test {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Test{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
配置类
public class MyFirstTestFactoryConfig {
@Bean(name = "testFactoryBean")
public MyFirstTestFactoryBean testFactoryBean(){
return new MyFirstTestFactoryBean();
}
}
启动类
public class BeanFactoryApplicationText {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = null;
try {
context = new AnnotationConfigApplicationContext(MyFirstTestFactoryConfig.class);
Test bean = context.getBean(Test.class);
System.out.println(bean);
MyFirstTestFactoryBean myFirstTestFactoryBean = context.getBean(MyFirstTestFactoryBean.class);
MyFirstTestFactoryBean myFirstTestFactoryBean1 = (MyFirstTestFactoryBean) context.getBean("&testFactoryBean");
MyFirstTestFactoryBean myFirstTestFactoryBean2 = (MyFirstTestFactoryBean) context.getBean("&&testFactoryBean");
System.out.println(myFirstTestFactoryBean==myFirstTestFactoryBean1 );
System.out.println(myFirstTestFactoryBean==myFirstTestFactoryBean2 );
}catch (Throwable e){
e.printStackTrace();
}finally {
assert context != null;
context.close();
}
}
}
结果
首先要说明,FactoryBean也是一个Bean,也会走Spring标准得创建得流程。因为Spring标准得创建Bean得流程太长了,这里就不详细得说了。具体得方法是ConfigurableListableBeanFactory接口得preInstantiateSingletons
,具体得实现类是DefaultListableBeanFactory
。
就挑一些重点得方法分析分析。
// 判断这个bean是否是一个FactoryBean
if (isFactoryBean(beanName)) {
// 在正常得bean得名字得前缀前面添加 &,这个方法很熟悉了,就会走标准得bean得创建过程。
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
//
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
//这里判断当前得找个bean是否是一个SmartFactoryBean,并且SmartFactoryBean得isEagerInit是否为true,
// 如果为true,表示需要舒适化FactoryBean创建得Bean
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) {
// 如果需要立即初始化,就会创建BeanFactory得需要创建得Bean
getBean(beanName);
}
}
}
针对上面得代码有几个问题
怎么判断是否是一个FactoryBean(isFactoryBean()是怎么做得?)?
本质是通过Bean得Class来判断得,主要是通过
isAssignableFrom
方法来判断得,并且会设置对应得BeanDefinition.里面得isFactoryBean属性为true。但是这里面还有一些小细节.transformedBeanName方法。
这个方法会获取bean得真正得名字,他会去掉FactoryBean得引用得前缀 & (在BeanFactory中,从名字得前缀上可以区分普通得bean和FactoryBean,FactoryBean得名字前面是有 & 得。)
下面得这个方法会截取掉 名字前面得&,然后再别名得缓存得map里面,通过bean得名字获取别名,如果没有,就直接返回bean得名字。
protected String transformedBeanName(String name) { return canonicalName(BeanFactoryUtils.transformedBeanName(name)); }
一个FactoryBean会被作用Aware接口,init和destroy和BeanPostProcess。Bean得注入吗?
会的,之前说过,FactoryBean虽然特殊,但是他也是一个Bean,作为一个Bean来说,他是完全由资格走标准得SpringBean得创建流程得。所以,他会得。
如果需要理解初始化,走得也是正常得获取bean得方法,从这个参数可以看到,入参还是FactoryBean得名字,怎么就能通过这个名字来获取,调用到FactoryBean里面得
getObjects()
方法。主要得方法是
getBean(beanName)
方法。第三个问题,涉及到得东西比较多,这里就不说了,再下面得章节分析。
在FactoryBean得基础上,增加了两个方法,
preInstantiateSingletons
方法里面创建FactoryBean得时候会将这个FactoryBean创建得Bean创建出来.public interface SmartFactoryBean<T> extends FactoryBean<T> {
default boolean isPrototype() {
return false;
}
default boolean isEagerInit() {
return false;
}
}
全量的代码就不贴出来了,分析一下重点的代码
先获取bean的真正的名字,这一步的目的是为了处理FactoryBean和普通bean的区别,但是FactoryBean也是有bean名字的,他不会自动给这个bean加上前缀&。而是在获取的时候,通过前缀来区分。
从一级缓存中获取获取bean,如果没有,就先去创建这个bean,走一波bean的标准的创建过程。
如果已经存在,就会走getObjectForBeanInstance
方法,这个方法很细节。
// 得到bean的名字,通过上面的分析可以知道,如果前缀带有&,他会去掉,比如&testFactoryBean,得到的名字就是testFactoryBean。
String beanName = transformedBeanName(name);
Object bean;
//先在一级缓存中检查是否存在,如果存在就走if里面的, 不存在就走标准的创建bean的流程了,
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 + "'");
}
}
// 注意,这个方法。很细节。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
// 下面就是创建标准的创建bean的过程了。忽略掉了
要注意,这里的几个参数。
beanInstance:bean的实例
name:需要获取的bean的名字,也就是调用的名字,比如 &testFactoryBean。
beanName:经过transformedBeanName
处理的bean的名字。基于上面的例子,比如testFactoryBean。
RootBeanDefinition:这个bean对应的BeanDefinition
主要功能:
通过bean名字的不同, 干不同的事情,注意这里有两个name。第一个name纯粹就是为了判断,当前你想要的是一个工厂bean还是一个普通的bean。别的在没有什么意思。
因为有FactoryBean的存在,所以,在Spring里面才有这样的写法,要是没有这个操作,两个name参数没有什么意思。
获取bean可以从bean工厂的获取,也可以从FactoryBean中获取,并且通过传递的name的不同,来区分是返回Factorybean还是普通的bean。
从代码可以看到,如果是一个&开头的beanName,就认为他获取的是factoryBean,如果当前的bean是Factorybean,下面要做的就是要从Factorybean中获取需要的bean。因为bean的来源就两个,BeanFactory和FactoryBean。
在这个里里面,肯定是要维护缓存的,比如FactoryBean名字和他能创建的Bean的映射关系,上来肯定从缓存里面查,如果没有就去创建bean,这就走到了getObjectFromFactoryBean
方法里面了。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 只是单纯的看了看,前缀是不是 &开头的,注意这里判断的name,
// 如果是&开头,说明这次想要获取的是FactoryBean,所以,这里只是做了一个判断,设置了他的isFactoryBean属性,直接返回原来的bean的实例
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;
}
// 如果不是工厂bean直接返回好了,如果是factoryBean,就会通过FactoryBena来创建Bean的实例。
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
//从缓存中获取bena,这个缓存,key是 工厂bean的名字,value是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()); // 这个表示,这个bean是否是一个合成得,所谓得合成就是不是由应用程序创建得,而是由代理,或者间接创建得
// 这里会通过Factorybean来创建bean。
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
getObjectFromFactoryBean(从Factorybean中创建bean)
先看入参:
factory:要创建对象的FactoryBean。
beanName:这个名字和之前的一样的含义。
shouldPostProcess:是否要应用postProcess
主要功能:
主要的功能就是从FactoryBean中创建Bean实例。具体的代码逻辑如下:
如果是单例就需要缓存下来,如果不是单例,每次都要创建。此外shouldPostProcess
为true,表示需要应用beanPostProcess方法 。中间还有一些的校验。
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 如果是单例,并且beanName包含在bean工厂中。
if (factory.isSingleton() && containsSingleton(beanName)) {
// 获取锁
synchronized (getSingletonMutex()) {
// 先从缓存中获取,key是beanFactory的名字,v是这个beanFactory创建的bean的名字,
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 缓存中没有,这个方法就是调用FactoryBean.getObject()方法。获取bean的实例
object = doGetObjectFromFactoryBean(factory, beanName);
// 再次从缓存中获取一下,如果没有,才会进行后续的postPorcess和缓存中存放值
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) { //如果说当前得bean正在创建, 那么直接返回就好了,不用走之后得process了,因为标准得流程也是会走这个流程得
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName); //这里引用postPorcess得时候只应用得是postProcessAfter得方法
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName); // 前后呼应
}
}
if (containsSingleton(beanName)) {
// 放缓存,这里是将真正创建的bean存在缓存里面,
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
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;
}
}
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 {
// 这个很简单,调用的就是BeanFactory的方法,这里就直接创建对象了
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) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
到这里,已经分析了FactoryBean创建对象的几个重点的方法,上面方法的入口是假设 一个SmartFactoryBean需要立即初始化,在preInstantiateSingletons里面循环的时候创建的。下面从正常的ApplicationContext启动起来,获取bean的操作来看,他是怎么创建的。
BeanFactory# T getBean(Class requiredType)方法开始
通过上面的方法知道了,可以通过getBean(factoryBean(这个名字没有带&))来获取这个FactoryBean创建对象的流程了,在这个方法里面要思考一个问题怎么把FactoryBean的类型和要创建的bean的类型关联起来。只要能关联起来,就能通过走上面的逻辑来获取要创建的Bean了。
一切的开始都是从getBean(Class type)开始。
这个方法主要是通过类型,参数来获取bean的实例,并且将bean的实例包装成NamedBeanHolder。
主要调用的方法是getBeanNamesForType(requiredType)
,这个方法主要是获取通过Bean的类型来获取合适的bean,并且返回合格的Bean的名字。
但是这个可能回返回多个bean的,比如一个接口的多个实现类,都是满足getBeanNamesForType
条件,但是这个接口返回的是一个Bean,所以下面的都是来针对这个情况来做处理的。
如果有多个满足的Bean,就需要处理了,
先看这个bean是否有BeanDefintion,或者这个bean是否是一个Autowire的候选者,(isAutowireCandidate这个属性是BeanDefinition的属性),取值是标注了@Autowire的bean的类型的所有的实现类。组成一个新的candidateNames
。
只有一个,就直接返回,否则就要继续判断了。通过@Primary注解和@Priority注解来判断,如果有多个实现了这俩注解中其中之一的注解,回直接报错,通过这个处理,如果还有,就看nonUniqueAsNull
的true还是false了,否则就直接返回null。
private <T> NamedBeanHolder<T> resolveNamedBean(
ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
// 获取符合的Bean的名字的集合
String[] candidateNames = getBeanNamesForType(requiredType);
// 如果有多个符合的
if (candidateNames.length > 1) {
List<String> autowireCandidates = new ArrayList<>(candidateNames.length);
for (String beanName : candidateNames) {
if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
autowireCandidates.add(beanName);
}
}
if (!autowireCandidates.isEmpty()) {
candidateNames = StringUtils.toStringArray(autowireCandidates);
}
}
// 如果只有一个,那简单了,直接返回就好了
if (candidateNames.length == 1) {
String beanName = candidateNames[0];
return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
}
//经过上面的处理之后,这里还是多个符合的,就再次处理一下。
else if (candidateNames.length > 1) {
//首先组组装成一个map,map的key是beanName,map的value是bean的实例,
Map<String, Object> candidates = new LinkedHashMap<>(candidateNames.length);
for (String beanName : candidateNames) {
if (containsSingleton(beanName) && args == null) {
Object beanInstance = getBean(beanName);
candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
}
else {
candidates.put(beanName, getType(beanName));
}
}
// 判断找到的多个bean里面是否有Primary注解,如果有多个Primary,就直接报错
String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());
if (candidateName == null) {
// 这里也是,是处理Priority注解的逻辑,和上面的一模一样,
candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());
}
if (candidateName != null) {
// 如果找到了,就直接返回了。不用再搞别的了。直接返回
Object beanInstance = candidates.get(candidateName);
if (beanInstance == null || beanInstance instanceof Class) {
beanInstance = getBean(candidateName, requiredType.toClass(), args);
}
return new NamedBeanHolder<>(candidateName, (T) beanInstance);
}
// 到这里,说明通过上面的处理,没有bean了,或者还有多个合适的bean,直接报错
// nonUniqueAsNull的意思是是否 允许非唯一的,并且还能为null的bean。
if (!nonUniqueAsNull) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
}
}
//直接返回null
return null;
}
从getBeanNamesForType方法进来,就一直到这个方法了,熟悉Spring的都知道,do开头得方法才是干活的方法。下面就分析这个方法,真正的来获取Bean的操作。
先看方法的几个参数
主要的功能
SmartInstantiationAwareBeanPostProcessor#predictBeanType
方法来判断bean的类型private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List<String> result = new ArrayList<>();
// Check all bean definitions.
for (String beanName : this.beanDefinitionNames) {
// Only consider bean as eligible if the bean name is not defined as alias for some other bean.
if (!isAlias(beanName)) {
try {
// 得到BeanDefintion,
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
if (!mbd.isAbstract() && (allowEagerInit ||
(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
// 这里会遍历所有的bean,这个时候bean的名字就是之前注册到BeanFactory中的名字,
//判断这个bean是否是一个工厂bean,
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
boolean matchFound = false;
// 是否允许工厂bean实例化,
// containsSingleton的判是因为,factorybean创建bean,前提是他得存在把,得实例化出来吧
boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName));
// 是否不是懒惰初始化的
boolean isNonLazyDecorated = (dbd != null && !mbd.isLazyInit());
if (!isFactoryBean) {
// 如果当前的bean不是一个FactoryBean,说明这个Bean没有创建对象的能力,所以,这里只是简单的
// 判断当前bean的类型就好了
if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
else {
if (includeNonSingletons || isNonLazyDecorated ||
(allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
// 这里就会调用Factorybean.getType方法来判断,
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
/// 如果是factoryBean但是类型确不匹配,就检测这个工厂bean
if (!matchFound) {
// In case of FactoryBean, try to match FactoryBean instance itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
if (matchFound) {
result.add(beanName);
}
}
}
catch (CannotLoadBeanClassException | BeanDefinitionStoreException ex) {
if (allowEagerInit) {
throw ex;
}
// Probably a placeholder: let's ignore it for type matching purposes.
LogMessage message = (ex instanceof CannotLoadBeanClassException ?
LogMessage.format("Ignoring bean class loading failure for bean '%s'", beanName) :
LogMessage.format("Ignoring unresolvable metadata in bean definition '%s'", beanName));
logger.trace(message, ex);
// Register exception, in case the bean was accidentally unresolvable.
onSuppressedException(ex);
}
catch (NoSuchBeanDefinitionException ex) {
// Bean definition got removed while we were iterating -> ignore.
}
}
}
// Check manually registered singletons too.
for (String beanName : this.manualSingletonNames) {
try {
// In case of FactoryBean, match object created by FactoryBean.
if (isFactoryBean(beanName)) {
if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
result.add(beanName);
// Match found for this bean: do not match FactoryBean itself anymore.
continue;
}
// In case of FactoryBean, try to match FactoryBean itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
}
// Match raw bean instance (might be raw FactoryBean).
if (isTypeMatch(beanName, type)) {
result.add(beanName);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Shouldn't happen - probably a result of circular reference resolution...
logger.trace(LogMessage.format(
"Failed to check manually registered singleton with name '%s'", beanName), ex);
}
}
return StringUtils.toStringArray(result);
}
大体的分析就是上面的这个样子了, 这个途中,有好几个缓存。
一个问题
如果有两个FactoryBean都生产同一个类型的Bean,会怎么样?
想想上面的代码逻辑,如果找到了两个合适的bean,并且这个两个合适的bean,还没有Primary或者Priority的注解,就会走到这个判断,然后通过 nonUniqueAsNull
来判断是否要报错。
通过FactoryBean的机智,就能将一个没有经过标准的Spring生命周期的bean,居然可以通过Spring中的FactoryBean获取到,体现在代码就是getBean方法。那么这样做的好处是什么呢?为什么要这么做呢?
囿于篇幅,关于在Spring中,FactoryBean的具体的使用,之后再说。
关于博客这件事,我是把它当做我的笔记,里面有很多的内容反映了我思考的过程,因为思维有限,不免有些内容有出入,如果有问题,欢迎指出。一同探讨。谢谢。