javascript
Spring BeanDefinition加载
Spring容器里通過BeanDefinition對象來表示Bean,BeanDefinition描述了Bean的配置信息。而BeanDefinitionRegistry接口提供了向容器注冊,刪除,獲取BeanDefinition對象的方法。
Spring IOC容器啟動的時候,需要加載Bean定義信息BeanDefinition,用到了幾個非常關鍵的類:
- AnnotatedBeanDefinitionReader
- ClassPathBeanDefinitionScanner
- XmlBeanDefinitionReader
BeanDefinition
繼承圖
BeanDefinition接口主要提供Bean的元數據描述信息,包括:類名、scope、屬性、構造函數參數列表、依賴的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元數據元素,作用是可以持有XML文件的一個bean標簽對應的Object。
AnnotatedBeanDefinition
public interface AnnotatedBeanDefinition extends BeanDefinition {AnnotationMetadata getMetadata();@NullableMethodMetadata getFactoryMethodMetadata();}AbstractBeanDefinition
略
ChildBeanDefinition
public class ChildBeanDefinition extends AbstractBeanDefinition {@Nullableprivate String parentName; }RootBeanDefinition
一個RootBeanDefinition定義表明它是一個可合并的bean definition:即在spring beanFactory運行期間,可以返回一個特定的bean。RootBeanDefinition可以作為一個重要的通用的bean definition 視圖。
RootBeanDefinition用來在配置階段進行注冊bean definition。然后,從spring 2.5后,編寫注冊bean definition有了更好的的方法:GenericBeanDefinition。GenericBeanDefinition支持動態定義父類依 賴,而非硬編碼作為root bean definition。其中RootBeanDefinition是最常用的實現類,它對應一般性的元素標簽
在 配置文件中可以定義父和子,父用RootBeanDefinition表示, 而子用ChildBeanDefiniton表示,而沒有父的就使用 RootBeanDefinition表示。
?
?
輔助類
BeanNameGenerator
BeanNameGenerator是bean Name的生成器。主要有2個實現:
- DefaultBeanNameGenerator
- AnnotationBeanNameGenerator
?
DefaultBeanNameGenerator
默認生成器,規則為:
1、如果有類名以類名作為name。
2、沒有類名,以父name +?"$child",沒有父name,以factory name +?"$created"
3、最后,如果是內部bean,加?"#" 加上 對象hash的十六進制表示。如果不是,加上 ?"#"? 加上同名排序后的序號
AnnotationBeanNameGenerator
注解生成器,規則為:
1、如果注解上有name,則以此為name,
2、否則為類的短名稱的駝峰寫法。
?
AnnotatedBeanDefinitionReader
屬性
//用于BeanDefinition注冊管理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中有大量的應用this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); //這句會把一些自動注解處理器加入到AnnotationConfigApplicationContext下的BeanFactory的BeanDefinitions中 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);}這里將AnnotationConfigApplicationContext注冊為管理BeanDefinition的BeanDefinitionRegistry,也就是說,spring中bean的管理完全交給了AnnotationConfigApplicationContext。
registerAnnotationConfigProcessors()
AnnotationConfigUtils#registerAnnotationConfigProcessors(),提供了一種極為方便注冊這些BeanPostProcessor的方式(若是xml方式,配置<context:annotation-config/>,若是全注解驅動的ApplicationContext,就默認會執行)
主要功能是如果未注冊以下幾個PostProcessor,則注冊默認類型:
- org.springframework.context.annotation.internalConfigurationAnnotationProcessor:ConfigurationClassPostProcessor
ConfigurationClassPostProcessor是一個BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor處理器,BeanDefinitionRegistryPostProcessor的處理方法能處理@Configuration等注解。ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法內部處理@Configuration,@Import,@ImportResource和類內部的@Bean。
- org.springframework.context.annotation.internalAutowiredAnnotationProcessor:AutowiredAnnotationBeanPostProcessor
AutowiredAnnotationBeanPostProcessor是用來處理@Autowired注解和@Value注解的
- org.springframework.context.annotation.internalCommonAnnotationProcessor:CommonAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor提供對JSR-250規范注解的支持@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實在spring4.2之后出現的,可以在一個Bean的方法上使用@EventListener注解來自動注冊一個ApplicationListener。
- org.springframework.context.event.internalEventListenerFactory:DefaultEventListenerFactory
?
?
注冊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) {// 先把此實體類型轉換為一個BeanDefinitionAnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);//abd.getMetadata() 元數據包括注解信息、是否內部類、類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));// 設定一些注解默認值,如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是否需要代理,最后把這個Bean注冊進去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就放進來了,會把該包下面所有的Bean都掃描進去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()
根據basePackage掃描候選的組件
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {Set<BeanDefinition> candidates = new LinkedHashSet<>();try {// 1.根據指定包名 生成包搜索路徑//通過觀察resolveBasePackage()方法的實現, 我們可以在設置basePackage時, 使用形如${}的占位符,Spring會在這里進行替換只要在Enviroment里面就行// 本次值為:classpath*:com/fsx/config/**/*.classString packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +resolveBasePackage(basePackage) + '/' + this.resourcePattern;//2. 資源加載器 加載搜索路徑下的 所有class 轉換為 Resource[]// 拿著上面的路徑,就可以getResources獲取出所有的.class類,這個很強大~~~// 真正干事的為:PathMatchingResourcePatternResolver#getResources方法// 此處能掃描到兩個類AppConfig(普通類,沒任何注解標注)和RootConfig。所以接下里就是要解析類上的注解,以及過濾掉不是候選的類(比如AppConfig)// 注意:這里會拿到類路徑下(不包含jar包內的)的所有的.class文件 可能有上百個,然后后面再交給后面進行篩選~~~~~~~~~~~~~~~~(這個方法,其實我們也可以使用)// 當然和getResourcePatternResolver和這個模版有關 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 {//讀取類的 注解信息 和 類信息 ,兩大信息儲存到 MetadataReaderMetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);// 根據TypeFilter過濾排除組件。因為AppConfig沒有標準@Component或者子注解,所以肯定不屬于候選組件 返回false// 注意:這里一般(默認處理的情況下)標注了默認注解的才會true,什么叫默認注解呢?就是@Component或者派生注解。還有javax....的,這里省略啦if (isCandidateComponent(metadataReader)) {//把符合條件的 類轉換成 BeanDefinitionScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);sbd.setResource(resource);sbd.setSource(resource);/ 再次判斷 如果是實體類 返回true,如果是抽象類,但是抽象方法 被 @Lookup 注解注釋返回true (注意 這個和上面那個是重載的方法) // 這和上面是個重載方法 個人覺得旨在處理循環引用以及@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
略
?
?
總結
以上是生活随笔為你收集整理的Spring BeanDefinition加载的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring-- Application
- 下一篇: Spring Environment