【Spring源碼系列】——徹底搞懂FactoryBean

       在上篇博客中【源碼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的關係

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章