SpringBoot自动装配的理解

run方法

// ...
public ConfigurableApplicationContext run(String... args) {
		//监控任务执行时间
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        //创建应用上下文
        ConfigurableApplicationContext context = null;
        //用来记录关于启动的错误报告
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        //监听SpringBoot应用启动过程中的一些生命周期
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
        //运行参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //加载相关配置文件
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            //打开banner
            Banner printedBanner = this.printBanner(environment);
            //创建应用上下文
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }
// ...

通过一个简单的run方法,将引发的是一系列复杂的内部调用和加载过程,从而初始化一个应用所需的配置、环境、资源以及各种自定义的类。在这个阶段,会导入一些列自动配置的类,实现强大的自动配置的功能。
自动配置的类又与@SpringBootApplication关系密切

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration   //主要
@EnableAutoConfiguration   //主要
@ComponentScan(				//主要
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
// ...

@SpringBootApplication

@SpringBootConfiguration

@SpringBootConfiguration继承自@Configuration,二者功能也一致,只不过@SpringBootConfiguration是springboot的注解,而@Configuration是spring的注解,标注当前类是配置类,并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中,并且实例名就是方法名。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration      //<-----
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

@EnableAutoConfiguration

SpringBoot的约定大于配置在这体现

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //<--
@Import({AutoConfigurationImportSelector.class})  //<--
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

利用@Import注解,将所有符合自动装配条件的bean注入到IOC容器中,@Import注解的原理…头皮发麻…
@Import原理
进入类AutoConfigurationImportSelector,观察selectImports方法,这个方法执行完毕后,Spring会把这个方法返回的类的全限定名数组里的所有的类都注入到IOC容器中

public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.filter(configurations, autoConfigurationMetadata);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }
    //...
     protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

首先会去加载所有Spring预先定义的配置条件信息,这些配置信息在org.springframework.boot.autoconfigure包下的META-INF/spring-autoconfigure-metadata.properties 文件中
在这里插入图片描述
如果你要自动装配某个类的话,你觉得先存在哪些类或者哪些配置文件等等条件,这些条件的判断主要是利用了@ConditionalXXX注解,例如springMVC的自动配置类
在这里插入图片描述
通过这些注解判断是否需要自动装配,详情就不赘述了。

总结:
1.springBoot在启动的时候,从类路径下/META-INF/spring.factories获取指定的值
2.将这些自动配置类导入容器,自动配置就会生效,帮我们进行自动配置
3.它会把所有需要导入的组件,以类名的形式返回,这些组件就会被添加到容器
4.容器存在非常多的XXXAutoConfiguration的文件(@Bean),就是这些类给容器中导入了这个场景需要的所有组件,并自动配置,@Cofiguration,JavaConfig
5.有了自动配置类,免去了我们手动编写的工作
6.Springboot帮我们写好了配置类(约定大于配置),启动时进行自动配置

@ComponentScan

自动扫描并加载符合条件的Bean到容器中,这个注解会默认扫描声明类所在的包,例如:类cn.shiyujun.Demo类上标注了@ComponentScan 注解,则cn.shiyujun.controller、cn.shiyujun.service等等包下的类都可以被扫描到

yml文件和Spring.factories的关系

配置文件路径的优先级:
我们从属性:DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/ 可以看出文件路径的先后顺序(注意:后加载的会覆盖先加载的):
classpath:/
classpath:/config/
file:./
file:./config/
在配置文件中能配置的东西,都存在一个固有的规律
xxxAutoConfiguration 默认值 xxx.Properties 配置文件绑定

// ....
@ConfigurationProperties(
    prefix = "spring.mvc"
)
public class WebMvcProperties {
    private Format messageCodesResolverFormat;
    private Locale locale;
    private WebMvcProperties.LocaleResolver localeResolver;
    private String dateFormat;
    private boolean dispatchTraceRequest;
    private boolean dispatchOptionsRequest;
    private boolean ignoreDefaultModelOnRedirect;
    private boolean publishRequestHandledEvents;
    private boolean throwExceptionIfNoHandlerFound;
    private boolean logResolvedException;
    private String staticPathPattern;
    private final WebMvcProperties.Async async;
    private final WebMvcProperties.Servlet servlet;
    private final WebMvcProperties.View view;
    private final WebMvcProperties.Contentnegotiation contentnegotiation;
    private final WebMvcProperties.Pathmatch pathmatch;
    //...

在这里插入图片描述
一 一 对应,我们配置yml即修改默认配置类的参数
xxxAutoConfiguration 默认值 xxx.Properties 配置文件绑定
在SpringBoot启动时一起加载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值