[原]Spring boot(2)-配置详解

hacy9104 3年前
   <h2>1、自动化配置</h2>    <p>Spring Boot 对于开发人员最大的好处在于可以对 Spring 应用进行自动配置。Spring Boot 会根据应用中声明的第三方依赖来自动配置 Spring 框架,而不需要进行显式的声明。比如当声明了对 HSQLDB 的依赖时,Spring Boot 会自动配置成使用 HSQLDB 进行数据库操作。</p>    <p>Spring Boot 推荐采用基于 Java 注解的配置方式,而不是传统的 XML。只需要在主配置 Java 类上添加“@EnableAutoConfiguration”注解就可以启用自动配置。Spring Boot 的自动配置功能是没有侵入性的,只是作为一种基本的默认实现。开发人员可以通过定义其他 bean 来替代自动配置所提供的功能。比如当应用中定义了自己的数据源 bean 时,自动配置所提供的 HSQLDB 就不会生效。这给予了开发人员很大的灵活性。既可以快速的创建一个可以立即运行的原型应用,又可以不断的修改和调整以适应应用开发在不同阶段的需要。可能在应用最开始的时候,嵌入式的内存数据库(如 HSQLDB)就足够了,在后期则需要换成 MySQL 等数据库。Spring Boot 使得这样的切换变得很简单。</p>    <h2>2、外部化的配置</h2>    <p>在应用中管理配置并不是一个容易的任务,尤其是在应用需要部署到多个环境中时。通常会需要为每个环境提供一个对应的属性文件,用来配置各自的数据库连接信息、服务器信息和第三方服务账号等。通常的应用部署会包含开发、测试和生产等若干个环境。不同的环境之间的配置存在覆盖关系。测试环境中的配置会覆盖开发环境,而生产环境中的配置会覆盖测试环境。Spring 框架本身提供了多种的方式来管理配置属性文件。Spring 3.1 之前可以使用 PropertyPlaceholderConfigurer。Spring 3.1 引入了新的环境(Environment)和概要信息(Profile)API,是一种更加灵活的处理不同环境和配置文件的方式。不过 Spring 这些配置管理方式的问题在于选择太多,让开发人员无所适从。Spring Boot 提供了一种统一的方式来管理应用的配置,允许开发人员使用属性文件、YAML 文件、环境变量和命令行参数来定义优先级不同的配置值。</p>    <p>Spring Boot 所提供的配置优先级顺序比较复杂。按照优先级从高到低的顺序,具体的列表如下所示。</p>    <ol>     <li>命令行参数。</li>     <li>通过 System.getProperties() 获取的 Java 系统参数。</li>     <li>操作系统环境变量。</li>     <li>从 java:comp/env 得到的 JNDI 属性。</li>     <li>通过 RandomValuePropertySource 生成的“random.*”属性。</li>     <li>应用 Jar 文件之外的属性文件。</li>     <li>应用 Jar 文件内部的属性文件。</li>     <li>在应用配置 Java 类(包含“@Configuration”注解的 Java 类)中通过“@PropertySource”注解声明的属性文件。</li>     <li>通过“SpringApplication.setDefaultProperties”声明的默认属性。</li>    </ol>    <p>Spring Boot 的这个配置优先级看似复杂,其实是很合理的。比如命令行参数的优先级被设置为最高。这样的好处是可以在测试或生产环境中快速地修改配置参数值,而不需要重新打包和部署应用。</p>    <h3>命令行参数</h3>    <p>通过 <a href="/misc/goto?guid=4959671943891288550" style="font-weight:bold;text-decoration:none;" title="Java EE知识库">Java</a> -jar app.jar --name="Spring" --server.port=9090 方式来传递参数。</p>    <p>SpringApplication 类默认会把以“--”开头的命令行参数转化成应用中可以使用的配置参数,如 “--name=Alex” 会设置配置参数 “name” 的值为 “Alex”.</p>    <p>可以使用的参数可以是我们自己定义的,也可以是Spring Boot中默认的参数。</p>    <p>注意: 命令行参数在 app.jar 的后面!</p>    <p>可以通过 SpringApplication.setAddCommandLineProperties(false) 禁用命令行配置。</p>    <h3>Java系统属性</h3>    <p>注意Java系统属性位置 java -Dname="isea533" -jar app.jar ,可以配置的属性都是一样的,优先级不同。</p>    <p>例如 java -Dname="isea533" -jar app.jar --name="Spring!" 中 name 值为 Spring.</p>    <p>有些系统,关于一些数据库或其他第三方账户等信息,由于安全问题,其配置并不会提前配置在项目中暴露给开发人员。</p>    <p>对于这种情况,我们在运行程序的时候,可以通过参数指定一个外部配置文件。 </p>    <p>以 demo.jar 为例,方法如下:</p>    <p>java -jar demo.jar --spring.config.location=/opt/config/application.properties</p>    <p>其中文件名随便定义,无固定要求。</p>    <p><strong>RandomValuePropertySource  </strong></p>    <p>RandomValuePropertySource 可以用来生成测试所需要的各种不同类型的随机值,从而免去了在代码中生成的麻烦。RandomValuePropertySource 可以生成数字和字符串。数字的类型包含 int 和 long,可以限定数字的大小范围。以“random.”作为前缀的配置属性名称由 RandomValuePropertySource 来生成:</p>    <p>  系统中用到随机数的地方,例如  使用 RandomValuePropertySource 生成的配置属性:</p>    <pre>  <code class="language-java">user.id=${random.value}  user.count=${random.int}  user.max=${random.long}  user.number=${random.int(100)}  user.range=${random.int[100, 1000]</code></pre>    <p>random.int* 支持 value 参数和 ,max 参数,当提供 max 参数的时候, value 就是最小值</p>    <h2>3、属性文件</h2>    <p>3.1 属性配置文件的位置</p>    <p>属性文件是最常见的管理配置属性的方式。Spring Boot 提供的 SpringApplication 类会搜索并加载 application.properties 或 application.yml 文件来获取配置属性值。SpringApplication 类会在下面位置搜索该文件。</p>    <ul>     <li>当前目录的“/config”子目录。</li>     <li>当前目录。</li>     <li>classpath 中的“/config”包。</li>     <li>classpath</li>    </ul>    <p>上面的顺序也表示了该位置上包含的属性文件的优先级。优先级按照从高到低的顺序排列。    即:/config优先于classpath根目录</p>    <p>可以通过“spring.config.name”配置属性来指定不同的属性文件名称。也可以通过“spring.config.location”来添加额外的属性文件的搜索路径。如果应用中包含多个 profile,可以为每个 profile 定义各自的属性文件,按照“application-{profile}”来命名。</p>    <p>3.2应用配置文件(.properties或.yml)</p>    <p>在配置文件 application.properties  中直接写:</p>    <p>name=Isea533</p>    <p>server.port=8080</p>    <p>.yml格式的配置文件如:</p>    <p>name: Isea533</p>    <p>server:</p>    <p>port: 8080</p>    <p>当有前缀的情况下,使用.yml格式的配置文件更简单。关于.yml配置文件用法 请看 <a href="/misc/goto?guid=4959676986602408590" rel="nofollow,noindex">这里</a></p>    <p>注意:使用.yml时,属性名的值和冒号中间必须有空格,如name: Isea533正确,name:Isea533就是错的。</p>    <p>3.3 @PropertySource优先级比较</p>    <p>这个注解可以指定具体的属性配置文件,优先级比较低。</p>    <p>SpringApplication.setDefaultProperties</p>    <p>例如:</p>    <pre>  <code class="language-java">SpringApplication application = new SpringApplication(Application.class);  Map<String, Object> defaultMap = new HashMap<String, Object>();  defaultMap.put("name", "Isea-Blog");  //还可以是Properties对象  application.setDefaultProperties(defaultMap);  application.run(args);</code></pre>    <p>3.5 应用程序使用属性 <strong>@Value(“${xxx}”)</strong></p>    <p>对于配置属性,可以在代码中通过“@Value”来使用,如:</p>    <pre>  <code class="language-java">@RestController  @EnableAutoConfiguration  public class Application {   @Value("${name}")   private String name;   @RequestMapping("/")   String home() {   return String.format("Hello %s!", name);   }  }</code></pre>    <p>变量 name 的值来自配置属性中的“name”属性。</p>    <p>比如application.properties有 port=8081</p>    <p>则</p>    <p>@Value("${port:8082}")</p>    <p>private String port;</p>    <p>即可获取8081这个值</p>    <p>3.6属性占位符</p>    <p>例如:</p>    <p>app.name=MyApp</p>    <p>app.description=${app.name} is a Spring Boot application</p>    <p>可以在配置文件中引用前面配置过的属性(优先级前面配置过的这里都能用)。</p>    <p>通过如${app.name:默认名称}方法还可以设置默认值,当找不到引用的属性时,会使用默认的属性。</p>    <p>由于${}方式会被Maven处理。如果你pom继承的spring-boot-starter-parent,Spring Boot 已经将maven-resources-plugins默认的${}方式改为了@ @方式,例如@name@。</p>    <p>如果你是引入的Spring Boot,你可以修改使用其他的分隔符</p>    <p>3.7通过属性占位符还能缩短命令参数</p>    <p>例如修改web默认端口需要使用--server.port=9090方式,如果在配置中写上:</p>    <p>server.port=${port:8080}</p>    <p>那么就可以使用更短的--port=9090,当不提供该参数的时候使用默认值8080。</p>    <p>3.8属性名匹配规则</p>    <p>例如有如下配置对象:</p>    <pre>  <code class="language-java">@Component  @ConfigurationProperties(prefix="person")  public class ConnectionSettings {      private String firstName;  }</code></pre>    <p>firstName可以使用的属性名如下:</p>    <p>person.firstName,标准的驼峰式命名</p>    <p>person.first-name,虚线(-)分割方式,推荐在.properties和.yml配置文件中使用</p>    <p>PERSON_FIRST_NAME,大写下划线形式,建议在系统环境变量中使用</p>    <p> </p>    <p>3.9属性验证</p>    <p>可以使用JSR-303注解进行验证,例如:</p>    <pre>  <code class="language-java">@Component  @ConfigurationProperties(prefix="connection")  public class ConnectionSettings {        @NotNull      private InetAddress remoteAddress;        // ... getters and setters    }</code></pre>    <h2>4、自定义配置</h2>    <p>spring boot使用application.properties默认了很多配置。但需要自己添加一些配置的时候,我们应该怎么做呢。</p>    <h2>若继续在application.properties中添加</h2>    <p>如:</p>    <pre>  <code class="language-java">wisely2.name=wyf2    wisely2.gender=male2</code></pre>    <h2>定义配置类:</h2>    <pre>  <code class="language-java">@ConfigurationProperties(prefix = "wisely2")    public class Wisely2Settings {        private String name;        private String gender;        public String getName() {            return name;        }        public void setName(String name) {            this.name = name;        }        public String getGender() {            return gender;        }        public void setGender(String gender) {            this.gender = gender;        }        }</code></pre>    <h2>若新用新的配置文件</h2>    <p>如我新建一个wisely.properties</p>    <pre>  <code class="language-java">wisely.name=wangyunfei    wisely.gender=male</code></pre>    <h2>需定义如下配置类</h2>    <pre>  <code class="language-java">@ConfigurationProperties(prefix = "wisely",locations = "classpath:config/wisely.properties")    public class WiselySettings {        private String name;        private String gender;        public String getName() {            return name;        }        public void setName(String name) {            this.name = name;        }        public String getGender() {            return gender;        }        public void setGender(String gender) {            this.gender = gender;        }        }</code></pre>    <p>最后注意在spring Boot入口类加上@EnableConfigurationProperties</p>    <p>@SpringBootApplication  </p>    <p>@EnableConfigurationProperties({WiselySettings.class,Wisely2Settings.class})  </p>    <p>public class DemoApplication {  </p>    <p>public static void main(String[] args) {  </p>    <p>SpringApplication.run(DemoApplication.class, args);  </p>    <p>}  </p>    <p>}  </p>    <h2>使用定义的properties</h2>    <p>在别的bean中可直接注入</p>    <pre>  <code class="language-java">@Controller    public class TestController {        @Autowired        WiselySettings wiselySettings;        @Autowired        Wisely2Settings wisely2Settings;            @RequestMapping("/test")        public @ResponseBody String test(){            System.out.println(wiselySettings.getGender()+"---"+wiselySettings.getName());            System.out.println(wisely2Settings.getGender()+"==="+wisely2Settings.getGender());            return "ok";        }     }</code></pre>    <p>或者</p>    <p>在@Bean方法上使用@ConfigurationProperties</p>    <p>例如:</p>    <pre>  <code class="language-java">@ConfigurationProperties(prefix = "foo")  @Bean  public FooComponent fooComponent() {      ...  }</code></pre>    <p>Spring Boot 会将foo开头的属性按照名字匹配注入到FooComponent对象中。</p>    <p>涉及四个文件:</p>    <p>1:properties文件,这里是config.properties,放置在properties文件常放置的地方,即src/main/resources目录下</p>    <p>2:一个存放properties配置文件属性的Bean,这里是 WiselySettings . <a href="/misc/goto?guid=4959671943891288550" rel="nofollow,noindex">Java</a></p>    <p>4:在spring Boot入口类加上@EnableConfigurationProperties</p>    <p>3:读取配置的Controller或者bean</p>    <h2>5、YAML配置</h2>    <p>相对于属性文件来说,YAML 是一个更好的配置文件格式。YAML 在 Ruby on Rails 中得到了很好的应用。SpringApplication 类也提供了对 YAML 配置文件的支持,只需要添加对 SnakeYAML 的依赖即可。application.yml 文件的示例。</p>    <pre>  <code class="language-java">spring:   profiles: development  db:   url: jdbc:hsqldb:file:testdb   username: sa   password:  ---  spring:   profiles: test  db:   url: jdbc:mysql://localhost/test   username: test   password: test</code></pre>    <p>AML 文件同时给出了 development 和 test 两个不同的 profile 的配置信息,这也是 YAML 文件相对于属性文件的优势之一。除了使用“@Value”注解绑定配置属性值之外,还可以使用更加灵活的方式。YAML 文件的 Java 类:</p>    <pre>  <code class="language-java">@Component  @ConfigurationProperties(prefix="db")  public class DBSettings {   private String url;   private String username;   private String password;  }</code></pre>    <p>通过“@ConfigurationProperties(prefix="db")”注解,配置属性中以“db”为前缀的属性值会被自动绑定到 Java 类中同名的域上,如 url 域的值会对应属性“db.url”的值。只需要在应用的配置类中添加“@EnableConfigurationProperties”注解就可以启用该自动绑定功能。</p>    <h2>6. @EnableAutoCongiguration配置</h2>    <p>从Spring 3.0开始,为了替代繁琐的XML配置,引入了 @Enable... 注解对 @Configuration 类进行修饰以达到和XML配置相同的效果。想必不少开发者已经使用过类似注解:</p>    <ul>     <li>@EnableTransactionManagement 开启Spring事务管理,相当于XMl中的 <tx:*></li>     <li>@EnableWebMvc 使用Spring MVC框架的一些默认配置</li>     <li>@EnableScheduling 会初始化一个Scheduler用于执行定时任务和异步任务</li>    </ul>    <p>Spring Boot提供的 @EnableAutoCongiguration 似乎功能更加强大,一旦加上,上述所有的配置似乎都被包含进来而无需开发者显式声明。它究竟是如何做到的呢,先看看它的定义:</p>    <pre>  <code class="language-java">@Target(ElementType.TYPE)  @Retention(RetentionPolicy.RUNTIME)  @Documented  @Import({ EnableAutoConfigurationImportSelector.class,   AutoConfigurationPackages.Registrar.class })  public @interface EnableAutoConfiguration {     /**   * Exclude specific auto-configuration classes such that they will never be applied.   */   Class<?>[] exclude() default {};    }</code></pre>    <p>EnableAutoConfigurationImportSelector 使用的是 spring-core 模块中的 SpringFactoriesLoader#loadFactoryNames() 方法,它的作用是在类路径上扫描 META-INF/spring.factories 文件中定义的类:</p>    <pre>  <code class="language-java"># Initializers  org.springframework.context.ApplicationContextInitializer=\  org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer    # Auto Configure  org.springframework.boot.autoconfigure.EnableAutoConfiguration=\  org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\  org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\  org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\  org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,\  org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\  org.springframework.boot.autoconfigure.data.JpaRepositoriesAutoConfiguration,\  org.springframework.boot.autoconfigure.data.MongoRepositoriesAutoConfiguration,\  org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration,\  org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\  org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\  org.springframework.boot.autoconfigure.jms.JmsTemplateAutoConfiguration,\  org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\  org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\  org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\  org.springframework.boot.autoconfigure.mongo.MongoTemplateAutoConfiguration,\  org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\  org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\  org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\  org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\  org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\  org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\  org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\  org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\  org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\  org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\  org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\  org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration</code></pre>    <p>实际上这就是Spring Boot会自动配置的一些对象,例如前面提到的Web框架由 EmbeddedServletContainerAutoConfiguration , DispatcherServletAutoConfiguration ,  ServerPropertiesAutoConfiguration 等配置完成,而 DataSource 的自动配置则是由 DataSourceAutoConfiguration 完成。现在我们以Mongo的配置 MongoAutoConfiguration 为例,来探索Spring Boot是如何完成这些配置的:</p>    <pre>  <code class="language-java">@Configuration  @ConditionalOnClass(Mongo.class)  @EnableConfigurationProperties(MongoProperties.class)  public class MongoAutoConfiguration {     @Autowired   private MongoProperties properties;     private Mongo mongo;     @PreDestroy   public void close() throws UnknownHostException {   if (this.mongo != null) {   this.mongo.close();   }   }     @Bean   @ConditionalOnMissingBean   public Mongo mongo() throws UnknownHostException {   this.mongo = this.properties.createMongoClient();   return this.mongo;   }    }</code></pre>    <p>首先这是一个Spring的配置 @Configuration ,它定义了我们访问Mongo需要的 @Bean ,如果这个 @Configuration 被Spring Context扫描到,那么Context中自然也就有两个一个 Mongo 对象能够直接为开发者所用。</p>    <p>但是注意到其它几个Spring注解:</p>    <ul>     <li>@ConditionOnClass 表明该 @Configuration 仅仅在一定条件下才会被加载,这里的条件是 Mongo.class 位于类路径上</li>     <li>@EnableConfigurationProperties 将Spring Boot的配置文件( application.properties )中的 spring.data.mongodb.* 属性映射为 MongoProperties 并注入到 MongoAutoConfiguration 中。</li>     <li>@ConditionalOnMissingBean 说明Spring Boot仅仅在当前上下文中不存在 Mongo 对象时,才会实例化一个Bean。这个逻辑也体现了Spring Boot的另外一个特性——自定义的Bean优先于框架的默认配置,我们如果显式的在业务代码中定义了一个 Mongo 对象,那么Spring Boot就不再创建。</li>    </ul>    <p>接下来看一看 MongoProperties :</p>    <pre>  <code class="language-java">@ConfigurationProperties(prefix = "spring.data.mongodb")  public class MongoProperties {     private String host;   private int port = DBPort.PORT;   private String uri = "mongodb://localhost/test";   private String database;     // ... getters/ setters omitted  }</code></pre>    <p>显然,它就是以 spring.data.mongodb 作为前缀的属性,然后通过名字直接映射为对象的属性,同时还包含了一些默认值。如果不配置,那么 mongo.uri 就是 mongodb://localhost/test 。</p>    <h2>配置通用属性</h2>    <p><a href="/misc/goto?guid=4959676986700611338" rel="nofollow,noindex">Spring Boot application.propertis配置文件的相关通用属性</a></p>    <p><a href="/misc/goto?guid=4959676986602408590" rel="nofollow,noindex">Spring Boot application.yaml配置文件的相关通用属性</a></p>    <p> </p>    <p>来自:http://blog.csdn.net/hguisu/article/details/51006252</p>    <p> </p>