当前位置: 代码迷 >> 综合 >> Spring源码解析 - FactoryBean&&BeanFactory
  详细解决方案

Spring源码解析 - FactoryBean&&BeanFactory

热度:0   发布时间:2024-01-30 17:30:58.0

何时使用FactoryBean?

FactoryBean是一个工厂Bean,可生成某一个类型的Bean实例。
最大作用:让我们能够自定义Bean的创建过程。

而在BeanFactory中可创建和管理Spring容器中的Bean,它对Bean的创建有一个统一的流程。

1 FactoryBean

定义

  • 泛型接口

API

  • 返回Bean对象实例

  • Bean类型

  • 是否单例。true是单例,false是非单例 。在Spring5.x利用Java8新特性变成default方法,返回true

2 使用FactoryBean

//FactoryBean接口实现类
@Component
public class FactoryBeanLearn implements FactoryBean {@Overridepublic Object getObject() throws Exception {// 自己new,这里就可以控制Bean的创建过程return new FactoryBeanServiceImpl();}@Overridepublic Class<?> getObjectType() {return FactoryBeanService.class;}@Overridepublic boolean isSingleton() {return true;}
}接口
public interface FactoryBeanService {/*** 测试FactoryBean*/void testFactoryBean();
}//实现类
public class FactoryBeanServiceImpl implements FactoryBeanService {@Overridepublic void testFactoryBean() {System.out.println("我是FactoryBean的一个测试类。。。。");}
}测试类
@Test
public void test() {ClassPathXmlApplicationContext cac = new ClassPathXmlApplicationContext("classpath:com/javaedge/applicationContext.xml");FactoryBeanService beanService = cac.getBean(FactoryBeanService.class);beanService.testFactoryBean();}

从Spring容器中获取了FactoryBeanService类型的Bean。那么这个获取Bean的过程Spring是怎么处理的呢?它是怎么从FactoryBean中获取我们自己创建的Bean实例的呢?

先从getBean这个方法看起,在Spring的AbstractApplicationContext中有很多重载的getBean方法,这里调用根据Type(Class类型)来获取的Bean信息。我们传入type是FactoryBeanService类型。

getBean

AbstractApplicationContext#getBean(java.lang.Class)

DefaultListableBeanFactory#getBean(java.lang.Class)


resolveBean

	@Nullableprivate <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {// 解析BeanNamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);if (namedBean != null) {return namedBean.getBeanInstance();}// 如果当前Spring容器中没获取到对应Bean信息,则从父容器获取BeanFactory parent = getParentBeanFactory();if (parent instanceof DefaultListableBeanFactory) {return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull);}else if (parent != null) {ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);if (args != null) {return parentProvider.getObject(args);}else {return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());}}return null;}

关注的是resolveNamedBean方法:

	@SuppressWarnings("unchecked")@Nullableprivate <T> NamedBeanHolder<T> resolveNamedBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {Assert.notNull(requiredType, "Required type must not be null");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<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));}}String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());if (candidateName == null) {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);}if (!nonUniqueAsNull) {throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());}}return null;}
	@SuppressWarnings("unchecked")@Nullableprivate <T> NamedBeanHolder<T> resolveNamedBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {Assert.notNull(requiredType, "Required type must not be null");// 该方法根据传入的Class类型获取BeanName,因为有接口有多个实现类情况,所以这里返回是String数组。// 调用getBean方法传入的type为com.javaedge.FactoryBeanService类型,但没有在Spring容器中注入FactoryBeanService类型的Bean// 所以讲道理在这里应该获取不到beanName,事实是这样吗?看对getBeanNamesForType的分析String[] candidateNames = getBeanNamesForType(requiredType);// 有多个BeanName,则挑最合适的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);}}// 如果只有一个BeanName,调用getBean获取Bean实例放到NamedBeanHolder// todoif (candidateNames.length == 1) {String beanName = candidateNames[0];return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));}// 经过挑选后,如果合适的BeanName还是多个else if (candidateNames.length > 1) {Map<String, Object> candidates = new LinkedHashMap<>(candidateNames.length);for (String beanName : candidateNames) {// 看看是不是已经创建过的单例Beanif (containsSingleton(beanName) && args == null) {Object beanInstance = getBean(beanName);candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));}else {// 调用getType继续获取Bean实例candidates.put(beanName, getType(beanName));}}// 有多个Bean实例,则取带有Primary注解或者带有Primary信息的String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());if (candidateName == null) {// 如果没有Primary注解或者Primary相关的信息,则取优先级高的BeancandidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());}if (candidateName != null) {Object beanInstance = candidates.get(candidateName);// Class类型的话 继续调用getBean获取Bean实例if (beanInstance == null || beanInstance instanceof Class) {beanInstance = getBean(candidateName, requiredType.toClass(), args);}return new NamedBeanHolder<>(candidateName, (T) beanInstance);}if (!nonUniqueAsNull) {// 都没获取到,抛出异常throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());}}return null;}

上面的代码中我们传入的type是com.javaedge.FactoryBeanService类型,但是在我们的Spring容器中却没有FactoryBeanService类型的Bean,那么我们是怎么从getBeanNamesForType获取到beanName的?

getBeanNamesForType



	@Overridepublic String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {if (!isConfigurationFrozen() || type == null || !allowEagerInit) {return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);}// 先从缓存获取Map<Class<?>, String[]> cache =(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);String[] resolvedBeanNames = cache.get(type);if (resolvedBeanNames != null) {return resolvedBeanNames;}// 调用doGetBeanNamesForType获取beanNameresolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);// 所传入类能否被当前类加载所加载if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {// 放到缓存,解析一次后从缓存中获取// 这里对应到我们这里 K:FactoryBeanService,V:beanFactoryLearncache.put(type, resolvedBeanNames);}return resolvedBeanNames;}

doGetBeanNamesForType

	private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {List<String> result = new ArrayList<>();// 循环所有beanName,这个是在Spring容器启动解析Bean的时候放入到这个List中的// 校验所有 bean definitionsfor (String beanName : this.beanDefinitionNames) {// Only consider bean as eligible if the bean name is not defined as alias for some other bean.// 如果未将 bean name 定义为其他bean的别名,则仅将bean视为可选if (!isAlias(beanName)) {try {// 根据 beanName 获取 RootBeanDefinitionRootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);// Only check bean definition if it is complete.// RootBeanDefinition 的 Bean 不是抽象类、非延迟初始化if (!mbd.isAbstract() && (allowEagerInit ||(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&!requiresEagerInitForType(mbd.getFactoryBeanName()))) {// 是否为 FactoryBean 的子类boolean isFactoryBean = isFactoryBean(beanName, mbd);BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();boolean matchFound = false;boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName));boolean isNonLazyDecorated = (dbd != null && !mbd.isLazyInit());if (!isFactoryBean) {if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {// 如果isTypeMatch返回true,则把这个beanName即 factoryBeanLearn 放入到result中返回matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);}}else  {if (includeNonSingletons || isNonLazyDecorated ||(allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);}if (!matchFound) {// 如果不匹配,还是FactoryBean的子类 这里会把beanName变为 &beanName// 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);}}}// 这里的Bean是Spring容器创建的特殊的几种Bean ,如Environment// 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);}

FactoryBeanLearn是FactoryBean类型的,所以上面代码中会调用isTypeMatch判断FactoryBeanLearn是不是和传入类型匹配。这里是值:FactoryBeanService类。

isTypeMatch

类型匹配判断

	protected boolean isTypeMatch(String name, ResolvableType typeToMatch, boolean allowFactoryBeanInit)throws NoSuchBeanDefinitionException {// 转换beanName,我们的beanName为factoryBeanLearn 因为上面循环了Spring容器中的所有的BeanString beanName = transformedBeanName(name);boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name);// 因为我们这里是用的AbstractApplicationContext的子类从Spring容器获取Bean// 获取beanName为factoryBeanLearn的Bean实例,这里是可以获取到Bean实例的// Check manually registered singletons.Object beanInstance = getSingleton(beanName, false);if (beanInstance != null && beanInstance.getClass() != NullBean.class) {// factoryBeanLearn是FactoryBean的实现类if (beanInstance instanceof FactoryBean) {// 判断beanName是不是&开头,这里明显不是if (!isFactoryDereference) {// 从factoryBeanLearn中获取type类型Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance);// 从factoryBeanLearn中获取到的type类型和传入类型是否一致,是则返回return (type != null && typeToMatch.isAssignableFrom(type));}...

getTypeForFactoryBean

	@Nullableprotected Class<?> getTypeForFactoryBean(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;}}

在调用factoryBeanLearn的getObjectType方法时,获取到的值为:com.javaedge.FactoryBeanService和我们传入type是一样的类型。所以这里返回true,根据我们上面说的如果isTypeMatch返回true的话,我们返回的beanName为factoryBeanLearn。

调用getBean(Class requiredType)方法根据类型获取容器中bean时
对应例子就是:根据类型FactoryBeanService从Spring容器中获取Bean(Spring容器中没有FactoryBeanService类型的BeanDefinition,但有一个Bean和FactoryBeanService这个类型有一些关系)。

Spring在根据type去获取Bean的时候,会先获取到beanName。
获取beanName的过程
先循环Spring容器中的所有的beanName
然后根据beanName获取对应的BeanDefinition,如果当前bean是FactoryBean的类型,则会从Spring容器中根据beanName获取对应的Bean实例,接着调用获取到的Bean实例的getObjectType方法获取到Class类型,判断此Class类型和我们传入的Class是否是同一类型。如果是则返回测beanName,对应到我们这里就是:根据factoryBeanLearn获取到FactoryBeanLearn实例,调用FactoryBeanLearn的getObjectType方法获取到返回值FactoryBeanService.class。和我们传入的类型一致,所以这里获取的beanName为factoryBeanLearn。
换句话说这里我们把factoryBeanLearn这个beanName映射为了:FactoryBeanService类型。即FactoryBeanService类型对应的beanName为factoryBeanLearn这是很重要的一点。

  相关解决方案