日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

spring boot实战(第九篇)Application创建源码分析

發布時間:2025/3/21 编程问答 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring boot实战(第九篇)Application创建源码分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

通過前面的文章了解到在spring boot的啟動時,利用的是編寫的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

    上篇中講述了上下文的創建,在run方法中接下來會執行

    [html]?view plain?copy

  • load(context,?sources.toArray(new?Object[sources.size()]));??

  • 這個的sources表示的為Application類,在創建SpringApplication時手動傳遞

    [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();??
  • ????}??

  • 調用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());??
  • ????}??

  • 執行load((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) 工具類獲取執行類對應的注解信息,該工具類在自己編碼代碼時可用得到

    ?

    由于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?{};??
  • ??
  • }??

  • 發現不存在Compoment注解,是不是表明Application不是一個Component呢?其實不然,來看下@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?"";??
  • ??
  • }??

  • 發現Configuration注解上存在Component注解,表明Application為Component

    ?

    接下來執行this.annotatedReader.register(source);

    ?

    [html]?view plain?copy

  • public?void?register(Class<?>...?annotatedClasses)?{??
  • ????????for?(Class<?>?annotatedClass?:?annotatedClasses)?{??
  • ????????????registerBean(annotatedClass);??
  • ????????}??
  • ????}??

  • 調用registerBean注冊Application對應的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對應條件則該bean不被創建;

    ?

    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數組值,對應的Class必須實現Condition接口:

    ?

    [html]?view plain?copy

  • public?interface?Condition?{???
  • ????boolean?matches(ConditionContext?context,?AnnotatedTypeMetadata?metadata);??
  • ??
  • }??

  • 如果matches返回true 表明該bean需要被創建,否則表明該bean不需要被創建。

    ?

    明白了該注解的用法后,來一個實際案例

    [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?{??
  • }??

  • 創建ConditionBean,使用注解@Conditional(MyCondition.class)調用MyCondition類

    ?

    [html]?view plain?copy

  • /**??
  • ?*?自定義condition??修改返回值,查看bean是否創建??
  • ?*???
  • ?*?@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實現接口Condition,在matches方法中獲取bean上注解Component信息,如果bean名稱等于MyCondition返回true,否則返回false,bean不會被創建。

    ?

    回到前面Application的分析,Application上不存在Conditional,因此shouldSkip返回false,代碼繼續執行

    ?

    [html]?view plain?copy

  • ScopeMetadata?scopeMetadata?=?this.scopeMetadataResolver.resolveScopeMetadata(abd);??
  • 處理Scope注解信息,默認是單例bean

    執行

    [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等注解

    ?

    最后調用

    [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的注冊調用為

    [html]?view plain?copy

  • registry.registerBeanDefinition(beanName,?definitionHolder.getBeanDefinition());??
  • 該代碼在上篇中已有說明。

    ?

    此時Application對應bean已創建完成。

    總結

    以上是生活随笔為你收集整理的spring boot实战(第九篇)Application创建源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。