Spring BeanDefinition加载
Spring容器里通過BeanDefinition對(duì)象來表示Bean,BeanDefinition描述了Bean的配置信息。而BeanDefinitionRegistry接口提供了向容器注冊(cè),刪除,獲取BeanDefinition對(duì)象的方法。
Spring IOC容器啟動(dòng)的時(shí)候,需要加載Bean定義信息BeanDefinition,用到了幾個(gè)非常關(guān)鍵的類:
- AnnotatedBeanDefinitionReader
- ClassPathBeanDefinitionScanner
- XmlBeanDefinitionReader
BeanDefinition
繼承圖
BeanDefinition接口主要提供Bean的元數(shù)據(jù)描述信息,包括:類名、scope、屬性、構(gòu)造函數(shù)參數(shù)列表、依賴的bean、是否是單例類、是否是懶加載等。
public interface AttributeAccessor {void setAttribute(String name, @Nullable Object value);@NullableObject getAttribute(String name);@NullableObject removeAttribute(String name);boolean hasAttribute(String name);String[] attributeNames(); }public interface BeanMetadataElement {@Nullabledefault Object getSource() {return null;} }BeanDefinition繼承了AttributeAccessor,說明它具有處理屬性的能力;
BeanDefinition繼承了BeanMetadataElement,說明它可以持有Bean元數(shù)據(jù)元素,作用是可以持有XML文件的一個(gè)bean標(biāo)簽對(duì)應(yīng)的Object。
AnnotatedBeanDefinition
public interface AnnotatedBeanDefinition extends BeanDefinition {AnnotationMetadata getMetadata();@NullableMethodMetadata getFactoryMethodMetadata();}AbstractBeanDefinition
略
ChildBeanDefinition
public class ChildBeanDefinition extends AbstractBeanDefinition {@Nullableprivate String parentName; }RootBeanDefinition
一個(gè)RootBeanDefinition定義表明它是一個(gè)可合并的bean definition:即在spring beanFactory運(yùn)行期間,可以返回一個(gè)特定的bean。RootBeanDefinition可以作為一個(gè)重要的通用的bean definition 視圖。
RootBeanDefinition用來在配置階段進(jìn)行注冊(cè)bean definition。然后,從spring 2.5后,編寫注冊(cè)bean definition有了更好的的方法:GenericBeanDefinition。GenericBeanDefinition支持動(dòng)態(tài)定義父類依 賴,而非硬編碼作為root bean definition。其中RootBeanDefinition是最常用的實(shí)現(xiàn)類,它對(duì)應(yīng)一般性的元素標(biāo)簽
在 配置文件中可以定義父和子,父用RootBeanDefinition表示, 而子用ChildBeanDefiniton表示,而沒有父的就使用 RootBeanDefinition表示。
?
?
輔助類
BeanNameGenerator
BeanNameGenerator是bean Name的生成器。主要有2個(gè)實(shí)現(xiàn):
- DefaultBeanNameGenerator
- AnnotationBeanNameGenerator
?
DefaultBeanNameGenerator
默認(rèn)生成器,規(guī)則為:
1、如果有類名以類名作為name。
2、沒有類名,以父name +?"$child",沒有父name,以factory name +?"$created"
3、最后,如果是內(nèi)部bean,加?"#" 加上 對(duì)象hash的十六進(jìn)制表示。如果不是,加上 ?"#"? 加上同名排序后的序號(hào)
AnnotationBeanNameGenerator
注解生成器,規(guī)則為:
1、如果注解上有name,則以此為name,
2、否則為類的短名稱的駝峰寫法。
?
AnnotatedBeanDefinitionReader
屬性
//用于BeanDefinition注冊(cè)管理private final BeanDefinitionRegistry registry;//Bean名稱生成器private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;//private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();//private ConditionEvaluator conditionEvaluator;public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {this(registry, getOrCreateEnvironment(registry));}public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");Assert.notNull(environment, "Environment must not be null");this.registry = registry; //ConditionEvaluator完成條件注解的判斷,在Spring Boot中有大量的應(yīng)用this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); //這句會(huì)把一些自動(dòng)注解處理器加入到AnnotationConfigApplicationContext下的BeanFactory的BeanDefinitions中 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);}這里將AnnotationConfigApplicationContext注冊(cè)為管理BeanDefinition的BeanDefinitionRegistry,也就是說,spring中bean的管理完全交給了AnnotationConfigApplicationContext。
registerAnnotationConfigProcessors()
AnnotationConfigUtils#registerAnnotationConfigProcessors(),提供了一種極為方便注冊(cè)這些BeanPostProcessor的方式(若是xml方式,配置<context:annotation-config/>,若是全注解驅(qū)動(dòng)的ApplicationContext,就默認(rèn)會(huì)執(zhí)行)
主要功能是如果未注冊(cè)以下幾個(gè)PostProcessor,則注冊(cè)默認(rèn)類型:
- org.springframework.context.annotation.internalConfigurationAnnotationProcessor:ConfigurationClassPostProcessor
ConfigurationClassPostProcessor是一個(gè)BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor處理器,BeanDefinitionRegistryPostProcessor的處理方法能處理@Configuration等注解。ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法內(nèi)部處理@Configuration,@Import,@ImportResource和類內(nèi)部的@Bean。
- org.springframework.context.annotation.internalAutowiredAnnotationProcessor:AutowiredAnnotationBeanPostProcessor
AutowiredAnnotationBeanPostProcessor是用來處理@Autowired注解和@Value注解的
- org.springframework.context.annotation.internalCommonAnnotationProcessor:CommonAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor提供對(duì)JSR-250規(guī)范注解的支持@javax.annotation.Resource、@javax.annotation.PostConstruct和@javax.annotation.PreDestroy等的支持。
- org.springframework.context.annotation.internalPersistenceAnnotationProcessor:internalPersistenceAnnotationProcessor
internalPersistenceAnnotationProcessor提供@PersistenceContext的支持。
- org.springframework.context.event.internalEventListenerProcessor:EventListenerMethodProcessor
EventListenerMethodProcessor提供@ EventListener 的支持。@ EventListener實(shí)在spring4.2之后出現(xiàn)的,可以在一個(gè)Bean的方法上使用@EventListener注解來自動(dòng)注冊(cè)一個(gè)ApplicationListener。
- org.springframework.context.event.internalEventListenerFactory:DefaultEventListenerFactory
?
?
注冊(cè)bean
public void register(Class<?>... componentClasses) {for (Class<?> componentClass : componentClasses) {registerBean(componentClass);}}public void registerBean(Class<?> beanClass) {doRegisterBean(beanClass, null, null, null, null);}public void registerBean(Class<?> beanClass, @Nullable String name) {doRegisterBean(beanClass, name, null, null, null);}@SuppressWarnings("unchecked")public void registerBean(Class<?> beanClass, Class<? extends Annotation>... qualifiers) {doRegisterBean(beanClass, null, qualifiers, null, null);}@SuppressWarnings("unchecked")public void registerBean(Class<?> beanClass, @Nullable String name,Class<? extends Annotation>... qualifiers) {doRegisterBean(beanClass, name, qualifiers, null, null);}public <T> void registerBean(Class<T> beanClass, @Nullable Supplier<T> supplier) {doRegisterBean(beanClass, null, null, supplier, null);}public <T> void registerBean(Class<T> beanClass, @Nullable String name, @Nullable Supplier<T> supplier) {doRegisterBean(beanClass, name, null, supplier, null);}public <T> void registerBean(Class<T> beanClass, @Nullable String name, @Nullable Supplier<T> supplier,BeanDefinitionCustomizer... customizers) {doRegisterBean(beanClass, name, null, supplier, customizers);}?
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,@Nullable BeanDefinitionCustomizer[] customizers) {// 先把此實(shí)體類型轉(zhuǎn)換為一個(gè)BeanDefinitionAnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);//abd.getMetadata() 元數(shù)據(jù)包括注解信息、是否內(nèi)部類、類Class基本信息等等// 此處由conditionEvaluator#shouldSkip去過濾,此Class是否是配置類// 大體邏輯為:必須有@Configuration注解。然后解析一些Condition注解,看是否排除~if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {return;}abd.setInstanceSupplier(supplier);// 解析ScopeScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);abd.setScope(scopeMetadata.getScopeName());// 得到Bean的名稱 一般為首字母小寫(此處為AnnotationBeanNameGenerator)String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));// 設(shè)定一些注解默認(rèn)值,如lazy、Primary等等AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);if (qualifiers != null) {// 解析qualifiers,若有此注解 則primary都成為true了for (Class<? extends Annotation> qualifier : qualifiers) {if (Primary.class == qualifier) {abd.setPrimary(true);}else if (Lazy.class == qualifier) {abd.setLazyInit(true);}else {abd.addQualifier(new AutowireCandidateQualifier(qualifier));}}}// 自定義定制信息(一般都不需要)if (customizers != null) {for (BeanDefinitionCustomizer customizer : customizers) {customizer.customize(abd);}}// 下面為解析Scope是否需要代理,最后把這個(gè)Bean注冊(cè)進(jìn)去BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);}
ClassPathBeanDefinitionScanner
屬性
private final BeanDefinitionRegistry registry;private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults();@Nullableprivate String[] autowireCandidatePatterns;private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();private boolean includeAnnotationConfig = true;public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {this(registry, true);}public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {this(registry, useDefaultFilters, getOrCreateEnvironment(registry));}public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,Environment environment) {this(registry, useDefaultFilters, environment,(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));}public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,Environment environment, @Nullable ResourceLoader resourceLoader) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");this.registry = registry;if (useDefaultFilters) {registerDefaultFilters();}setEnvironment(environment);setResourceLoader(resourceLoader);}掃描
public int scan(String... basePackages) {int beanCountAtScanStart = this.registry.getBeanDefinitionCount();doScan(basePackages);// Register annotation config processors, if necessary.if (this.includeAnnotationConfig) {AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);}return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);}?
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");// 裝載掃描到的BeanSet<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();for (String basePackage : basePackages) {// 把掃描到的Bean就放進(jìn)來了,會(huì)把該包下面所有的Bean都掃描進(jìn)去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) {// 如果是AbstractBeanDefinition,做一些處理postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {// 如果是AnnotatedBeanDefinition,做一些處理AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}//檢查第三方 生成的bean。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;}scanCandidateComponents()
根據(jù)basePackage掃描候選的組件
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {Set<BeanDefinition> candidates = new LinkedHashSet<>();try {// 1.根據(jù)指定包名 生成包搜索路徑//通過觀察resolveBasePackage()方法的實(shí)現(xiàn), 我們可以在設(shè)置basePackage時(shí), 使用形如${}的占位符,Spring會(huì)在這里進(jìn)行替換只要在Enviroment里面就行// 本次值為:classpath*:com/fsx/config/**/*.classString packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +resolveBasePackage(basePackage) + '/' + this.resourcePattern;//2. 資源加載器 加載搜索路徑下的 所有class 轉(zhuǎn)換為 Resource[]// 拿著上面的路徑,就可以getResources獲取出所有的.class類,這個(gè)很強(qiáng)大~~~// 真正干事的為:PathMatchingResourcePatternResolver#getResources方法// 此處能掃描到兩個(gè)類AppConfig(普通類,沒任何注解標(biāo)注)和RootConfig。所以接下里就是要解析類上的注解,以及過濾掉不是候選的類(比如AppConfig)// 注意:這里會(huì)拿到類路徑下(不包含jar包內(nèi)的)的所有的.class文件 可能有上百個(gè),然后后面再交給后面進(jìn)行篩選~~~~~~~~~~~~~~~~(這個(gè)方法,其實(shí)我們也可以使用)// 當(dāng)然和getResourcePatternResolver和這個(gè)模版有關(guān) Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);boolean traceEnabled = logger.isTraceEnabled();boolean debugEnabled = logger.isDebugEnabled();for (Resource resource : resources) {if (traceEnabled) {logger.trace("Scanning " + resource);}if (resource.isReadable()) {try {//讀取類的 注解信息 和 類信息 ,兩大信息儲(chǔ)存到 MetadataReaderMetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);// 根據(jù)TypeFilter過濾排除組件。因?yàn)锳ppConfig沒有標(biāo)準(zhǔn)@Component或者子注解,所以肯定不屬于候選組件 返回false// 注意:這里一般(默認(rèn)處理的情況下)標(biāo)注了默認(rèn)注解的才會(huì)true,什么叫默認(rèn)注解呢?就是@Component或者派生注解。還有javax....的,這里省略啦if (isCandidateComponent(metadataReader)) {//把符合條件的 類轉(zhuǎn)換成 BeanDefinitionScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);sbd.setResource(resource);sbd.setSource(resource);/ 再次判斷 如果是實(shí)體類 返回true,如果是抽象類,但是抽象方法 被 @Lookup 注解注釋返回true (注意 這個(gè)和上面那個(gè)是重載的方法) // 這和上面是個(gè)重載方法 個(gè)人覺得旨在處理循環(huán)引用以及@Lookup上if (isCandidateComponent(sbd)) {if (debugEnabled) {logger.debug("Identified candidate component class: " + resource);}candidates.add(sbd);}else {if (debugEnabled) {logger.debug("Ignored because not a concrete top-level class: " + resource);}}}else {if (traceEnabled) {logger.trace("Ignored because not matching any filter: " + resource);}}}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, ex);}}else {if (traceEnabled) {logger.trace("Ignored because not readable: " + resource);}}}}catch (IOException ex) {throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);}return candidates;}
XmlBeanDefinitionReader
略
?
?
總結(jié)
以上是生活随笔為你收集整理的Spring BeanDefinition加载的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring-- Application
- 下一篇: Spring Environment