通常在一个项目中,老是会有好多个环境。好比:javascript
开发环境 -> 测试环境 -> 预发布环境【验证环境】 -> 生产环境html
每一个环境上的配置文件老是不同的,甚至开发环境中每一个开发者的环境可能也会有一点不一样,配置读取但是一个让人有点伤脑筋的问题。java
Spring Boot提供了一种优先级配置读取的机制来帮助咱们从这种困境中走出来。mysql
常规状况下,咱们都知道Spring Boot的配置会从application.properties
中读取。实际上,从resource
目录下的application.properties
文件读取是Spring Boot配置链中的一环而已。linux
在应用中管理配置并非一个容易的任务,尤为是在应用须要部署到多个环境中时。一般会须要为每一个环境提供一个对应的属性文件,用来配置各自的数据库链接信息、服务器信息和第三方服务帐号等。一般的应用部署会包含开发、测试和生产等若干个环境。不一样的环境之间的配置存在覆盖关系。测试环境中的配置会覆盖开发环境,而生产环境中的配置会覆盖测试环境。Spring 框架自己提供了多种的方式来管理配置属性文件。
Spring 3.1 以前可使用 PropertyPlaceholderConfigurer【继承PropertyPlaceholderConfigurer读取配置文件,相关示例代码见下】。
Spring 3.1 引入了新的环境(Environment)和概要信息(Profile)API,是一种更加灵活的处理不一样环境和配置文件的方式。不过 Spring 这些配置管理方式的问题在于选择太多,让开发人员无所适从。Spring Boot 提供了一种统一的方式来管理应用的配置,容许开发人员使用属性文件、YAML 文件、环境变量和命令行参数来定义优先级不一样的配置值。web
Spring Boot 所提供的配置优先级顺序比较复杂。按照优先级从高到低的顺序,具体的列表以下所示。spring
Spring Boot 的这个配置优先级看似复杂,实际上是很合理的。好比命令行参数的优先级被设置为最高。
这样的好处是能够在测试或生产环境中快速地修改配置参数值,而不须要从新打包和部署应用。sql
SpringApplication 类默认会把以“--”开头的命令行参数转化成应用中可使用的配置参数,如 “--name=Alex” 会设置配置参数 “name” 的值为 “Alex”。若是不须要这个功能,能够经过 “SpringApplication.setAddCommandLineProperties(false)” 禁用解析命令行参数。数据库
RandomValuePropertySource 能够用来生成测试所须要的各类不一样类型的随机值,从而免去了在代码中生成的麻烦。RandomValuePropertySource 能够生成数字和字符串。数字的类型包含 int 和 long,能够限定数字的大小范围。以“random.”做为前缀的配置属性名称由 RandomValuePropertySource 来生成,如代码清单 3 所示。tomcat
user.id=${random.value} user.count=${random.int} user.max=${random.long} user.number=${random.int(100)} user.range=${random.int[100, 1000]}
属性文件
属性文件是最多见的管理配置属性的方式。Spring Boot 提供的 SpringApplication 类会搜索并加载 application.properties 文件来获取配置属性值。SpringApplication 类会在下面位置搜索该文件。
上面的顺序也表示了该位置上包含的属性文件的优先级。优先级按照从高到低的顺序排列。能够经过“spring.config.name”配置属性来指定不一样的属性文件名称。也能够经过“spring.config.location”来添加额外的属性文件的搜索路径。若是应用中包含多个 profile,能够为每一个 profile 定义各自的属性文件,按照“application-{profile}”来命名。
对于配置属性,能够在代码中经过“@Value”来使用,如代码清单 4 所示。
@RestController @EnableAutoConfiguration public class Application { @Value("${name}") private String name; @RequestMapping("/") String home() { return String.format("Hello %s!", name); } }
在代码清单 4 中,变量 name 的值来自配置属性中的“name”属性。
相对于属性文件来讲,YAML 是一个更好的配置文件格式。YAML 在 Ruby on Rails 中获得了很好的应用。SpringApplication 类也提供了对 YAML 配置文件的支持,只须要添加对 SnakeYAML 的依赖便可。代码清单 5 给出了 application.yml 文件的示例。
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
代码清单 5 中的 YAML 文件同时给出了 development 和 test 两个不一样的 profile 的配置信息,这也是 YAML 文件相对于属性文件的优点之一。
除了使用“@Value”注解绑定配置属性值以外,还可使用更加灵活的方式。
代码清单 6 给出的是使用代码清单 5 中的 YAML 文件的 Java 类。
经过“@ConfigurationProperties(prefix="db")”注解,配置属性中以“db”为前缀的属性值会被自动绑定到 Java 类中同名的域上,如 url 域的值会对应属性“db.url”的值。
只须要在应用的配置类中添加“@EnableConfigurationProperties”注解就能够启用该自动绑定功能。
@Component @ConfigurationProperties(prefix="db") public class DBSettings { private String url; private String username; private String password; }
http://www.ibm.com/developerworks/cn/java/j-lo-spring-boot/index.html
这意味着,若是Spring Boot在优先级更高的位置找到了配置,那么它就会无视优先级低的配置。
好比,我在application.properties
目录中,写入本地的MySQL的配置:
db.jdbc.driver=com.mysql.jdbc.Driver db.jdbc.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8 db.jdbc.username=username db.jdbc.password=password
在本身项目调试的阶段,项目老是会使用本地的MySQL数据库。而一旦打包以后,在外部声明一个test_evn.properties
.
启动Jar包的时候, 指定一个外部配置文件:
java -jar demo.jar --spring.config.location=/path/test_evn.properties
这样一来,咱们在开发者的机器上老是使用本身的配置,而一到对应的环境,就会使用高级的位置所作的配置。
在代码中读取这些配置也是很是方便的,在代码的逻辑中,实际上是无需去关心这个配置是从什么地方来的,只用关注能获取什么配置就够了。
public class ApplicationConfigure { @Value("${db.jdbc.driver}") private String jdbcDriver; @Value("${db.jdbc.url}") private String jdbcUrl; @Value("${db.jdbc.username}") private String jdbcUsername; @Value("${db.jdbc.password}") private String jdbcPassword; // mysql config class // ..... }
有时候咱们在项目启动的时候,老是须要先启动一些初始化的类,之前比较常见的作法是写再static
块中,Spring Boot提供了一个CommandLineRunner
接口,实现这个接口的类老是会被优先启动,并优先执行CommandLineRunner
接口中提供的run()
方法。
public class ApplicationConfigure implements CommandLineRunner { @Value("${db.jdbc.driver}") private String jdbcDriver; @Value("${db.jdbc.url}") private String jdbcUrl; @Value("${db.jdbc.username}") private String jdbcUsername; @Value("${db.jdbc.password}") private String jdbcPassword; // mysql config class // ..... @Override public void run(String... strings) throws Exception { // 预先加载的一些方法,类,属性。 } }
若是有多个CommandLineRunner
接口实现类,那么能够经过注解@Order
来规定全部实现类的运行顺序。
经过这一系列API的帮助,Spring Boot让环境配置变得轻松不少。
http://www.cnblogs.com/whthomas/p/5270917.html
http://www.ibm.com/developerworks/cn/java/j-lo-spring-boot/index.html
Tomcat
Tomcat为Spring Boot的默认容器,下面是几个经常使用配置:
# tomcat最大线程数,默认为200 server.tomcat.max-threads=800 # tomcat的URI编码 server.tomcat.uri-encoding=UTF-8 # 存放Tomcat的日志、Dump等文件的临时文件夹,默认为系统的tmp文件夹(如:C:\Users\Shanhy\AppData\Local\Temp) server.tomcat.basedir=H:/springboot-tomcat-tmp # 打开Tomcat的Access日志,并能够设置日志格式的方法: #server.tomcat.access-log-enabled=true #server.tomcat.access-log-pattern= # accesslog目录,默认在basedir/logs #server.tomcat.accesslog.directory= # 日志文件目录 logging.path=H:/springboot-tomcat-tmp # 日志文件名称,默认为spring.log logging.file=myapp.log
Jetty
若是你要选择Jetty,也很是简单,就是把pom中的tomcat依赖排除,并加入Jetty容器的依赖,以下:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <dependencies>
打包
打包方法:
CMD进入项目目录,使用 mvn clean package 命令打包,以个人项目工程为例:
E:\spring-boot-sample>mvn clean package
能够追加参数 -Dmaven.test.skip=true (-DskipTests)跳过测试。
打包后的文件存放于项目下的target目录中,如:spring-boot-sample-0.0.1-SNAPSHOT.jar
若是pom配置的是war包,则为spring-boot-sample-0.0.1-SNAPSHOT.war
public class SpringBootSampleApplication extends SpringBootServletInitializer{ private static final Logger logger = LoggerFactory.getLogger(SpringBootSampleApplication.class); @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(this.getClass()); } }
<!-- <packaging>jar</packaging> --> <packaging>war</packaging>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
spring boot 能够在 “配置文件”、“Java代码类”、“日志配置” 中来配置profile区分不一样环境执行不一样的结果
一、配置文件
使用配置文件application.yml 和 application.properties 有所区别
以application.properties 为例,经过文件名来区分环境 application-{profile}.properties
application.properties
app.name=MyApp server.port=8080 spring.profiles.active=dev
application-dev.properties
server.port=8081
application-stg.properties
server.port=8082
在启动程序的时候经过添加 –spring.profiles.active={profile} 来指定具体使用的配置
例如咱们执行 java -jar demo.jar –spring.profiles.active=dev 那么上面3个文件中的内容将被如何应用?
Spring Boot 会先加载默认的配置文件,而后使用具体指定的profile中的配置去覆盖默认配置。
app.name 只存在于默认配置文件 application.properties 中,由于指定环境中不存在一样的配置,因此该值不会被覆盖
server.port 默认为8080,可是咱们指定了环境后,将会被覆盖。若是指定stg环境,server.port 则为 8082
spring.profiles.active 默认指定dev环境,若是咱们在运行时指定 –spring.profiles.active=stg 那么将应用stg环境,最终 server.port 的值为8082
二、Java类中@Profile注解
下面2个不一样的类实现了同一个接口,@Profile注解指定了具体环境
// 接口定义 public interface SendMessage { // 发送短信方法定义 public void send(); }
// Dev 环境实现类 @Component @Profile("dev") public class DevSendMessage implements SendMessage { @Override public void send() { System.out.println(">>>>>>>>Dev Send()<<<<<<<<"); } }
// Stg环境实现类 @Component @Profile("stg") public class StgSendMessage implements SendMessage { @Override public void send() { System.out.println(">>>>>>>>Stg Send()<<<<<<<<"); } }
// 启动类 @SpringBootApplication public class ProfiledemoApplication { @Value("${app.name}") private String name; @Autowired private SendMessage sendMessage; @PostConstruct public void init(){ sendMessage.send();// 会根据profile指定的环境实例化对应的类 } }
三、logback-spring.xml也支持有节点来支持区分
<?xml version="1.0" encoding="UTF-8"?> <configuration> <include resource="org/springframework/boot/logging/logback/base.xml" /> <logger name="org.springframework.web" level="INFO"/> <springProfile name="default"> <logger name="org.springboot.sample" level="TRACE" /> </springProfile> <springProfile name="dev"> <logger name="org.springboot.sample" level="DEBUG" /> </springProfile> <springProfile name="staging"> <logger name="org.springboot.sample" level="INFO" /> </springProfile> </configuration>
再说一遍文件名不要用logback.xml 请使用logback-spring.xml
有些系统,关于一些数据库或其余第三方帐户等信息,因为安全问题,其配置并不会提早配置在项目中暴露给开发人员。
对于这种状况,咱们在运行程序的时候,能够经过参数指定一个外部配置文件。
以 demo.jar 为例,方法以下:
java -jar demo.jar --spring.config.location=/opt/config/application.properties
其中文件名随便定义,无固定要求。
下面几个脚本仅供参考,请根据本身须要作调整
start.sh
#!/bin/sh rm -f tpid nohup java -jar /data/app/myapp.jar --spring.profiles.active=stg > /dev/null 2>&1 & echo $! > tpid
stop.sh
tpid=`cat tpid | awk '{print $1}'` tpid=`ps -aef | grep $tpid | awk '{print $2}' |grep $tpid` if [ ${tpid} ]; then kill -9 $tpid fi
check.sh
tpid=`cat tpid | awk '{print $1}'` tpid=`ps -aef | grep $tpid | awk '{print $2}' |grep $tpid` if [ ${tpid} ]; then echo App is running. else echo App is NOT running. fi
kill.sh
#!/bin/sh # kill -9 `ps -ef|grep 项目名称|awk '{print $2}'` kill -9 `ps -ef|grep demo|awk '{print $2}'`
继承PropertyPlaceholderConfigurer.从spring容器获取取配置文件属性
import java.util.HashMap; import java.util.Map; import java.util.Properties; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; public class CustomPropertyConfig extends PropertyPlaceholderConfigurer{ private static Map<String, Object> ctxPropertiesMap; @Override protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,Properties props) throws BeansException { super.processProperties(beanFactoryToProcess, props); ctxPropertiesMap = new HashMap<String, Object>(); for (Object key : props.keySet()) { String keyStr = key.toString(); String value = props.getProperty(keyStr); ctxPropertiesMap.put(keyStr, value); } } public static Object getContextProperty(String name) { return ctxPropertiesMap.get(name); } }
<bean id="propertyConfigurer" class="com.test.utils.CustomPropertyConfig"> <property name="locations"> <list> <!-- org.springframework.beans.factory.config.PropertyPlaceholderConfigurer这里支持多种寻址方式:classpath和file --> <!-- 推荐使用file的方式引入,这样能够将配置和代码分离 --> <!-- <value>classpath:jdbc.properties</value> --> <value>classpath:dbconfig.properties</value> </list> </property> </bean>
https://blog.csdn.net/y_index/article/details/79893765
实现BeanFactoryAware来达到Spring静态方法获取Bean对象的BeanUtil工具类
在spring里自己是没有提供这类方法的。
因此咱们只能经过重写一些类来达到咱们想要的效果
在容器初始化时注入Bean工厂,并提供一些列静态方法,用于运行期间任何地方均可以用过他来获许对应Bean
import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; public class BeanUtil implements BeanFactoryAware{ private static BeanFactory beanFactory; // private static ApplicationContext context; @Override public void setBeanFactory(BeanFactory factory) throws BeansException { this.beanFactory = factory; } /** * 根据beanName名字取得bean * * @param beanName * @return */ public static <T> T getBean(String beanName) { if (null != beanFactory) { return (T) beanFactory.getBean(beanName); } return null; } }