Spring Framework 组件注册 之 FactoryBean (3)

isTypeMatch()方法中的部分代码

public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException { // 对beanName进行处理,将开头的 & 符过滤 String beanName = transformedBeanName(name); // 从spring容器中获取单实例Bean,由于spring容器启动时已经将单实例Bean进行了实例化, // 所以此时可以直接在容器中得到Bean实例 Object beanInstance = getSingleton(beanName, false); if (beanInstance != null && beanInstance.getClass() != NullBean.class) { // 获取到Bean实例后,判断是否为工厂Bean if (beanInstance instanceof FactoryBean) { // 如果是工厂Bean,并且获取的beanName不是以&符开头 if (!BeanFactoryUtils.isFactoryDereference(name)) { // 将实例强转为 FactoryBean 并调用 FactoryBean接口的getObjectType()方法, // 获取工厂Bean所生产的实例类型 Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance); // 判断工厂Bean生产的实例类型与传入的类型是否匹配 return (type != null && typeToMatch.isAssignableFrom(type)); } else { return typeToMatch.isInstance(beanInstance); } } // ...省略代码... } // ...省略代码... }

getTypeForFactoryBean()方法中的代码

protected Class<?> getTypeForFactoryBean(final FactoryBean<?> factoryBean) { try { if (System.getSecurityManager() != null) { return AccessController.doPrivileged((PrivilegedAction<Class<?>>) factoryBean::getObjectType, getAccessControlContext()); } else { // 直接调用 FactoryBean 接口的 getObjectType()方法,获取生产的类型 return factoryBean.getObjectType(); } } catch (Throwable ex) { // Thrown from the FactoryBean's getObjectType implementation. logger.info("FactoryBean threw exception from getObjectType, despite the contract saying " + "that it should return null if the type of its object cannot be determined yet", ex); return null; } }

以上便是getBeanNamesForType()方法经过的部分重要代码

由此可以看出,当我们想要获取BikeFactoryBean本身的beanName时,doGetBeanNamesForType方法内部将bikeFactoryBean前添加了&符前缀,于是便获取到了&bikeFactoryBean;
当我们想要获取Bike类型的beanName时,spring会通过容器遍历已经注册的所有的beanNames,然后根据beanName及对应的Bean定义信息BeanDefinition进行判断过滤,并且对于所有的工厂Bean,会获取spring容器中已经实例化的Bean对象,调用 FactoryBean 接口的 getObjectType()方法,得到工厂Bean所生产的实例类型,然后与Bike.class相比较,如果匹配,则将此beanName保存到结果集中,最后返回。所以,当我们想要获取Bike类型的beanName时,从spring容器中便可以找到bikeFactoryBean。

从spring容器中获取到beanName后,我们继续获取Bike实例
从前文中引导类的代码可以看出,获取Bike实例有两种方式,跟踪源码可以发现,根据Bike类型获取实例时,spring实际是通过第二步获取到beanName后再最终调用doGetBean方法获取实例对象。下面看看部分源码

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // 对传入的beanName进行过滤,去除&符前缀 final String beanName = transformedBeanName(name); Object bean; // 从spring容器中获取实例,由于spring容器启动时已经将单实例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实例,如果是工厂bean,则为Bean实例本身或其创建的对象。 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } // ...省略代码... return (T) bean; }

从上面的代码可以看出,获取Bike实例的具体代码还在getObjectForBeanInstanc()方法内部,我们继续查看

protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { // 判断beanName是否是以&符开头的 if (BeanFactoryUtils.isFactoryDereference(name)) { if (beanInstance instanceof NullBean) { return beanInstance; } if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); } } // 根据beanName从spring容器中获取的Bean实例如果不是工厂Bean,或者beanName是以&符开头,就直接返回这个Bean实例 // 当我们获取Bike类型的实例时,beanName为“bikeFactoryBean”, // beanInstance为“BikeFactoryBean”类型,是一个工厂Bean,所以条件不满足,继续向下走 if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } Object object = null; if (mbd == null) { // 根据beanName从缓存中获取Bean实例,第一次来获取Bike实例时为空, // factoryBeanObjectCache.get(beanName); // 后续再获取时,便可以在此获得到,然后返回 object = getCachedObjectForFactoryBean(beanName); } if (object == null) { // 将获取的工厂Bean强转为 FactoryBean 类型,以便下面调用其getObject()方法获取对象 FactoryBean<?> factory = (FactoryBean<?>) beanInstance; // 获取bean定义信息 if (mbd == null && containsBeanDefinition(beanName)) { mbd = getMergedLocalBeanDefinition(beanName); } boolean synthetic = (mbd != null && mbd.isSynthetic()); //在此方法内部调用 FactoryBean 接口的 getObject()方法获取对象 object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfxsg.html