springcloud(1) : 自定义配置中心并实现读取配置启动项目

1.定义http配置接口

接口名为 : /springbootService/server01,完整接口路径如下

http://127.0.0.1:10001/springbootService/server01

注 : springbootService在其他服务中定义,server01为配置名称

接口响应格式与内容如下

{
    "name":"springbootService",
    "profiles":[
        "server01"
    ],
    "label":null,
    "propertySources":[
        {
            "name":"http://127.0.0.1:10001/springbootService/server01",
            "source":{
                "name":"001",
                "server.port":"8002"
            }
        }
    ],
    "version":null,
    "state":null
}

说明 : 只需要关注 source 属性即可

对象类如下

Environment
package com.aliyun.industry.configuration.biz.model.config;

import java.util.List;

/**
 * @Auther: liyue
 * @Date: 2020/5/6 18:13
 * @Description:
 */
public class Environment {
    private String name;
    private String[] profiles;
    private String label;
    private List<PropertySource> propertySources;
    private String version;
    private String state;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String[] getProfiles() {
        return profiles;
    }

    public void setProfiles(String[] profiles) {
        this.profiles = profiles;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public List<PropertySource> getPropertySources() {
        return propertySources;
    }

    public void setPropertySources(List<PropertySource> propertySources) {
        this.propertySources = propertySources;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public Environment() {

    }

    public Environment(String name, String[] profiles, String label, List<PropertySource> propertySources, String version, String state) {

        this.name = name;
        this.profiles = profiles;
        this.label = label;
        this.propertySources = propertySources;
        this.version = version;
        this.state = state;
    }
}
PropertySource

import java.util.Map;

/**
 * @Auther: liyue
 * @Date: 2020/5/6 18:14
 * @Description:
 */
public class PropertySource {
    private String name;
    private Map<?, ?> source;

    public PropertySource() {
    }

    public PropertySource(String name, Map<?, ?> source) {
        this.name = name;
        this.source = source;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Map<?, ?> getSource() {
        return source;
    }

    public void setSource(Map<?, ?> source) {
        this.source = source;
    }
}

封装工具类 : ConfigWrapperUtil ; type是配置文件名,content是map类型,key是配置名称,value是配置值


import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * @Auther: liyue
 * @Date: 2020/5/8 17:09
 * @Description:
 */
public class ConfigWrapperUtil {

    public static Environment wrapper(String type, Map<String,String> content){
        Environment environment = new Environment();
        environment.setName("springbootService");
        environment.setLabel(null);
        String[] profiles = {type};
        environment.setProfiles(profiles);
        PropertySource propertySource = new PropertySource("http://127.0.0.1:10001/springbootService/"+type,content);
        List<PropertySource> propertySources = new LinkedList<PropertySource>(){{
            add(propertySource);
        }};
        environment.setPropertySources(propertySources);
        return environment;
    }
}

控制层 : SpringCloudConfigController

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;
import java.util.TreeMap;

/**
 * @Auther: liyue
 * @Date: 2020/5/8 17:05
 * @Description:
 */
@RestController
public class SpringCloudConfigController {


    @RequestMapping("/{springbootService}/{type}")
    public Object getMap(@PathVariable String type) {
        Map<String, String> map = new TreeMap<>();
        map.put("server.port", "8002");
        map.put("name", "张三");
        return ConfigWrapperUtil.wrapper(type, map);
    }
}

 注 : springbootService 两边不加大括号的话,该名称必须和其他服务的 spring.application.name 配置的数值对应才能读取,两边加了大括号之后可以通用匹配,不需要管其他服务的 spring.application.name 配置内容

2.其他springboot服务读取配置

引入maven配置

<!--Spring Cloud Config 客户端依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
            <version>1.4.0.RELEASE</version>
        </dependency>

resources下新建 bootstrap.properties 文件,profile为接口的第二个URI,内容如下

spring.cloud.config.uri=http://localhost:10001/
spring.cloud.config.profile=server01

application.properties 中定义 spring.application.name,改数值必须与配置接口的第一个URI相同

spring.application.name=springCloudConfig
server.port=8001

3.调试

配置接口正常访问时,启动测试服务,若以8002端口运行说明成功,8001端口说明获取配置失败

4.依赖对应

  • 2.0.2.RELEASE
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
            <version>2.0.2.RELEASE</version>
        </dependency>
  • parent
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
        <relativePath />
    </parent>


    <properties>
        <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
    </properties>

5.配置增删改查(文件形式存储)

package com.alibaba.gts.flm.config.center.api.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.gts.flm.config.center.api.constant.Constants;
import com.alibaba.gts.flm.config.center.api.controller.model.CommonResult;
import com.alibaba.gts.flm.config.center.api.exception.MsgException;
import com.alibaba.gts.flm.config.center.api.service.model.ConfigDTO;
import com.alibaba.gts.flm.config.center.api.service.model.Environment;
import com.alibaba.gts.flm.config.center.api.service.model.PropertySource;
import com.alibaba.gts.flm.config.center.api.util.DateUtil;
import com.alibaba.gts.flm.config.center.api.util.FileUtil;
import com.alibaba.gts.flm.config.center.api.util.ShellUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: liyue
 * @Date: 2023/05/31/09:49
 * @Description:
 */
@Service
public class ConfigService {

    public static final String configListFile = Constants.configPath + File.separator + "list.json";

    @Value("${ip}")
    private String ip;

    @Value("${server.port}")
    private Integer port;

    public Object list(ConfigDTO req) {
        if (!new File(configListFile).exists()) {
            return CommonResult.success();
        }
        String s = FileUtil.readByLineRs(configListFile);
        List<ConfigDTO> reqS = JSONArray.parseArray(s, ConfigDTO.class);
        List<ConfigDTO> rs = reqS.stream().filter(c -> filter(req, c)).collect(Collectors.toList());
        int index = 1;
        for (ConfigDTO r : rs) {
            r.setNumber(index);
            index++;
        }
        return CommonResult.success(rs);
    }

    private Boolean filter(ConfigDTO req, ConfigDTO c) {
        JSONObject reqs = JSONObject.parseObject(JSONObject.toJSONString(req));
        if (reqs.size() == 0) {
            return Boolean.TRUE;
        }
        JSONObject cs = JSONObject.parseObject(JSONObject.toJSONString(c));
        Boolean rs = Boolean.FALSE;
        for (Map.Entry<String, Object> entry : reqs.entrySet()) {
            String cv = cs.getString(entry.getKey());
            Object reqv = entry.getValue();
            if (reqv == null) {
                rs = Boolean.FALSE;
            } else {
                if (cv.contains(reqv.toString())) {
                    rs = Boolean.TRUE;
                } else {
                    return Boolean.FALSE;
                }
            }
        }
        return rs;
    }

    public Object getById(Long id) {
        if (!new File(configListFile).exists()) {
            return CommonResult.success();
        }
        String s = FileUtil.readByLineRs(configListFile);
        List<ConfigDTO> reqS = JSONArray.parseArray(s, ConfigDTO.class);
        ConfigDTO req = reqS.stream().filter(c -> c.getId().equals(id)).findFirst().get();
        return CommonResult.success(req);
    }

    public Object add(ConfigDTO req) {
        List<ConfigDTO> reqS = null;
//        if (req.getConfig().equals("commonConfig")){
//            throw new MsgException("<公共配置>已添加");
//        }
        if (new File(configListFile).exists()) {
            String s = FileUtil.readByLineRs(configListFile);
            reqS = JSONArray.parseArray(s, ConfigDTO.class);
            Long max = null;
            try {
                max = reqS.stream().max(Comparator.comparingLong(ConfigDTO::getId)).get().getId();
            } catch (Exception e) {
                max = 0L;
            }
            req.setId(max + 1);
            reqS.add(req);
        } else {
            reqS = new LinkedList<>();
            req.setId(1L);
            reqS.add(req);
        }
        FileUtil.write(configListFile, JSONObject.toJSONString(reqS));
        return CommonResult.success();
    }

    private void backup(){
        ShellUtil.exec("cp "+configListFile+" "+configListFile+".bak_"+ DateUtil.format(new Date(),DateUtil.PATTERN_YYYYMMDDHHMMSSSSS));
    }

    public Object update(ConfigDTO req) {
        if (!new File(configListFile).exists()) {
            return CommonResult.success();
        }
        this.backup();
        String s = FileUtil.readByLineRs(configListFile);
        List<ConfigDTO> reqS = JSONArray.parseArray(s, ConfigDTO.class);
        for (ConfigDTO dto : reqS) {
            if (dto.getId().equals(req.getId())) {
                if (req.getName() != null) {
                    dto.setName(req.getName());
                }
                if (req.getConfig() != null) {
                    dto.setConfig(req.getConfig());
                }
                if (req.getEnv() != null) {
                    dto.setEnv(req.getEnv());
                }
                if (req.getRemake() != null) {
                    dto.setRemake(req.getRemake());
                }
                if (req.getContent() != null) {
                    checkPropertiesStr(req.getContent());
                    dto.setContent(req.getContent());
                }
                break;
            }
        }
        FileUtil.write(configListFile, JSONObject.toJSONString(reqS));
        return CommonResult.success();
    }

    public Object delete(Long id) {
        if (!new File(configListFile).exists()) {
            return CommonResult.success();
        }
        this.backup();
        String s = FileUtil.readByLineRs(configListFile);
        List<ConfigDTO> reqS = JSONArray.parseArray(s, ConfigDTO.class);
        Iterator<ConfigDTO> iterator = reqS.iterator();
        while (iterator.hasNext()) {
            ConfigDTO next = iterator.next();
//            if (next.getConfig().equals("commonConfig")){
//                throw new MsgException("公共配置无法删除");
//            }
            if (next.getId().equals(id)) {
                iterator.remove();
                break;
            }
        }
        FileUtil.write(configListFile, JSONObject.toJSONString(reqS));
        return CommonResult.success();
    }

    public Object getConfig(String config, String env) {
        if (!new File(configListFile).exists()) {
            return CommonResult.success();
        }
        String s = FileUtil.readByLineRs(configListFile);
        List<ConfigDTO> reqS = JSONArray.parseArray(s, ConfigDTO.class);
        ConfigDTO req = reqS.stream().filter(c -> c.getConfig().equals(config) && c.getEnv().equals(env)).findFirst().get();
        Map<String, String> map = JSONObject.parseObject(propertiesStrToJsonStr(req.getContent()), Map.class);
        return wrapper(config, env, map);
    }

    public static void main(String[] args) {
        String s = "url=2222=3333";
        int i = s.indexOf("=");
        System.out.println(s.substring(0, i));
        System.out.println(s.substring(i + 1));
    }

    private void checkPropertiesStr(String str) {
        for (String s : str.split("\n")) {
            if (isContinue(s)) {
                continue;
            }
            try {
                int i = s.indexOf("=");
                s.substring(0, i);
                s.substring(i + 1);
            } catch (Exception e) {
                throw new MsgException("内容\"" + s + "\"格式错误! 正确格式为 k=v");
            }
        }
    }

    public String propertiesStrToJsonStr(String str) {
        if (str == null) {
            return null;
        }
        JSONObject json = new JSONObject();
        for (String s : str.split("\n")) {
            if (isContinue(s)) {
                continue;
            }
            try {
                int i = s.indexOf("=");
                json.put(s.substring(0, i), s.substring(i + 1));
            } catch (Exception e) {
                throw new MsgException("内容\"" + s + "\"格式错误! 正确格式为 k=v");
            }
        }
        return json.toJSONString();
    }

    private Boolean isContinue(String str) {
        if (str.startsWith("#") || str.equals("") || str.trim().equals("")) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    public String jsonStrToPropertiesStr(String str) {
        if (str == null) {
            return null;
        }
        JSONObject jsonObject = JSONObject.parseObject(str);
        StringBuilder sb = new StringBuilder();
        jsonObject.forEach((k, v) -> {
            sb.append(k).append("=").append(v).append("\n");
        });
        return sb.toString();
    }

    public Environment wrapper(String config, String env, Map<String, String> content) {
        Environment environment = new Environment();
        environment.setName(config);
        environment.setLabel(null);
        String[] profiles = {env};
        environment.setProfiles(profiles);
        PropertySource propertySource = new PropertySource("http://" + ip + ":" + port + "/" + config + "/" + env, content);
        List<PropertySource> propertySources = new LinkedList<PropertySource>() {{
            add(propertySource);
        }};
        environment.setPropertySources(propertySources);
        return environment;
    }
}

工具类 : Java 常用工具类(30) : File工具类_archive.nextfileheader() 为空_Lxinccode的博客-CSDN博客

END。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值