springBoot — @Configuration注解解析

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface Configuration { /** * Explicitly specify the name of the Spring bean definition associated * with this Configuration class. If left unspecified (the common case), * a bean name will be automatically generated. *

The custom name applies only if the Configuration class is picked up via

? ? * component scanning or supplied directly to a {@link AnnotationConfigApplicationContext}.

? ? * If the Configuration class is registered as a traditional XML bean definition,

? ? * the name/id of the bean element will take precedence.

? ? * @return the suggested component name, if any (or empty String otherwise)

? ? * @see org.springframework.beans.factory.support.DefaultBeanNameGenerator

? ? */

? ? @AliasFor(annotation = Component.class)

? ? String value() default "";

}

1失都、AnnotatedBeanDefinitionReader

針對(duì)?main()方法所在的類進(jìn)行注解解析的是通過(guò)?BeanDefinitionLoader來(lái)操作的,而具體的解析操作其實(shí)是其內(nèi)部的屬性?annotatedReader來(lái)實(shí)現(xiàn)的

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;

? ? ? ? // @Conditional注解表達(dá)式解析類

? ? ? ? this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);

? ? ? ? // processor接口集合注冊(cè)

? ? ? ? AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

? ? }

上面可知阵谚,在構(gòu)造函數(shù)初始化的過(guò)程中桌吃,順便還注冊(cè)了?BeanDefinitionRegistryPostProcessor集合洒扎,這個(gè)接口會(huì)在?ApplicationContext#refresh()操作中會(huì)被統(tǒng)一調(diào)用。


2讳推、AnnotationConfigUtils#registerAnnotationConfigProcessors()

public static Set registerAnnotationConfigProcessors(

? ? ? ? ? ? BeanDefinitionRegistry registry, @Nullable Object source) {

? ? ? ? ....

? ? ? ? ....

? ? ? ? Set beanDefs = new LinkedHashSet(4);


? ? ? ? // @Configuration注解解析處理類

? ? ? ? if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {

? ? ? ? ? ? RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);

? ? ? ? ? ? def.setSource(source);

? ? ? ? ? ? beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));

? ? ? ? }

? ? ? ? // @Autowired注解解析處理類

? ? ? ? if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {

? ? ? ? ? ? RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);

? ? ? ? ? ? def.setSource(source);

? ? ? ? ? ? beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));

? ? ? ? }


? ? ? ? // @Required注解解析處理類

? ? ? ? if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {

? ? ? ? ? ? RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);

? ? ? ? ? ? def.setSource(source);

? ? ? ? ? ? beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));

? ? ? ? }

? ? ? ? // @WebServiceDef/@EJB/@Resource/@PostConstruct/@PreDestroy注解解析

? ? ? ? if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {

? ? ? ? ? ? RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);

? ? ? ? ? ? def.setSource(source);

? ? ? ? ? ? beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));

? ? ? ? }

? ? ? ? // JPA注解解析

? ? ? ? if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {

? ? ? ? ? ? RootBeanDefinition def = new RootBeanDefinition();

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,

? ? ? ? ? ? ? ? ? ? ? ? AnnotationConfigUtils.class.getClassLoader()));

? ? ? ? ? ? }

? ? ? ? ? ? catch (ClassNotFoundException ex) {

? ? ? ? ? ? ? ? throw new IllegalStateException(

? ? ? ? ? ? ? ? ? ? ? ? "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);

? ? ? ? ? ? }

? ? ? ? ? ? def.setSource(source);

? ? ? ? ? ? beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));

? ? ? ? }

? ? ? ? ....

? ? ? ? ....

? ? ? ? return beanDefs;

? ? }


3琅攘、ConfigurationClassPostProcessor#postProcessBeanFactory()

@Override

? ? public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {

? ? ? ? int factoryId = System.identityHashCode(beanFactory);

? ? ? ? if (this.factoriesPostProcessed.contains(factoryId)) {

? ? ? ? ? ? throw new IllegalStateException(

? ? ? ? ? ? ? ? ? ? "postProcessBeanFactory already called on this post-processor against " + beanFactory);

? ? ? ? }

? ? ? ? this.factoriesPostProcessed.add(factoryId);

? ? ? ? if (!this.registriesPostProcessed.contains(factoryId)) {

? ? ? ? ? ? // 關(guān)鍵方法

? ? ? ? ? ? processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);

? ? ? ? }


? ? ? ? // 對(duì)bean工廠的含Configuration注解實(shí)例進(jìn)行CGLIB代理

? ? ? ? enhanceConfigurationClasses(beanFactory);

? ? ? ? // 對(duì)類型為ImportAware的bean進(jìn)行額外處理

? ? ? ? beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));

? ? }


4、ConfigurationClassPostProcessor#?processConfigBeanDefinitions

* Build and validate a configuration model based on the registry of

? ? * {@link Configuration} classes.

? ? */

? ? public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {

? ? ? ? List configCandidates = new ArrayList();

? ? ? ? String[] candidateNames = registry.getBeanDefinitionNames();

? ? ? ? // 遍歷注冊(cè)在bean工廠上的所有bean爆袍,篩選出未加載過(guò)的@Configuration類

? ? ? ? for (String beanName : candidateNames) {

? ? ? ? ? ? // 避免重復(fù)加載

? ? ? ? ? ? BeanDefinition beanDef = registry.getBeanDefinition(beanName);

? ? ? ? ? ? if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||

? ? ? ? ? ? ? ? ? ? ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {

? ? ? ? ? ? ? ? if (logger.isDebugEnabled()) {

? ? ? ? ? ? ? ? ? ? logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {

? ? ? ? ? ? ? ? configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? // 無(wú)@Configuration注解bean則直接返回

? ? ? ? if (configCandidates.isEmpty()) {

? ? ? ? ? ? return;

? ? ? ? }

? ? ? ? ....

? ? ? ? ....

? ? ? ? // 解析@Configuration

? ? ? ? ConfigurationClassParser parser = new ConfigurationClassParser(

? ? ? ? ? ? ? ? this.metadataReaderFactory, this.problemReporter, this.environment,

? ? ? ? ? ? ? ? this.resourceLoader, this.componentScanBeanNameGenerator, registry);

? ? ? ? Set candidates = new LinkedHashSet(configCandidates);

? ? ? ? Set alreadyParsed = new HashSet(configCandidates.size());

? ? ? ? do {

? ? ? ? ? ? parser.parse(candidates);

? ? ? ? ? ? parser.validate();

? ? ? ? ? ? ...

? ? ? ? ? ? candidates.clear();

? ? ? ? ? ? // 檢查是否含有新的bean沒(méi)有被解析

? ? ? ? ? ? if (registry.getBeanDefinitionCount() > candidateNames.length) {

? ? ? ? ? ? ? ? ...

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? while (!candidates.isEmpty());

? ? ? ? ...

? ? }


5、ConfigurationClassParser#parse()

public void parse(Set configCandidates) {

? ? ? ? this.deferredImportSelectors = new LinkedList();

? ? ? ? // 對(duì)不同類型的bean調(diào)用不同的parse負(fù)載方法

? ? ? ? for (BeanDefinitionHolder holder : configCandidates) {

? ? ? ? ? ? BeanDefinition bd = holder.getBeanDefinition();

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? if (bd instanceof AnnotatedBeanDefinition) {

? ? ? ? ? ? ? ? ? ? parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {

? ? ? ? ? ? ? ? ? ? parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? else {

? ? ? ? ? ? ? ? ? ? parse(bd.getBeanClassName(), holder.getBeanName());

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? catch (BeanDefinitionStoreException ex) {

? ? ? ? ? ? ? ? throw ex;

? ? ? ? ? ? }

? ? ? ? ? ? catch (Throwable ex) {

? ? ? ? ? ? ? ? throw new BeanDefinitionStoreException(

? ? ? ? ? ? ? ? ? ? ? ? "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? // 針對(duì)DeferredImportSelector延遲選擇類作下處理

? ? ? ? processDeferredImportSelectors();

? ? }


6作郭、ConfigurationClassParser#doProcessConfigurationClass()

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)

? ? ? ? ? ? throws IOException {

? ? ? ? // Recursively process any member (nested) classes first

? ? ? ? processMemberClasses(configClass, sourceClass);

? ? ? ? // Process any @PropertySource annotations

? ? ? ? for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(

? ? ? ? ? ? ? ? sourceClass.getMetadata(), PropertySources.class,

? ? ? ? ? ? ? ? org.springframework.context.annotation.PropertySource.class)) {

? ? ? ? ? ? if (this.environment instanceof ConfigurableEnvironment) {

? ? ? ? ? ? ? ? processPropertySource(propertySource);

? ? ? ? ? ? }

? ? ? ? ? ? else {

? ? ? ? ? ? ? ? logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +

? ? ? ? ? ? ? ? ? ? ? ? "]. Reason: Environment must implement ConfigurableEnvironment");

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? // Process any @ComponentScan annotations

? ? ? ? Set componentScans = AnnotationConfigUtils.attributesForRepeatable(

? ? ? ? ? ? ? ? sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);

? ? ? ? if (!componentScans.isEmpty() &&

? ? ? ? ? ? ? ? !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {

? ? ? ? ? ? for (AnnotationAttributes componentScan : componentScans) {

? ? ? ? ? ? ? ? // The config class is annotated with @ComponentScan -> perform the scan immediately

? ? ? ? ? ? ? ? Set scannedBeanDefinitions =

? ? ? ? ? ? ? ? ? ? ? ? this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());

? ? ? ? ? ? ? ? // Check the set of scanned definitions for any further config classes and parse recursively if needed

? ? ? ? ? ? ? ? for (BeanDefinitionHolder holder : scannedBeanDefinitions) {

? ? ? ? ? ? ? ? ? ? BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();

? ? ? ? ? ? ? ? ? ? if (bdCand == null) {

? ? ? ? ? ? ? ? ? ? ? ? bdCand = holder.getBeanDefinition();

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {

? ? ? ? ? ? ? ? ? ? ? ? parse(bdCand.getBeanClassName(), holder.getBeanName());

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? // Process any @Import annotations

? ? ? ? processImports(configClass, sourceClass, getImports(sourceClass), true);

? ? ? ? // Process any @ImportResource annotations

? ? ? ? AnnotationAttributes importResource =

? ? ? ? ? ? ? ? AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);

? ? ? ? if (importResource != null) {

? ? ? ? ? ? String[] resources = importResource.getStringArray("locations");

? ? ? ? ? ? Class readerClass = importResource.getClass("reader");

? ? ? ? ? ? for (String resource : resources) {

? ? ? ? ? ? ? ? String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);

? ? ? ? ? ? ? ? configClass.addImportedResource(resolvedResource, readerClass);

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? // Process individual @Bean methods

? ? ? ? Set beanMethods = retrieveBeanMethodMetadata(sourceClass);

? ? ? ? for (MethodMetadata methodMetadata : beanMethods) {

? ? ? ? ? ? configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));

? ? ? ? }

? ? ? ? // Process default methods on interfaces

? ? ? ? processInterfaces(configClass, sourceClass);

? ? ? ? // Process superclass, if any

? ? ? ? if (sourceClass.getMetadata().hasSuperClass()) {

? ? ? ? ? ? String superclass = sourceClass.getMetadata().getSuperClassName();

? ? ? ? ? ? if (superclass != null && !superclass.startsWith("java") &&

? ? ? ? ? ? ? ? ? ? !this.knownSuperclasses.containsKey(superclass)) {

? ? ? ? ? ? ? ? this.knownSuperclasses.put(superclass, configClass);

? ? ? ? ? ? ? ? // Superclass found, return its annotation metadata and recurse

? ? ? ? ? ? ? ? return sourceClass.getSuperClass();

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? // No superclass -> processing is complete

? ? ? ? return null;

? ? }

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末陨囊,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子夹攒,更是在濱河造成了極大的恐慌蜘醋,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咏尝,死亡現(xiàn)場(chǎng)離奇詭異压语,居然都是意外死亡啸罢,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門胎食,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)扰才,“玉大人,你說(shuō)我怎么就攤上這事厕怜●孟唬” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵粥航,是天一觀的道長(zhǎng)琅捏。 經(jīng)常有香客問(wèn)我,道長(zhǎng)递雀,這世上最難降的妖魔是什么柄延? 我笑而不...
    開(kāi)封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮缀程,結(jié)果婚禮上搜吧,老公的妹妹穿的比我還像新娘。我一直安慰自己杠输,他們只是感情好赎败,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著蠢甲,像睡著了一般僵刮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鹦牛,一...
    開(kāi)封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天搞糕,我揣著相機(jī)與錄音,去河邊找鬼曼追。 笑死窍仰,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的礼殊。 我是一名探鬼主播驹吮,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼晶伦!你這毒婦竟也來(lái)了碟狞?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤婚陪,失蹤者是張志新(化名)和其女友劉穎族沃,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡脆淹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年常空,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盖溺。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡漓糙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出咐柜,到底是詐尸還是另有隱情兼蜈,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布拙友,位于F島的核電站为狸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏遗契。R本人自食惡果不足惜辐棒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望牍蜂。 院中可真熱鬧漾根,春花似錦、人聲如沸鲫竞。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)从绘。三九已至寄疏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間僵井,已是汗流浹背陕截。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留批什,地道東北人农曲。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像驻债,于是被迫代替她去往敵國(guó)和親乳规。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容