在上篇博客中【源码Spring系列】——彻底搞懂BeanFactory和FactoryBean不同讲解了两者的不同,先确定两者的作用并不一样,本文主要讲解Spring是怎样从FactoryBean获取我们自己创建的Bean实例。
何为FactoryBean?
public interface FactoryBean {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class> getObjectType();
default boolean isSingleton() {
return true;
}
}
从上述代码的定义中可以发现FactoryBean中定义了一个Spring Bean重要的三个特性:是否单例,Bean类型,Bean实例。也证明了FactoryBean本身就是一个Bean。下面写一个关于FactoryBean的应用,在从源码角度解析Spring容器是如何从FactoryBean中获取创建的Bean实例。
public class User {
public User() {
System.out.println("调用构造器User()");
}
public void testUser() {
System.out.println("user类被调用了");
}
}
@Component
public class MyFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
return new User();
}
@Override
public Class> getObjectType() {
return User.class;
}
}
@Service
public class UserService {
@Autowired
private User user;
public UserService(){
System.out.println("调用构造器UserService()");
}
public User getUser() {
return user;
}
}
@ComponentScan("mandy.com")
@Configuration
public class AppConfig {
}
@Test
public void test(){
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
User user = context.getBean(User.class);
user.testUser();
System.out.println(context.getBean("userService"));
UserService userService = (UserService) context.getBean("userService");
System.out.println(userService.getUser());
}
从上述代码以及打印结果中可以知道,我们从Spring容器中获得了User类型的Bean,并且成功注入到UserService中。那么这个获取Bean的过程,以及注入Bean的过程在Spring容器中是怎么处理的呢?
org.springframework.beans.factory.support.DefaultListableBeanFactory#getBean(java.lang.Class
public T getBean(Class requiredType) throws BeansException {
return this.getBean(requiredType, (Object[])null);
}
public T getBean(Class requiredType, @Nullable Object... args) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
//解析bean
Object resolved = this.resolveBean(ResolvableType.forRawClass(requiredType), args, false);
if (resolved == null) {
throw new NoSuchBeanDefinitionException(requiredType);
} else {
return resolved;
}
}
@Nullable
private T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
//关键点 根据传入的Class类型来获取BeanName
NamedBeanHolder namedBean = this.resolveNamedBean(requiredType, args, nonUniqueAsNull);
if (namedBean != null) {
return namedBean.getBeanInstance();
} else {
//如果当前Spring容器中没有获取到相应的Bean信息,则从父容器中获取
//SpringMVC是一个很典型的父子容器
BeanFactory parent = this.getParentBeanFactory();
if (parent instanceof DefaultListableBeanFactory) {
return ((DefaultListableBeanFactory)parent).resolveBean(requiredType, args, nonUniqueAsNull);
} else if (parent != null) {
ObjectProvider parentProvider = parent.getBeanProvider(requiredType);
if (args != null) {
return parentProvider.getObject(args);
} else {
return nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable();
}
} else {
return null;
}
}
}
重点关注org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveNamedBean(org.springframework.core.ResolvableType, java.lang.Object[], boolean)
@Nullable
private NamedBeanHolder resolveNamedBean(
ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
//我们调用getBean方法传入的是mandy.com.bean.User类型,但是并没有在Spring容器中注入User类型的Bean
//理论上是获取不到beanName的,但是通过getBeanNamesForType却拿到了
String[] candidateNames = getBeanNamesForType(requiredType);
//如果有多个BeanName,则挑选合适的BeanName
if (candidateNames.length > 1) {
List 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中
if (candidateNames.length == 1) {
String beanName = candidateNames[0];
return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
}
else if (candidateNames.length > 1) {
//如果合适的BeanName还是有多个的话
Map candidates = new LinkedHashMap<>(candidateNames.length);
for (String beanName : candidateNames) {
//判断是不是已经创建多的单例Bean
if (containsSingleton(beanName) && args == null) {
Object beanInstance = getBean(beanName);
candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
}
else {
//调用getType方法继续获取Bean实例
candidates.put(beanName, getType(beanName));
}
}
String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());
if (candidateName == null) {
//如果没有Primary注解或者Primary相关的信息,则去优先级高的Bean实例
candidateName = 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;
}
怎么从org.springframework.beans.factory.support.DefaultListableBeanFactory#getBeanNamesForType(org.springframework.core.ResolvableType)中获取到的beanName呢?
@Override
public String[] getBeanNamesForType(@Nullable Class> type, boolean includeNonSingletons, boolean allowEagerInit) {
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
}
//先从缓存中获取
Map, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
String[] resolvedBeanNames = cache.get(type);
if (resolvedBeanNames != null) {
return resolvedBeanNames;
}
//调用doGetBeanNamesForType方法获取beanName
resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
//所传入的类能不能被当前类加载加载
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
//这里对应到我们这里 key是User Value是MyFactoryBean
cache.put(type, resolvedBeanNames);
}
return resolvedBeanNames;
}
咱们今天先不看doGetBeanNamesForType方法,咱们看下allBeanNamesByType
private final Map, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
getObject() bean singletonObjects myFactoryBean
getObjectType() User.class--映射--myFactoryBean
allBeanNamesByType: User.class:myFactoryBean factoryBeanObjectCache
allBeanNamesByType 就是FactoryBean按bean类型存储的Map,使得类可以通过getObjectType() 被找到。
这也就是factoryBeanObjectCache,与allBeanNamesByType的关系