1. 程式人生 > >我的編碼習慣 - 配置規範

我的編碼習慣 - 配置規範

ice 接口 思想 調用 中間 修改 com get 決定

原文出處:曉風輕

導讀:程序員你為什麽這麽累?

導讀(請先仔細閱讀):分享我工作中制定配置文件的習慣

工作中少不了要制定各種各樣的配置文件,這裏和大家分享一下工作中我是如何制定配置文件的,這是個人習慣,結合強大的spring,效果很不錯。

=============================需求==========================

如我們現在有一個這樣的配置需求,頂層是Server,有port和shutdown2個屬性,包含一個service集合,service對象有name一個屬性,並包含一個connector集合,connector對象有port和protocol2個屬性。

我一上來不會去考慮是用xml還是json還是數據庫配置,我會第一步寫好對應的配置bean。如上面的需求,就寫3個bean。bean和bean之間的包含關系要體現出來。(使用了lombok)

@Data
public class ServerCfg {
  private int port = 8005;
  private String shutDown = "SHUTDOWN";
  private List<ServiceCfg> services;
}

@Data
public class ServiceCfg {
  private String name;
  private List<ConnectorCfg> connectors;
}

@Data
public class ConnectorCfg {
  private int port = 8080;
  private String protocol = "HTTP/1.1";
}

然後找一個地方先用代碼產生這個bean:

@Configuration
public class Configs {

  @Bean
  public ServerCfg createTestBean() {
    ServerCfg server = new ServerCfg();

    // 
    List<ServiceCfg> services = new ArrayList<ServiceCfg>();
    server.setServices(services);

    // 
    ServiceCfg service = new ServiceCfg();
    services.add(service);

    service.setName("Kitty");
    
    // 
    List<ConnectorCfg> connectors = new ArrayList<ConnectorCfg>();
    service.setConnectors(connectors);

    //
    ConnectorCfg connectorhttp11 = new ConnectorCfg();

    connectorhttp11.setPort(8088);
    connectorhttp11.setProtocol("HTTP/1.1");

    connectors.add(connectorhttp11);

    //
    ConnectorCfg connectorAJP = new ConnectorCfg();

    connectorAJP.setPort(8089);
    connectorAJP.setProtocol("AJP");

    connectors.add(connectorAJP);
    
    return server;
  }
}

然後先測試,看看是否ok。為了演示,我就直接在controller裏面調用一下

@Autowired
ServerCfg cfg;

@GetMapping(value = "/configTest")
@ResponseBody
public ResultBean<ServerCfg> configTest() {
  return new ResultBean<ServerCfg>(cfg);
}

測試一下,工作正常

技術分享

然後進行業務代碼編寫,等到所有功能測試完畢,就是【開發後期】,再來定義配置文件。中途當然少不了修改格式,字段等各種修改,對於我們來說只是修改bean定義,so easy。

都ok了,再決定使用哪種配置文件。如果是json,我們這樣:

==============================JSON===========================

把上面接口調用的json復制下來,報存到配置文件。

技術分享

json內容

{
  "port": 8005,
  "shutDown": "SHUTDOWN",
  "services": [
    {
      "name": "Kitty",
      "connectors": [
        {
          "port": 8088,
          "protocol": "HTTP/1.1",
          "executor": null
        },
        {
          "port": 8089,
          "protocol": "AJP",
          "executor": null
        }
      ]
    }
  ]
}

然後修改config的bean生成的代碼為:

import com.fasterxml.jackson.databind.ObjectMapper;

@Configuration
public class Configs {
  @Value("classpath:config/tomcat.json")
  File serverConfigJson;
  
  @Bean
  public ServerCfg readServerConfig() throws IOException {
    return new ObjectMapper().readValue(serverConfigJson, ServerCfg.class); 
  }
}

代碼太簡潔了,有沒有?!

==============================XML===========================

如果使用XML,麻煩一點,我這裏使用XStream序列化和反序列化xml。

首先在bean上增加XStream相關註解

@Data
@XStreamAlias("Server")
public class ServerCfg {

  @XStreamAsAttribute
  private int port = 8005;

  @XStreamAsAttribute
  private String shutDown = "SHUTDOWN";

  private List<ServiceCfg> services;

}

@Data
@XStreamAlias("Service")
public class ServiceCfg {

  @XStreamAsAttribute
  private String name;

  private List<ConnectorCfg> connectors;
}

@Data
@XStreamAlias("Connector")
public class ConnectorCfg {
  @XStreamAsAttribute
  private int port = 8080;
  
  @XStreamAsAttribute
  private String protocol = "HTTP/1.1";
}

然後修改產品文件的bean代碼如下:

@Configuration
public class Configs {
  @Value("classpath:config/tomcat.xml")
  File serverConfigXML;

  @Bean
  public ServerCfg readServerConfig() throws IOException {
    return XMLConfig.toBean(serverConfigXML, ServerCfg.class);
  }
}

XMLConfig工具類相關代碼:

public class XMLConfig {

  public static String toXML(Object obj) {
    XStream xstream = new XStream();

    xstream.autodetectAnnotations(true);
    // xstream.processAnnotations(Server.class);

    return xstream.toXML(obj);
  }

  public static <T> T toBean(String xml, Class<T> cls) {
    XStream xstream = new XStream();

    xstream.processAnnotations(cls);
    T obj = (T) xstream.fromXML(xml);

    return obj;
  }

  public static <T> T toBean(File file, Class<T> cls) {
    XStream xstream = new XStream();

    xstream.processAnnotations(cls);
    T obj = (T) xstream.fromXML(file);

    return obj;
  }

}

XStream庫需要增加以下依賴:

<dependency>
  <groupId>com.thoughtworks.xstream</groupId>
  <artifactId>xstream</artifactId>
  <version>1.4.10</version>
</dependency>

所以個人愛好,格式推薦json格式配置。

=========================編碼習慣=========================

配置文件編碼禁忌

1. 讀取配置的代碼和業務代碼耦合在一起!大忌!千萬千萬不要!

如下,業務代碼裏面出現了json的配置代碼。

public void someServiceCode() {
  // 使用json配置,這裏讀取到了配置文件,返回的是json格式
  JSONObject config = readJsonConfig();
  
  // 如果某個配置了
  if(config.getBoolean("somekey")){
    // dosomething
  }
  else{
    
  }
}

2. 開發初期就定配置文件

毫無意義,還導致頻繁改動!先定義bean,改bean簡單多了。我的習慣是轉測試前一天才生成配置文件。

=============================重要============================

最主要的思想是,不要直接和配置文件發生關系,一定要有第三者(這裏是配置的bean)。你可以說是中間件,中介都行。 否則,一開始說用xml配置,後面說用json配置,再後面說配置放數據庫?這算不算需求變更?你們說算不算?算嗎?不算嗎?何必這麽認真呢?只是1,2行代碼的問題,這裏使用xml還是json,代碼修改量是2行。而且改了測試的話,寫個main函數或者junit測試即可,不需要測試業務,工程都不用起,你自己算算節約多少時間

另外,代碼裏面是使用spring的習慣,沒有spring也是一樣的,或者配置的bean你不用spring註入,而用工具類獲取也是一樣,區別不大。

我的編碼習慣 - 配置規範