FactoryBean
友情提示:如果时间紧,任务重,可以直接查看页面最后的总结。
一提到FactoryBean,大家可能会立马想到BeanFactory,这两个单词已经被我混淆了不知多少次,总是记不住谁是谁的谁,这里其实就记住他们的最后一个单词去区分他们就好了(Bean、Factory),那么为了让大家对这两个概念有更清楚的了解,我们就来说一下他们两个之间的区别
从他们的尾部单词可知,FactoryBean是一个Bean,而BeanFactory是我们所说的容器,具有管理Bean的功能,前面我们已经讲述过BeanFactory相关的功能,这里我们不在过多的赘述,他俩的直观区别就是一个是bean,一个是管理bean的容器
FactoryBean是一种特殊的Bean,FactoryBean接口定义了三个方法
public interface FactoryBean<T> { String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType"; @Nullable //返回有FactoryBean创建的Bean实例,如果isSingleton()返回true,则该实例会放到Spring容器的单实例缓存池中。 T getObject() throws Exception; @Nullable //返回FactoryBean创建Bean的类型。 Class<?> getObjectType(); //确定由FactoryBean创建Bean的作用域是singleton还是prototype. default boolean isSingleton() { return true; } }
一般,我们都会通过实现Spring内部中的FactoryBean接口去创建一个自定义的factorybean
@Component public class FactoryBeanTest implements FactoryBean { @Override public Object getObject() throws Exception { return new ObjectBean(); } @Override public Class<?> getObjectType() { return ObjectBean.class; } }
package com.beans; public class ObjectBean { }
然后再在配置类中去获取在getObject()方法中生成的ObjectBean对象
@ComponentScan("com.beans") public class mainT { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(mainT.class); System.out.println(context.getBean("factoryBeanTest")); System.out.println(context.getBean("factoryBeanTest")); System.out.println(context.getBean("factoryBeanTest")); //System.out.println(context.getBean("&factoryBeanTest")); } }
在这里提出一个疑问:上述获得的三个Bean是否是同一个?
答案 : 是同一个 ,因为FactoryBean中有一个默认的方法,是否是单例,默认为true,如果想得到非单例,可以重写这个默认方法
default boolean isSingleton() { return true; }
即默认是单例的。
在提出一个疑问?上述4个Bean得到的是否是同一个类
答案:不是
System.out.println(context.getBean("factoryBeanTest")); System.out.println(context.getBean("factoryBeanTest")); System.out.println(context.getBean("factoryBeanTest")); //com.beans.ObjectBean@77f80c04 //com.beans.ObjectBean@77f80c04 //com.beans.ObjectBean@77f80c04 System.out.println(context.getBean("&factoryBeanTest")); //com.beans.FactoryBeanTest@1dac5ef
上面的注释是每一个输出语句输出的结果,可以发现上方三个beanName没有加&号的得到的bean是在FactoryBean中getObject方法new的类,而加了&符号的得到的是FactoryBean自身。
所以当你需要得到FactoryBean自身的话,在getBean的时候要在BeanName前加上一个或多个&即可。
那么Spring如何去处理这个名字呢,我们可以看一下Spring中的源码
//返回BeanName,去掉FatoryBean的&前缀,并且把name当作别名去aliasMap中寻找原始的beanName protected String transformedBeanName(String name) { return canonicalName(BeanFactoryUtils.transformedBeanName(name)); } public static String transformedBeanName(String name) { Assert.notNull(name, "'name' must not be null"); if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { return name; } //如果BeanName以&开头,截取&后的beanname,并且把截取前后的name存储到transformedBeanNameCache中 return transformedBeanNameCache.computeIfAbsent(name, beanName -> { do { beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); } while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)); return beanName; }); }
public String canonicalName(String name) { String canonicalName = name; // Handle aliasing... String resolvedName; do { //去找原始beanName,aliasMap:{别名:原始名} resolvedName = this.aliasMap.get(canonicalName); if (resolvedName != null) { canonicalName = resolvedName; } } while (resolvedName != null); //如果通过别名找到原始beanName,则返回找出的原始beanName,如果没有找到,则返回传进来的BeanName return canonicalName; }
上述就是Spring处理这个beanName的方法,如果对上面代码有疑问或者不接,可以看作者做得一个流程图,来帮助您加深记忆,更容易理解
这里要说一下,Spring在getbean之前也就是在启动的时候就会把FactoryBeanTest都加载到的BeanFactory中的单例池中,但没有加载ObjectBean。
那么除了FactoryBean以外还可以通过什么来new一个对象而得到一个bean呢
就是@Bean注解,如下面例子所示:
@Configuration public class mainConfiguration { @Bean public ObjectBean getObjectBean(){ return new ObjectBean(); } }
那么可以通过@Bean注解以一个相同的方法来得到一个Bean,为什么还需要FactoryBean来定义一个Bean呢?因为当一个类继承了FactoryBean之后,它还可以继承其他的类和接口,起到一个拓展的作用。
public class FactoryBeanTest implements FactoryBean, BeanFactoryPostProcessor...
那么在getBean方法中是如何去判断这个Bean是不是一个FactoryBean以及如何加载getObject()方法中取到得对象为bean得呢
我们一同来看一下getBean()方法的源码,只需要看前半部分即可
protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { //返回BeanName,去掉FatoryBean的&前缀,并且把name当作别名去aliasMap中寻找原始的beanName String beanName = transformedBeanName(name); Object beanInstance; // 根据beanName从单例池中获取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 + "'"); } } //判断sharedInstance是不是FactoryBean beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null); } // else { // // Fail if we're already creating this bean instance: // // We're assumably within a circular reference. // if (isPrototypeCurrentlyInCreation(beanName)) { // throw new BeanCurrentlyInCreationException(beanName); // } // // // Check if bean definition exists in this factory. // BeanFactory parentBeanFactory = getParentBeanFactory(); // if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // // Not found -> check parent. // String nameToLookup = originalBeanName(name); // if (parentBeanFactory instanceof AbstractBeanFactory) { // return ((AbstractBeanFactory) parentBeanFactory).doGetBean( // nameToLookup, requiredType, args, typeCheckOnly); // } // else if (args != null) { // // Delegation to parent with explicit args. // return (T) parentBeanFactory.getBean(nameToLookup, args); // } // else if (requiredType != null) { // // No args -> delegate to standard getBean method. // return parentBeanFactory.getBean(nameToLookup, requiredType); // } // else { // return (T) parentBeanFactory.getBean(nameToLookup); // } // } // //父子容器都没有才去创建 // if (!typeCheckOnly) { // markBeanAsCreated(beanName); // } // // StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate") // .tag("beanName", name); // try { // if (requiredType != null) { // beanCreation.tag("beanType", requiredType::toString); // } // RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // checkMergedBeanDefinition(mbd, beanName, args); // // // Guarantee initialization of beans that the current bean depends on. // String[] dependsOn = mbd.getDependsOn(); // if (dependsOn != null) { // for (String dep : dependsOn) { // //判断beanName是不是也被dep依赖了,如果是,就是相互依赖 // if (isDependent(beanName, dep)) { // throw new BeanCreationException(mbd.getResourceDescription(), beanName, // "Circular depends-on relationship between '" + beanName + "' and '" + //dep + "'"); // } // //加载依赖的bean // //存在在两个map中 // //1、dependentBeanMap ,key为dep,value是一个LinkedHashSet,表示dep被哪些bean依赖了 // //2、dependenciesForBeanMap key为beanName,value是一个LinkedHashSet,表示beanName依赖了哪些bean // registerDependentBean(dep, beanName); // try { // //先去生成所依赖的bean // getBean(dep); // } // catch (NoSuchBeanDefinitionException ex) { // throw new BeanCreationException(mbd.getResourceDescription(), beanName, // "'" + beanName + "' depends on missing bean '" + dep + "'", ex); // } // } // } // // // Create bean instance. // if (mbd.isSingleton()) { // sharedInstance = getSingleton(beanName, () -> { // try { // return createBean(beanName, mbd, args); // } // catch (BeansException ex) { // // Explicitly remove instance from singleton cache: It might have been put there // // eagerly by the creation process, to allow for circular reference resolution. // // Also remove any beans that received a temporary reference to the bean. // destroySingleton(beanName); // throw ex; // } // }); // //sharedInstance可能是一个FactoryBean,所以需要单独再去factoryBeanObjectCache中去获取对应的对象 // beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); // } // // else if (mbd.isPrototype()) { // // It's a prototype -> create a new instance. // Object prototypeInstance = null; // try { // beforePrototypeCreation(beanName); // prototypeInstance = createBean(beanName, mbd, args); // } // finally { // afterPrototypeCreation(beanName); // } // beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); // } // //其他的scope request,session // else { // String scopeName = mbd.getScope(); // if (!StringUtils.hasLength(scopeName)) { // throw new IllegalStateException("No scope name defined for bean ´" + beanName + //"'"); // } // Scope scope = this.scopes.get(scopeName); // if (scope == null) { // throw new IllegalStateException("No Scope registered for scope name '" + scopeName + //"'"); // } // try { // Object scopedInstance = scope.get(beanName, () -> { // beforePrototypeCreation(beanName); // try { // return createBean(beanName, mbd, args); // } // finally { // afterPrototypeCreation(beanName); // } // }); // beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); // } // catch (IllegalStateException ex) { // throw new ScopeNotActiveException(beanName, scopeName, ex); // } // } // } // catch (BeansException ex) { // beanCreation.tag("exception", ex.getClass().toString()); // beanCreation.tag("message", String.valueOf(ex.getMessage())); // cleanupAfterBeanCreationFailure(beanName); // throw ex; // } // finally { // beanCreation.end(); // } // } // // return adaptBeanInstance(name, beanInstance, requiredType); // }
/** * @param beanInstance 从单例池中获取到的bean * @param name 原始name(没有经过任何处理,比如,没有去掉&符号) * @param beanName 经过转换后的name(例如:去掉了&符号) * @param mbd null * @return */ 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. //如果是&FactoryBean,那么直接返回单例池中的对象,这里就是判断原始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没有继承FactoryBean且beanName没有以&开头,则认为是普通bean,直接返回 if (!(beanInstance instanceof FactoryBean)) { return beanInstance; } // 如果beanInstance是FactoryBean且BeanName是以&开头的 Object object = null; if (mbd != null) { mbd.isFactoryBean = true; } else { //首先去缓存中通过BeanName获取getObject方法得到的bean(这是为单例准备的) object = getCachedObjectForFactoryBean(beanName); } //从factoryBeanObjectCache中没有拿到则进行创建 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)) { //获取合并后beanDefinition mbd = getMergedLocalBeanDefinition(beanName); } boolean synthetic = (mbd != null && mbd.isSynthetic()); //调用getObject方法得到对象并放入factoryBeanObjectCache中 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) { //调用getObject方法得到一个对象 object = doGetObjectFromFactoryBean(factory, beanName); // Only post-process and store if not put there already during getObject() call above // (e.g. because of circular reference processing triggered by custom getBean calls) 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 { //调用BeanPostProcessor执行初始化后的逻辑,主要就是进行AOP object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", ex); } finally { afterSingletonCreation(beanName); } } //如果是单例的,存入factoryBeanObjectCache中 //{工厂bean的名(没有&符号):getObject()方法中new的新对象} if (containsSingleton(beanName)) { this.factoryBeanObjectCache.put(beanName, object); } } } return object; } } //当FactoryBean不是单例的情况下 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; } }
下面是一个流程图,帮您加深印象以及能够更好得了解上面得过程
总结:
1、什么是FactoryBean
FactoryBean本质上是一个Bean,但他是一个特殊的Bean,而是一个能够生产和修饰对象生成的工厂Bean。
2、FactoryBean与BeanFactory的区别
如1所说,FactoryBean本质上是一个Bean,但他比较特殊,它是可以生产和修饰对象生成的工厂Bean。
BeanFactory本质上是一个容器,所有Bean都是由BeanFactory来管理的,BeanFactory是一个接口,提供了IOC容器应遵守的最基本的接口,他的核心实现类是DefaultListableBeanFactory。
3、FactoryBean生产的Bean默认是单例的还是多例的
默认是单例的,可以重写它的isSingleton()方法,修改返回值为false即可变为多例
4、如何获得FactoryBean本身这个Bean
可以通过在beanName前加上一个或多个&符号来获取
例如:getBean("&FactoryBean的名字")