生活随笔
收集整理的這篇文章主要介紹了
spring boot实战(第九篇)Application创建源码分析
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
前言
通過前面的文章了解到在spring boot的啟動時(shí),利用的是編寫的Application類,使用了注解@SpringBootApplication,本篇將闡述該Bean的加載過程。
?
[html]?view plain?copy
@SpringBootApplication??public?class?Application?{??????public?static?void?main(String[]?args)?{??????????SpringApplication?app?=?new?SpringApplication(Application.class);???????????app.addListeners(new?MyApplicationStartedEventListener());??????????app.run(args);??????}??}??
?
?
?
?
?
Application
上篇中講述了上下文的創(chuàng)建,在run方法中接下來會執(zhí)行
[html]?view plain?copy
load(context,?sources.toArray(new?Object[sources.size()]));??
這個(gè)的sources表示的為Application類,在創(chuàng)建SpringApplication時(shí)手動傳遞
[html]?view plain?copy
SpringApplication?app?=?new?SpringApplication(Application.class);??
?
load方法如下:
?
[html]?view plain?copy
protected?void?load(ApplicationContext?context,?Object[]?sources)?{??????????if?(this.log.isDebugEnabled())?{??????????????this.log.debug("Loading?source?"??????????????????????+?StringUtils.arrayToCommaDelimitedString(sources));??????????}??????????BeanDefinitionLoader?loader?=?createBeanDefinitionLoader(??????????????????getBeanDefinitionRegistry(context),?sources);??????????if?(this.beanNameGenerator?!=?null)?{??????????????loader.setBeanNameGenerator(this.beanNameGenerator);??????????}??????????if?(this.resourceLoader?!=?null)?{??????????????loader.setResourceLoader(this.resourceLoader);??????????}??????????if?(this.environment?!=?null)?{??????????????loader.setEnvironment(this.environment);??????????}??????????loader.load();??????}??
調(diào)用loader.load();
[html]?view plain?copy
private?int?load(Object?source)?{??????????Assert.notNull(source,?"Source?must?not?be?null");??????????if?(source?instanceof?Class<?>)?{??????????????return?load((Class<?>)?source);??????????}??????????if?(source?instanceof?Resource)?{??????????????return?load((Resource)?source);??????????}??????????if?(source?instanceof?Package)?{??????????????return?load((Package)?source);??????????}??????????if?(source?instanceof?CharSequence)?{??????????????return?load((CharSequence)?source);??????????}??????????throw?new?IllegalArgumentException("Invalid?source?type?"?+?source.getClass());??????}??
執(zhí)行l(wèi)oad((Class<?>) source)
?
[html]?view plain?copy
private?int?load(Class<?>?source)?{??????????if?(isGroovyPresent())?{??????????????//?Any?GroovyLoaders?added?in?beans{}?DSL?can?contribute?beans?here??????????????if?(GroovyBeanDefinitionSource.class.isAssignableFrom(source))?{??????????????????GroovyBeanDefinitionSource?loader?=?BeanUtils.instantiateClass(source,??????????????????????????GroovyBeanDefinitionSource.class);??????????????????load(loader);??????????????}??????????}??????????if?(isComponent(source))?{??????????????this.annotatedReader.register(source);??????????????return?1;??????????}??????????return?0;??????}??
?
isComponent判斷Application是否存在注解Compent
?
[html]?view plain?copy
private?boolean?isComponent(Class<?>?type)?{??????????//?This?has?to?be?a?bit?of?a?guess.?The?only?way?to?be?sure?that?this?type?is??????????//?eligible?is?to?make?a?bean?definition?out?of?it?and?try?to?instantiate?it.??????????if?(AnnotationUtils.findAnnotation(type,?Component.class)?!=?null)?{??????????????return?true;??????????}??????????//?Nested?anonymous?classes?are?not?eligible?for?registration,?nor?are?groovy??????????//?closures??????????if?(type.getName().matches(".*\\$_.*closure.*")?||?type.isAnonymousClass()??????????????????||?type.getConstructors()?==?null?||?type.getConstructors().length?==?0)?{??????????????return?false;??????????}??????????return?true;??????}??
AnnotationUtils.findAnnotation(type, Component.class) 工具類獲取執(zhí)行類對應(yīng)的注解信息,該工具類在自己編碼代碼時(shí)可用得到
?
由于Application使用注解@SpringBootApplication,其定義如下
?
[html]?view plain?copy
@Target(ElementType.TYPE)??@Retention(RetentionPolicy.RUNTIME)??@Documented??@Inherited??@Configuration??@EnableAutoConfiguration??@ComponentScan??public?@interface?SpringBootApplication?{????????/**???????*?Exclude?specific?auto-configuration?classes?such?that?they?will?never?be?applied.???????*?@return?the?classes?to?exclude???????*/??????Class<?>[]?exclude()?default?{};????}??
發(fā)現(xiàn)不存在Compoment注解,是不是表明Application不是一個(gè)Component呢?其實(shí)不然,來看下@Configuration注解
?
[html]?view plain?copy
@Target(ElementType.TYPE)??@Retention(RetentionPolicy.RUNTIME)??@Documented??@Component??public?@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.???????*?<p>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?specified?bean?name,?if?any???????*?@see?org.springframework.beans.factory.support.DefaultBeanNameGenerator???????*/??????String?value()?default?"";????}??
發(fā)現(xiàn)Configuration注解上存在Component注解,表明Application為Component
?
接下來執(zhí)行this.annotatedReader.register(source);
?
[html]?view plain?copy
public?void?register(Class<?>...?annotatedClasses)?{??????????for?(Class<?>?annotatedClass?:?annotatedClasses)?{??????????????registerBean(annotatedClass);??????????}??????}??
調(diào)用registerBean注冊Application對應(yīng)的bean信息
?
[html]?view plain?copy
public?void?registerBean(Class<?>?annotatedClass,?String?name,??????????????@SuppressWarnings("unchecked")?Class<??extends?Annotation>...?qualifiers)?{????????????AnnotatedGenericBeanDefinition?abd?=?new?AnnotatedGenericBeanDefinition(annotatedClass);??????????if?(this.conditionEvaluator.shouldSkip(abd.getMetadata()))?{??????????????return;??????????}????????????ScopeMetadata?scopeMetadata?=?this.scopeMetadataResolver.resolveScopeMetadata(abd);??????????abd.setScope(scopeMetadata.getScopeName());??????????String?beanName?=?(name?!=?null???name?:?this.beanNameGenerator.generateBeanName(abd,?this.registry));??????????AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);??????????if?(qualifiers?!=?null)?{??????????????for?(Class<??extends?Annotation>?qualifier?:?qualifiers)?{??????????????????if?(Primary.class.equals(qualifier))?{??????????????????????abd.setPrimary(true);??????????????????}??????????????????else?if?(Lazy.class.equals(qualifier))?{??????????????????????abd.setLazyInit(true);??????????????????}??????????????????else?{??????????????????????abd.addQualifier(new?AutowireCandidateQualifier(qualifier));??????????????????}??????????????}??????????}????????????BeanDefinitionHolder?definitionHolder?=?new?BeanDefinitionHolder(abd,?beanName);??????????definitionHolder?=?AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,?definitionHolder,?this.registry);??????????BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder,?this.registry);??????}??
首先來看
?
[html]?view plain?copy
if?(this.conditionEvaluator.shouldSkip(abd.getMetadata()))?{??????????????return;??????????}??
判斷是否需要跳過,其代碼如下:
?
[html]?view plain?copy
public?boolean?shouldSkip(AnnotatedTypeMetadata?metadata,?ConfigurationPhase?phase)?{??????????if?(metadata?==?null?||?!metadata.isAnnotated(Conditional.class.getName()))?{??????????????return?false;??????????}????????????if?(phase?==?null)?{??????????????if?(metadata?instanceof?AnnotationMetadata?&&??????????????????????ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata)?metadata))?{??????????????????return?shouldSkip(metadata,?ConfigurationPhase.PARSE_CONFIGURATION);??????????????}??????????????return?shouldSkip(metadata,?ConfigurationPhase.REGISTER_BEAN);??????????}????????????List<Condition>?conditions?=?new?ArrayList<Condition>();??????????for?(String[]?conditionClasses?:?getConditionClasses(metadata))?{??????????????for?(String?conditionClass?:?conditionClasses)?{??????????????????Condition?condition?=?getCondition(conditionClass,?this.context.getClassLoader());??????????????????conditions.add(condition);??????????????}??????????}????????????AnnotationAwareOrderComparator.sort(conditions);????????????for?(Condition?condition?:?conditions)?{??????????????ConfigurationPhase?requiredPhase?=?null;??????????????if?(condition?instanceof?ConfigurationCondition)?{??????????????????requiredPhase?=?((ConfigurationCondition)?condition).getConfigurationPhase();??????????????}??????????????if?(requiredPhase?==?null?||?requiredPhase?==?phase)?{??????????????????if?(!condition.matches(this.context,?metadata))?{??????????????????????return?true;??????????????????}??????????????}??????????}????????????return?false;??????}??
該代碼判斷Application上是否存在Conditional注解,如果不滿足Conditional對應(yīng)條件則該bean不被創(chuàng)建;
?
Conditional注解
代碼分析到這里可以先看看Conditional注解的使用,其定義為:
[html]?view plain?copy
@Retention(RetentionPolicy.RUNTIME)??@Target({ElementType.TYPE,?ElementType.METHOD})??public?@interface?Conditional?{??????/**???????*?All?{@link?Condition}s?that?must?{@linkplain?Condition#matches?match}???????*?in?order?for?the?component?to?be?registered.???????*/??????Class<??extends?Condition>[]?value();????}??
從源碼可以看出,首先判斷Application上是否存在Conditional,如果存在,則獲取Conditional注解中的value數(shù)組值,對應(yīng)的Class必須實(shí)現(xiàn)Condition接口:
?
[html]?view plain?copy
public?interface?Condition?{???????boolean?matches(ConditionContext?context,?AnnotatedTypeMetadata?metadata);????}??
如果matches返回true 表明該bean需要被創(chuàng)建,否則表明該bean不需要被創(chuàng)建。
?
明白了該注解的用法后,來一個(gè)實(shí)際案例
[html]?view plain?copy
package?com.lkl.springboot.condition;????import?org.springframework.context.annotation.Conditional;??import?org.springframework.stereotype.Component;????@Component("MyCondition")??@Conditional(MyCondition.class)??public?class?ConditionBean?{??}??
創(chuàng)建ConditionBean,使用注解@Conditional(MyCondition.class)調(diào)用MyCondition類
?
[html]?view plain?copy
/**???*?自定義condition??修改返回值,查看bean是否創(chuàng)建???*????*?@author?liaokailin???*/??public?class?MyCondition?implements?Condition?{????????/**???????*?返回true?生成bean???????*?返回false?不生成bean????????*/??????@Override??????public?boolean?matches(ConditionContext?context,?AnnotatedTypeMetadata?metadata)?{??????????Map<String,?Object>?map?=?metadata.getAnnotationAttributes(Component.class.getName());??????????return?"MyCondition".equals(map.get("value").toString());??????}????}??
MyCondition實(shí)現(xiàn)接口Condition,在matches方法中獲取bean上注解Component信息,如果bean名稱等于MyCondition返回true,否則返回false,bean不會被創(chuàng)建。
?
回到前面Application的分析,Application上不存在Conditional,因此shouldSkip返回false,代碼繼續(xù)執(zhí)行
?
[html]?view plain?copy
ScopeMetadata?scopeMetadata?=?this.scopeMetadataResolver.resolveScopeMetadata(abd);??
處理Scope注解信息,默認(rèn)是單例bean
執(zhí)行
[html]?view plain?copy
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);??
處理一些常見注解信息
?
[html]?view plain?copy
static?void?processCommonDefinitionAnnotations(AnnotatedBeanDefinition?abd,?AnnotatedTypeMetadata?metadata)?{??????????if?(metadata.isAnnotated(Lazy.class.getName()))?{??????????????abd.setLazyInit(attributesFor(metadata,?Lazy.class).getBoolean("value"));??????????}??????????else?if?(abd.getMetadata()?!=?metadata?&&?abd.getMetadata().isAnnotated(Lazy.class.getName()))?{??????????????abd.setLazyInit(attributesFor(abd.getMetadata(),?Lazy.class).getBoolean("value"));??????????}????????????if?(metadata.isAnnotated(Primary.class.getName()))?{??????????????abd.setPrimary(true);??????????}??????????if?(metadata.isAnnotated(DependsOn.class.getName()))?{??????????????abd.setDependsOn(attributesFor(metadata,?DependsOn.class).getStringArray("value"));??????????}????????????if?(abd?instanceof?AbstractBeanDefinition)?{??????????????AbstractBeanDefinition?absBd?=?(AbstractBeanDefinition)?abd;??????????????if?(metadata.isAnnotated(Role.class.getName()))?{??????????????????absBd.setRole(attributesFor(metadata,?Role.class).getNumber("value").intValue());??????????????}??????????????if?(metadata.isAnnotated(Description.class.getName()))?{??????????????????absBd.setDescription(attributesFor(metadata,?Description.class).getString("value"));??????????????}??????????}??????}??
處理Lazy、Primary、DependsOn、Role、Description等注解
?
最后調(diào)用
[html]?view plain?copy
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder,?this.registry);??
注冊bean信息,在注冊bean信息之前通過
[html]?view plain?copy
String?beanName?=?(name?!=?null???name?:?this.beanNameGenerator.generateBeanName(abd,?this.registry));??
獲取bean名稱
bean的注冊調(diào)用為
[html]?view plain?copy
registry.registerBeanDefinition(beanName,?definitionHolder.getBeanDefinition());??
該代碼在上篇中已有說明。
?
此時(shí)Application對應(yīng)bean已創(chuàng)建完成。
總結(jié)
以上是生活随笔為你收集整理的spring boot实战(第九篇)Application创建源码分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。