006 自动配置

一 .概述

  在springboot之中最令我们喜欢的特性大概就是自动配置了.springboot根据自动配置帮助我们实现整个开发环境的配置,这可以让我们不需要每次都完成那些重复的配置工作了.

  本此,我们就分析一下自动配置的原理.



二 .程序的启动类  

@SpringBootApplication
public class SpringbootRunnerClass {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootRunnerClass.class, args);
    }
}

在我们springboot的程序启动类之中,我们使用了一个注解@SpringBootApplicatiion注解.

我们下面看看这个注解帮助我们完成了什么.  

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

我们发现在这个注解上面带有三个子注解,我们下面来看看这写注解是干什么用的.  

@Configuration
public @interface SpringBootConfiguration {

}

第一个注解,我们发现就是一个配置类,只不过是springvoot特意定义的一个注解而已.  

@Repeatable(ComponentScans.class)
public @interface ComponentScan

第三个注解,我们非常的熟悉了,那就是扫包注解,在springboot之中,默认的扫包策略就是启动包的子包进行扫描.

  现在,我们所有的注意都放在了第二个注解上面.

@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

我们发现在这个注解上面有两个子注解.我们看看他们是干什么用的.

/**
 * Indicates that the package containing the annotated class should be registered with
 * {@link AutoConfigurationPackages}.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

}

从上面的注视之中,我们可以看到,它帮助我们注册该包的所有的bean.

  我们再来看看帮助我们引入的那个类是干什么用的.

public class EnableAutoConfigurationImportSelector
        extends AutoConfigurationImportSelector {

    @Override
    protected boolean isEnabled(AnnotationMetadata metadata) {
        if (getClass().equals(EnableAutoConfigurationImportSelector.class)) {
            return getEnvironment().getProperty(
                    EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class,
                    true);
        }
        return true;
    }

}

我们看看它的父类:  

@Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        try {
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                    .loadMetadata(this.beanClassLoader);
            AnnotationAttributes attributes = getAttributes(annotationMetadata);
            List<String> configurations = getCandidateConfigurations(annotationMetadata,
                    attributes);
            configurations = removeDuplicates(configurations);
            configurations = sort(configurations, autoConfigurationMetadata);
            Set<String> exclusions = getExclusions(annotationMetadata, attributes);
            checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = filter(configurations, autoConfigurationMetadata);
            fireAutoConfigurationImportEvents(configurations, exclusions);
            return configurations.toArray(new String[configurations.size()]);
        }
        catch (IOException ex) {
            throw new IllegalStateException(ex);
        }
    }

我们发现,这个就是一个导入bean的组件的@Import而已,我们现在需要关注的就是到底为我们导入了什么?

    protected static final String PATH = "META-INF/"
            + "spring-autoconfigure-metadata.properties";

我们发现从该配置之中加入了很多了bean.这些bean很多都是一些配置类,基本上都存在springboot的自动配置包下.也就是说,最终这个路径下的配置文件之中的bean大多都会注册到我们的bean之中.  

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

另外我们发现也从这个配置文件之中引入了很多的组件.

  也就是说,springboot会从上面的一些配置文件之中加载很多的bean.  



三 .自动配置类

  我们从上面看到了springboot几乎为我们加载了自动配置包下面的所有的自动配置类.

  我们看看我们这个包下面到底有些什么东西.

  里面所有的类都是自动配置类,我们看一个简单的就好了. 

@Configuration
@ConditionalOnClass(Gson.class)
public class GsonAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public Gson gson() {
        return new Gson();
    }

}

我们发现上面就是一个简单的配置类,如果类路径下面由一个Gson类,而且容器之中没有gson对象,springboot就会帮助我们向容器之中注入一个bean.



四 [email protected]注解

  在springboot之中(实际上在spring4之中引入),为我们引入了一些条件注解,这些注解会帮助我们在运行环境下确定是否向容器之中注册bean.

  实际上就是一个boolean的判断,如果条件满足,就会注入,否则就不会注入.

  我们看看几个常见的注解:

  [1]ConditionalOnBean : 当容器之中含有这个bean的时候,就会注入

  [2]ConditionalOnClass : 当类路径下有这个class的时候就会注册

  [3]ConditionalOnProperty : 当环境变量之中有这个属性的时候就会注册

  等等等,springboot就是通过这些注解完成的自动的装配.



五 .自动装配的分析

  我们使用一个比较简单的配置类进行自动配置的一般流程的分析:

@Configuration
@EnableConfigurationProperties(HttpEncodingProperties.class)
@ConditionalOnWebApplication
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

    private final HttpEncodingProperties properties;

    public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
        this.properties = properties;
    }

    @Bean
    @ConditionalOnMissingBean(CharacterEncodingFilter.class)
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
        return filter;
    }

    @Bean
    public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
        return new LocaleCharsetMappingsCustomizer(this.properties);
    }

    private static class LocaleCharsetMappingsCustomizer
            implements EmbeddedServletContainerCustomizer, Ordered {

        private final HttpEncodingProperties properties;

        LocaleCharsetMappingsCustomizer(HttpEncodingProperties properties) {
            this.properties = properties;
        }

        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            if (this.properties.getMapping() != null) {
                container.setLocaleCharsetMappings(this.properties.getMapping());
            }
        }

        @Override
        public int getOrder() {
            return 0;
        }

    }

}

[1]首先,我们发现这个是一个配置类.

[2]@ConditionalOnWebApplication 表示需要在web环境下才注册

[3]@ConditionalOnClass(CharacterEncodingFilter.class) 表示需要在类路径下有一个类才进行注册

[4]@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true) 这个表示在配置文件下有这个属性才可以,但是在这里给出了默认值,也就是说一定成立的,除非用户主动取消掉这个配置.

[5]@EnableConfigurationProperties(HttpEncodingProperties.class)  这个注解表示完成对HttpEncodingProperties这个属性配置类进行属性的填充.

下面,我们来分析一下源代码了:

    private final HttpEncodingProperties properties;

    public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
        this.properties = properties;
    }

我们从上面的注解之中看到了会向容器之中注册一个HttpEncodingProperties类,然后本自动配置类就实例化了.也就是说,现在的HttpEncodingProperties 的属性被填充好了.

@Bean
    @ConditionalOnMissingBean(CharacterEncodingFilter.class)
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
        return filter;
    }

表示向容器之中添加一个字符编码过滤器.

@Bean
    public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
        return new LocaleCharsetMappingsCustomizer(this.properties);
    }

表示向容器之中添加一个自定义配置器.



六 .自动配置的基本流程

[1]一般会有一个属性配置类与属性文件进行绑定

[2]然后通过这个属性的对自动配置i类进行属性的填充

[3]然后就是创建不同bean到容器之之中,直到完成整个springboot的自动配置.



七 .自动配置报告

  我们现在知道了springvoot的自动配置原理了,但是我们看到自动配置非常的复杂,我们如何好能确定一个bean是否已经被初始化好了呢?

  springboot为我们提供了自动配置报告.  

debug=true

我们在主配置文件之中,可以添加如上的配置,然后再启动springboot 的时候就会开启自动配置报告的生成.

  在我们的控制台上就显示了不同的配置报告的信息.

从这里显示的就是springboot帮助我们添加的bean,也就是自动配置成功的类.

下面显示的就是没有自动成功的类.

原文地址:https://www.cnblogs.com/trekxu/p/9739548.html

时间: 2024-10-11 05:45:53

006 自动配置的相关文章

win7设置固定IP重启后无法上网,ipconfig显示为自动配置IPV4 169.254的地址

近日安装原版Win7系统打完网卡驱动补丁后,给电脑设置了固定的IP地址后一切正常,但是电脑重启后发现上不了网了,右下角网络图标有个感叹号,打开网络和共享中心-->本地连接-->详细信息-->发现IPv4的地址与ipconfig /all得到的IP地址一致,均显示为:自动配置IPv4地址:169.254.123.188(首选) 但是查看本地连接-->属性里看到之前设置的固定IP地址是没有问题的, 所以想到了应该是电脑启用了自动配置IPv4功能,导致了固定IP无法分配给电脑, 尝试用命

一个由于springboot自动配置所产生的问题的解决

由于我的项目里面需要使用到solr,我做了一下solr和springboot的整合,结果启动项目的时候,就报错了...报错的信息的第一行提示如下: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'solrClient' defined in class path resource [org/springframework/boot/autoconfigure/solr/

网络连接详细信息出现两个自动配置ipv4地址

  问题:网络连接详细信息出现两个自动配置ipv4地址,一个是有效地址,一个是无效地址.   解决办法:先将本地连接ip设置成自动获取,然后点击开始-->运行-->输入cmd,回车,进入命令行界面,输入ipconfig  /release回车,然后输入ipconfig  /renew,然后等待ip更新,一般到这里问题已经解决,然后再设置静态ip就行了.

Java环境变量自动配置。嗯,就是用C#去配置JDK

在跟学弟们聊天的过程中,发现一些人在首次接触Java时,对环境变量配置总是很生疏.可能是由于初学,对一些概念没有很深刻的理解.本着助人为乐的精神.我决定帮他们一下.写一个自动配置JDK环境变量的小工具. 其实,整个过程的逻辑并不难: 1.找到jdk的安装路径(默认为C:\Program Files\Java\jdkxxx,xxx指版本号字符串). 2.在环境变量中添加 JAVA_HOME 变量,用于标记jdk路径,在下面的步骤中会用到,其值为 第1步中找到的jdk文件夹路径. 3.在环境变量中添

huhamhire-hosts — Hosts文件自动配置工具

https://www.anotherhome.net/1376 推荐配合EasyGoAgent使用: EasyGoAgent — 开箱即用的GoAgent Update 2015.5.15 数据文件V1.5.7已更新, 数据包下载:http://pan.baidu.com/s/1mgrExrM (感谢网友zzd911) Update 2015.4.1 数据文件V1.5.6已更新, 数据包下载:http://pan.baidu.com/s/1qWqOtUO Update 2015.2.4 数据文

[win]AD域组策略wifi自动配置

http://wenku.baidu.com/link?url=MC950wliAZNeVUJ2M6Y1VTi5faqo7kG374fyBjW57r0qyLJkBZLg5ypiql4RFywQ8q7yfdjr5nQMdvolCvNv6RBkogAmcibH0QHAr1NXklG 802.1x认证AD域自动下发客户端配置指导书 这篇文档不再描述radius 服务器和AD 域的搭建过程,只说明通过域下发802.1X客户端配置(即对域的配置过程) 适用的服务器:Win Server2008 radiu

自定义PAC文件实现代理自动配置

首先了解什么是PAC文件,点击了解详情. 在了解了PAC文件之后,那么后面的事情就比较简单了. 按照规范编写出适合自己的PAC文件,让网络更为自由(作为开发人员已被逼上不归路了)! 需要的朋友点击下载(下载完后打开文件修改对应的端口值) 代理工具集点击下载 下面以GoAgentX为例说明使用方法: 选择完后,记得点击下面的"Restart PAC Server"按钮进行立即生效: 选择适当的模式: 一般下图的网络配置是自动配置的: 自定义PAC文件实现代理自动配置,布布扣,bubuko

代理自动配置脚本

iefile://d:/PersonalSet/agent.pac火狐file:///d:/PersonalSet/agent.pac function FindProxyForURL(url, host){ if (isPlainHostName(host)) {     return "DIRECT"; } if (isInNet(host, "10.0.0.0", "255.0.0.0")) {     return "DIREC

自动配置IPv4问题

对于 Windows , 配置 IP,如: 192.168.1.101, 如果这个 IP 已经在局域网内存在,那么将会提示局域网内已经存在该 IP. 而这个时候,Windows 7 将产生一个 “自动配置IPv4地址”,如:169.254.255.44. 这个时候,使用 ping 命令,将提示从 169.254.255.44 返回不可达错误,而非提示从 192.168.1.101 返回不可达错误. 解决该问题方法: 重新配置IP,这个 IP 需要在局域网内目前无人使用.