上一篇spring getBean 源碼學(xué)習(xí)(上)基本上把getBean的過程細(xì)節(jié)了解清楚了,還剩下一些疑問以及沒有注意到的細(xì)節(jié)昼弟,本篇文章就來深入細(xì)節(jié)饲握,解析之前遺留的問題救欧,最好是配合著上篇一起看。
現(xiàn)在已知的存在不同類型(scope)的bean被存儲在容器中
并不存在這樣的铝耻,spring整個的bean管理容器是DefaultListableBeanFactory
,他有很多個線程安全或者線程不安全的容器存有不同類型的數(shù)據(jù)蹬刷,可是具體bean的信息是存儲在BeanDefinition
中的办成,在AbstractBeanDefinition
中有個scope的數(shù)據(jù),他就存儲著bean的具體類型某弦,在使用的時候直接判斷其scope即可
把獲取的bean列表 循環(huán)一遍依次實例化靶壮、填充數(shù)據(jù)
是這樣操作的员萍,在解析xml的時候,finishBeanFactoryInitialization方法會實例化所有還沒處理的single對象
有一個問題不知道有沒有想到螃壤,實際開發(fā)中很少有使用getBean操作去獲取相應(yīng)bean映穗,那么那些注解依賴的bean是如何生成的呢?下面是我們使用的demo聊一聊這個問題
Teacher類加上了Component這個注解,spring啟動的時候就會解析實例化這個類睦霎。
原因就在下面這個xml配置上
在spring xml的bean提取 源碼學(xué)習(xí)文章中對NameSpace進(jìn)行了詳細(xì)的解釋副女。在此不做過多說明蚣旱,直接看圖
很明顯了塞绿,相關(guān)bean的注冊操作就是依靠ComponentScanBeanDefinitionParser類完成异吻,xml文件掃描完成之后,在refresh中的finishBeanFactoryInitialization完成實例化操作棋返。如下代碼完成了bean的注冊工作雷猪。
ClassPathBeanDefinitionScanner 文件
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
for (String basePackage : basePackages) {
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
各種不同類型的容器酵颁,例如實例化好的月帝,正在實例化的嚷辅、正在被銷毀的距误、已經(jīng)銷毀的
如下代碼,在DefaultListableBeanFactory文件中有多種容器趁俊,以完成各種需求
// 工廠的序列號id寺擂,唯一性
private String serializationId;
// 允許bean出現(xiàn)覆蓋的情況
private boolean allowBeanDefinitionOverriding = true;
// 是否提前加載,而不需要關(guān)系是否存在懶加載的情況
private boolean allowEagerClassLoading = true;
// 針對依賴列表的選擇器
private Comparator<Object> dependencyComparator;
// 目前還沒搞懂具體的含義
private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
// 依賴對應(yīng)的具體對象
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<Class<?>, Object>(16);
// 存儲bean的容器垦细,以name為key
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
// 以className為key的線程安全的容器括改,包括了single和非single(prototype)
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64);
// 單例single的容器家坎,以className為key
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64);
// beanName 為集合的list
private volatile List<String> beanDefinitionNames = new ArrayList<String>(256);
...
其中關(guān)鍵字allowBeanDefinitionOverriding很有意思虱疏,是關(guān)于重名bean的订框,可以查看spring 同名bean問題 源碼學(xué)習(xí) 具體了解其中的用法
填充數(shù)據(jù)這部分操作得支持@value
等類似操作
@value作為一個注解,在填充到bean中肯定需要從配置文件獲取其值衩侥,然后才可以設(shè)置類的字段意思矛物。接下來就具體學(xué)習(xí)下其中的原理
ComponentScanBeanDefinitionParser 類
這個類是為<context:component-scan base-package="com.demo"/>
履羞,他會注入接下來需要使用的AutowiredAnnotationBeanPostProcessor
類
接下來峦萎,在填充值的時候就會利用到AutowiredAnnotationBeanPostProcessor類了。
AutowiredAnnotationBeanPostProcessor 文件
從populateBean函數(shù)進(jìn)入的忆首,設(shè)置屬性值
public PropertyValues postProcessPropertyValues(PropertyValues pvs,
PropertyDescriptor[] pds, Object bean, String beanName)
throws BeanCreationException {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
// 從該AutowiredAnnotationBeanPostProcessor的cache中獲取該名稱的注入元類信息
try {
metadata.inject(bean, beanName, pvs);
// 注入值
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
InjectionMetadata 文件
public void inject(Object target, String beanName, PropertyValues pvs)
throws Throwable {
Collection<InjectedElement> elementsToIterate =
(this.checkedElements != null ? this.checkedElements : this.injectedElements);
// 獲取的元素一次循環(huán)進(jìn)行注入inject操作
if (!elementsToIterate.isEmpty()) {
boolean debug = logger.isDebugEnabled();
for (InjectedElement element : elementsToIterate) {
if (debug) {
logger.debug("Processing injected element of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, pvs);
}
}
}
AutowiredAnnotationBeanPostProcessor 文件
protected void inject(Object bean, String beanName, PropertyValues pvs)
throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
// 調(diào)用bean工廠DefaultListableBeanFactory 的解決依賴功能
// 得到其真實的值
// TODO 目前也沒看懂具體的細(xì)節(jié)爱榔,(/_\)
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName)) {
if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
// 最后直接修改這個field的屬性值
field.set(bean, value);
}
}
}
總結(jié):其實沒有非常理解其在賦值的操作細(xì)節(jié),跨度太長糙及,不過也清楚了如果需要使用依賴注入的功能更详幽,則一定需要在xml中加入<context:component-scan base-package="com.demo"/>
這樣類似的話。
對外提供各種接口唇聘,便于用戶可以自定義操作bean(例如BeanPostProcessor)
在spring中確實發(fā)現(xiàn)了很多的繼承自BeanPostProcessor的類版姑,beanfactory通過getBeanPostProcessor方法獲得所有的BeanPostProcessor,然后通過類型篩選取得需要的對象迟郎,依次處理被管理的bean剥险。如我們之前說的Spring 鉤子之BeanFactoryPostProcessor和BeanPostProcessor的源碼學(xué)習(xí) 同樣是BeanPostProcessor的一種∠苄ぃ基本上所有的使用的套路都是這樣的表制,如下圖中還存在自定義的CustomBeanPostProcessor
PS:在idea中可以通過Ctrl+H
查看該類繼承圖
相互引用的情況,A引用B匈庭,B引用A該如何解決
這里存在兩種依賴情況
- 構(gòu)造器依賴
構(gòu)造器依賴意味著引用的對象必須實例化夫凸,可是這樣就導(dǎo)致了A等著B的實例化,B又等著A的實例化阱持,造成了死鎖一般的情況夭拌,會提示錯誤
- set依賴
set依賴原則上來說是沒問題的,只需要選擇一個先實例化即可衷咽,但是官方并不推薦這樣做鸽扁,而是推薦修改業(yè)務(wù)邏輯,使用其他方法實現(xiàn)
這一節(jié)基本上就到此結(jié)束了镶骗,大概的說了一些之前忽略的點桶现,其實還有幾個點可以細(xì)說,限于精力鼎姊,后續(xù)會繼續(xù)介紹同名Bean的處理情況以及BeanPostProcessor等