在上篇博客中【源碼Spring系列】——徹底搞懂BeanFactory和FactoryBean不同講解了兩者的不同,先確定兩者的作用並不一樣,本文主要講解Spring是怎樣從FactoryBean獲取我們自己創建的Bean實例。
何爲FactoryBean?
public interface FactoryBean<T> {
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<T>)
public <T> T getBean(Class<T> requiredType) throws BeansException {
return this.getBean(requiredType, (Object[])null);
}
public <T> T getBean(Class<T> 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> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
//關鍵點 根據傳入的Class類型來獲取BeanName
NamedBeanHolder<T> 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<T> 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 <T> NamedBeanHolder<T> 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<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中
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<String, Object> 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<Class<?>, 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<Class<?>, 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的關係