添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

这是我参与8月更文挑战的第12天,活动详情查看: 8月更文挑战

遇到的问题

首先在spring cloud微服务化的开发大环境下,配置的动态化必不可少,spring cloud 自身集成的config 配置中心就可以实现但是项目遇到了问题很不舒服: 我们公司spring cloud 集成config 方案就是一个bootstrap.yml文件作为加载启动文件,所有的配置从配置中心加载

server:
  port: 8688
#测试环境
eureka:
  client:
    serviceUrl:
      defaultZone: http://127.0.0.1:8601/eureka/
  instance:
    prefer-ip-address: true
spring:
  application:
    name: cccc
  cloud:
    config:
      discovery:
        enabled: true
        service-id: config
      profile: dev,redis
      label: master

大致就是上面那样,那么如果我要部署本地环境和线上环境呢,就是修改注册中心地址,根据分支进行控制 这样的话线上部署就用prod分支,本地部署就用local分支,测试部署就用test,但是这样很容易出现问题,就是改完代码之后分支的合并得小心,不能合并配置文件,否则会出现配置出错的问题

传统的 spring boot项目 其实可以根据配置文件的名字进行环境的切换 这样需要什么环境根据jvm参数或者maven打包参数进行构建就行

这个问题找了好久其实可以有这几种方案

  • 指定booststrap.yml的文件位置,通过 --spring.cloud.bootstrap.location= 启动参数设置
  • 放置一个空的bootstrap.yml,然后在项目启动时设置默认的参数 springApplication.setDefaultProperties(properties)
  • 想个办法动态的构建 bootstrap.yml 文件就是说项目启动时在 classpath下生成一个 bootstrap.yml 文件
  • 启动参数:

    java jar 0.0.1-SNAPSHOT.jar --spring.cloud.bootstrap.location=classpath:/local/bootstrap.yml
    

    这样是可以的,不同的环境不同的启动参数

    大家也看到了,这样话需要配置idea,让其识别,否则开发时代码没提示啊,不爽

    利用spring boot的加载顺序进行改变

    这是我从网上找的spring boot 加载顺序

    那么我们可以手动设置 还是一样classpath下放一个空的 bootstrap.yml 文件

    将配置放在 ${env}.properties文件中 resource - bootstrap.yml - local.properties - test.properties - prod.properties

    在项目启动类如下

    public class Application {
        public static void main(String[] args) throws Exception {
        	SpringApplication springApplication = new SpringApplication(Application.class)
    		// 虚拟机参数指定部署环境
    		String profile = System.getProperty("spring.profiles.active");
    		if (StringUtils.isEmpty(profile)){
    		    throw new RuntimeException("未指定构建环境");
    		log.info("构建环境 ==> {}", profile);
    		Properties properties1 = new Properties();
    		properties1.load(EcoIpadApplication.class.getClassLoader().getResourceAsStream(profile + ".properties"));
    		springApplication.setDefaultProperties(properties1);
    		springApplication.run(args);
    
    java -Dspring.profiles.active=local  jar 0.0.1-SNAPSHOT.jar
    

    代码也有提示(实在想不出来编的)

    项目原来的yml或者开发者喜欢用yml的这种格式的会感觉不舒服

    这种方案实现起来很多解决思路

  • 项目启动时复制指定环境的配置文件重命名为 bootstrap.yml
  • maven打包时利用插件将文件重定向
  • maven方案(推荐)

    pom 文件

    <profiles>
            <profile>
                <!-- 本地开发环境 -->
                <id>local</id>
                <properties>
                    <env>local</env>
                </properties>
                <activation>
                    <!-- 设置默认激活这个配置 -->
                    <activeByDefault>true</activeByDefault>
                </activation>
            </profile>
            <profile>
                <!-- 发布环境 -->
                <id>prod</id>
                <properties>
                    <env>prod</env>
                </properties>
            </profile>
            <profile>
                <!-- 测试环境 -->
                <id>test</id>
                <properties>
                    <env>test</env>
                </properties>
            </profile>
        </profiles>
    <build>
            <plugins>
                <!--将指定环境的yml文件重命名为bootstrap.yml-->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-antrun-plugin</artifactId>
                    <version>1.8</version>
                    <executions>
                        <execution>
                            <phase>compile</phase>
                            <goals>
                                <goal>run</goal>
                            </goals>
                            <configuration>
                                <tasks>
                                    <move file="${project.build.directory}/classes/application-${env}.yml"
                                          tofile="${project.build.directory}/classes/bootstrap.yml" />
                                </tasks>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    

    这样maven打包时

    mvn clean install -Dmaven.test.skip=true -Ptest
    

    打包完target/classes如下 这也是我现在用的方案

    既没有硬编码又使用了yml格式

    维护起来不方便,要是接手项目的人不懂又没写好注释把这个插件删了,那就凉了

    硬编码方案

    public class Application {
        public static void main(String[] args) throws Exception {
     		String profile = System.getProperty("spring.profiles.active");
    		 if (StringUtils.isEmpty(profile)){
    		      throw new RuntimeException("未指定构建环境");
    		  log.info("构建环境 ==> {}", profile);
    		// 获取项目构建路径
    		// 这里想不到方案直接把文件放到 classpath 下,linux环境下不行,所以退而求其次,放到外部的文件夹
    		  String property = System.getProperty("user.dir");
    		  Resource resource = new DefaultResourceLoader().getResource("classpath:" + String.format("application-%s.yml", profile));
    		  File target = new File(property + File.separator + "bootstrap.yml");
    		  if (target.exists()){
    		      target.delete();
    		  Files.copy(resource.getInputStream(), target.toPath());
    		  if (target.exists()){
    		      List<String> collect = Stream.of(args).collect(Collectors.toList());
    			// 指定配置文件地址
    		      collect.add("--spring.cloud.bootstrap.location=" + target.getPath());
    		      args = collect.toArray(new String[0]);
    

    其实还有一种方案,基于分支构建,但是改动小 利用yml多环境配置

    server:
      port: 8688
    spring:
      profiles:
        active: test
    #测试环境
    eureka:
      client:
        serviceUrl:
          defaultZone: http://127.0.0.1:8601/eureka/
      instance:
        prefer-ip-address: true
    spring:
      application:
        name: cccc
      cloud:
        config:
          discovery:
            enabled: true
            service-id: config
          profile: dev,redis
          label: master
      profiles: test
    # 正式环境
    eureka:
      client:
        serviceUrl:
          defaultZone: http://127.0.0.1:8601/eureka/
      instance:
        prefer-ip-address: true
    spring:
      application:
        name: cccc
      cloud:
        config:
          discovery:
            enabled: true
            service-id: config
          profile: dev,redis
          label: master
      profiles: prod
    

    合并代码时只要小心

    spring:
      profiles:
        active: test
    

    其实一开始的问题应该还有更优雅的解决方案,只是我没找到,还有其他方案的朋友可以留个言让我学习下,谢谢