Java 구성 로드 메커니즘 상세 및 실례

앞말
현재 거의 대부분의 자바 응용 프로그램, 예를 들어 우리가 잘 아는tomcat,struts2,netty... 등 셀 수 없는 소프트웨어는 유니버설성을 만족시키기 위해 사용자 맞춤형 기능을 제공하는 프로필을 제공한다.
심지어 일부 Netty와 같은 네트워크 프레임워크는 거의 완전히 설정에 의해 구동된다. 이런 소프트웨어를 우리는 통상적으로'마이크로코어 구조'라고 부른다.네가 그것을 무엇으로 배치했느냐, 그것이 바로 무엇이냐.
It is what you configure it to be.
가장 일반적인 프로파일 형식은 XML, Properties 등의 파일입니다.
본고는 로드 설정에서 가장 통용되고 가장 흔히 볼 수 있는 장면을 연구하고자 한다. 그것은 바로 하나의 프로필을 자바의 POJO 대상으로 비추는 것이다.
그리고 어떻게 서로 다른 방식의 로딩을 실현하는지 연구한다. 예를 들어 일부 설정은 로컬 XML 파일에서 불러오고 일부 설정은 로컬 Properties 파일에서 불러와야 한다.
더욱이 일부 설정은 네트워크를 통해 설정을 불러와야 한다.
어떻게 이런 설정 불러오는 메커니즘을 실현할 수 있습니까? 우리가 이 메커니즘을 가지고 있으면 불러오는 코드가 곳곳에 흩어지지 않고 확장되고 관리할 수 있습니다.
로더 구성
우선, 우리는 설정 마운트가 필요하다. 이 설정 마운트는 여러 가지 다른 마운트 방식을 가질 수 있기 때문에, 우리는 인터페이스로 그것을 다음과 같이 설명한다.

/**
 * 
 *
 * @author Bean
 * @date 2016 1 21   11:47:12
 * @version 1.0
 *
 */
public interface IConfigLoader<T> {

  /**
   * load the config typed by T
   *
   * @return
   * @throws ConfigException
   */
  public T load() throws ConfigException;
}

그런데, 왜 우리는 이 인터페이스에서 범용 를 성명해야 합니까?
분명히 우리가 플러그인을 사용하려고 할 때, 플러그인을 불러와서 어떤 결과를 얻어야 하는지 알려줘야 한다.
예를 들어, 구성을 로드한 후 AppleConfig 객체를 얻으면 위에서 정의한 인터페이스를 사용할 수 있습니다.
IConfigLoader loader = new AppleConfigLoader();
AppleConfig config = loader.load();
그래서 프로필에 있는 정보를 AppleConfig 대상으로 바꾸고, 이 AppleConfig 대상의 실례를 얻을 수 있습니다.
지금까지 Apple Config Loader에서 프로필을 어떻게 불러오는지 구체적인 작업을 실현하기만 하면 우리는 쉽게 프로필을 불러올 수 있을 것 같다.
이렇게 말할 수 있지만, 설정이 다른 방식으로 불러올 수 있다는 것을 아직 고려하지 않았습니다. 예를 들어Properties를 통해 불러오거나dom방식을 통해 불러오거나,sax방식을 통해 불러오거나,특정한 제3자의 소스 라이브러리를 통해 불러옵니다.
따라서 캐리어를 설정하는 것 외에 다른 역할, 캐리어 방식의 공급자를 설정해야 합니다.당분간, 우리는 그것을 IConfig Provider라고 부른다.
로딩 방식의 공급자 설정
로딩 방식을 설정하는 공급자는 로딩 방식을 설정 로더에 제공할 수 있으며, 다시 말하면 설정 로더에 대상을 제공할 수 있다.
  • dom 방식으로 로드하면 공급자는 Document 객체를 로드기에 제공합니다..
  • Properties 방식으로 불러오면 공급자는 Properties 대상을 캐리어에 제공합니다
  • 만약에 제3자 클래스 라이브러리에서 제공하는 방식으로 불러옵니다. 예를 들어apache-commons-digester3(tomcat의 설정 불러오기)을 통해 공급자는 Digester 대상을 추가기에 제공합니다
  • 공급자의 직책은 제공하는 것이다. 단지 이것뿐이다. 캐리어 설정에 필요한 대상만 제공하지만, 그 자체는 캐리어 설정 작업에 참여하지 않는다.
    우리는 인터페이스 IConfig Provider로 이 공급자를 정의합니다
    
    /**
     *
     *
     * @author Bean
     * @date 2016 1 21   11:54:28
     * @version 1.0
     *
     */
    public interface IConfigProvider<T> {
    
      /**
       * provide a config source used for loading config
       *
       * @return
       * @throws ConfigException
       */
      public T provide() throws ConfigException;
    }
    
    
    여기에 왜 또 가 범형을 성명합니까?
    만약 공급자가 필요하다면, 적어도 이 공급자에게 무엇을 제공해야 하는지 알려줘야 한다.
    따라서 공급자가 무엇을 제공할 것인지는 이것에 의해 결정된다.
    그리고 이곳에 와서 우리는 먼저 공장을 건설하여 특정한 공급자를 생산할 수 있다.
    
    /**
     *
     *
     * @author Bean
     * @date 2016 1 21   11:56:28
     * @version 1.0
     *
     */
    public class ConfigProviderFactory {
    
      private ConfigProviderFactory() {
        throw new UnsupportedOperationException("Unable to initialize a factory class : "
            + getClass().getSimpleName());
      }
    
      public static IConfigProvider<Document> createDocumentProvider(String filePath) {
        return new DocumentProvider(filePath);
      }
    
      public static IConfigProvider<Properties> createPropertiesProvider(String filePath) {
        return new PropertiesProvider(filePath);
      }
    
      public static IConfigProvider<Digester> createDigesterProvider(String filePath) {
          return new DigesterProvider(filePath);
      }
    }
     
    
    
    구체적인 설정 캐리어를 실행할 수 있습니까?
    아직 안 돼!
    여기까지, 만약 우리가 프로필을 가지고 있다면, apple이라고 한다.xml.그리고 우리는 DOM 방식을 통해 이 앱을xml을 로드하면 AppleConfig 객체가 됩니다.
    그러면 우선 공급자 공장을 통해 문서를 제공할 수 있는 공급자를 만들어 드리겠습니다.그리고 이 공급자를 얻으면 Document 대상을 얻기 위해provide 방법을 사용할 수 있습니다.document 대상이 있으면 설정을 불러올 수 있습니다.
    하지만 BananaConfig, PearConfig를 로드하려면...네, 그 절차는 모두 같습니다.따라서 우리는 기본적인 공동 행위를 실현하기 위해 추상적인 유형이 하나 더 있어야 한다.
    
    /**
     *
     *
     * @author Bean
     * @date 2016 1 21   11:59:19
     * @version 1.0
     *
     */
    public abstract class AbstractConfigLoader <T, U> implements IConfigLoader<T>{
    
      protected IConfigProvider<U> provider;
    
      protected AbstractConfigLoader(IConfigProvider<U> provider) {
        this.provider = provider;
      }
    
      /*
       * @see IConfigLoader#load()
       */
      @Override
      public T load() throws ConfigException {
        return load(getProvider().provide());
      }
    
      public abstract T load(U loaderSource) throws ConfigException;
    
      protected IConfigProvider<U> getProvider() {
        return this.provider;
      }
    }
    
    
    각 구성 로드에는 Provider를 수신하는 매개 변수 구조기가 있습니다.
    범형은 내가 불러올 Apple Config인지 Banan Config인지 가리키고, 범형 는 어떤 불러올 방식으로 불러올 것인지, Document인지, Properties인지 등을 가리킨다.
    실전 운용 실례
    요리 시장 프로필 시장이 있습니다.xml, 요리 시장의 상품을 배치했는데 그 안에 두 가지 상품이 있는데 각각 사과와 계란이다.
    
    <market>
      <apple>
        <color>red</color>
        <price>100</price>
      </apple>
      <egg>
        <weight>200</weight>
      </egg>
    </market>
    
    그리고 각 서류의 사장 이름에 대한 프로필, owner도 있습니다.properties
    port1=Steve Jobs
    port2=Bill Gates
    port3=Kobe Bryant
    우리는 먼저 다음과 같은 종류를 정의한다: MarketConfig.java
    
    /**
     *
     *
     * @author Bean
     * @date 2016 1 21   11:03:37
     * @version 1.0
     *
     */
    public class MarketConfig {
    
      private AppleConfig appleConfig;
      private EggConfig eggConfig;
      private OwnerConfig ownerConfig;
    
      public AppleConfig getAppleConfig() {
        return appleConfig;
      }
      public void setAppleConfig(AppleConfig appleConfig) {
        this.appleConfig = appleConfig;
      }
      public EggConfig getEggConfig() {
        return eggConfig;
      }
      public void setEggConfig(EggConfig eggConfig) {
        this.eggConfig = eggConfig;
      }
      public OwnerConfig getOwnerConfig() {
        return ownerConfig;
      }
      public void setOwnerConfig(OwnerConfig ownerConfig) {
        this.ownerConfig = ownerConfig;
      }
    }
    
    
    AppleConfig.java
    
    /**
     *
     *
     * @author Bean
     * @date 2016 1 21   11:03:45
     * @version 1.0
     *
     */
    public class AppleConfig {
    
      private int price;
      private String color;
    
      public void setPrice(int price) {
        this.price = price;
      }
    
      public int getPrice() {
        return this.price;
      }
    
      public void setColor(String color) {
        this.color = color;
      }
    
      public String getColor() {
        return this.color;
      }
    }
    
    
    EggConfig.java
    
    /**
     *
     *
     * @author Bean
     * @date 2016 1 21   11:03:58
     * @version 1.0
     *
     */
    public class EggConfig {
    
      private int weight;
    
      public void setWeight(int weight) {
        this.weight = weight;
      }
    
      public int getWeight() {
        return this.weight;
      }
    }
    
    
    OwnerConfig.java
    
    /**
     *
     *
     * @author Bean
     * @date 2016 1 21   11:04:06
     * @version 1.0
     *
     */
    public class OwnerConfig {
    
      private Map<String, String> owner = new HashMap<String, String>();
    
      public void addOwner(String portName, String owner) {
        this.owner.put(portName, owner);
      }
    
      public String getOwnerByPortName(String portName) {
        return this.owner.get(portName);
      }
    
      public Map<String, String> getOwners() {
        return Collections.unmodifiableMap(this.owner);
      }
    }
    
    
    이 예에는 Dom과 Properties 로드의 두 가지 구성 로드가 있습니다.
    그래서 우리 공급자가 공장을 건설하려면 두 가지 공급자provider를 제조해야 한다.
    또한 다음과 같은 2개의 구성 로더를 정의해야 합니다.
    OwnerConfigLoader
    
    /**
     *
     *
     * @author Bean
     * @date 2016 1 21   11:24:50
     * @version 1.0
     *
     */
    public class OwnerConfigLoader extends AbstractConfigLoader<OwnerConfig, Properties>{
    
      /**
       * @param provider
       */
      protected OwnerConfigLoader(IConfigProvider<Properties> provider) {
        super(provider);
      }
    
      /* 
       * @see AbstractConfigLoader#load(java.lang.Object)
       */
      @Override
      public OwnerConfig load(Properties props) throws ConfigException {
        OwnerConfig ownerConfig = new OwnerConfig();
    
        /**
         *  props, ownerConfig 
         * 
         *  
         */
        return ownerConfig;
      }
    }
    
    
    그다음에 Market Config Loader.
    
    import org.w3c.dom.Document;
    
    /**
     *
     *
     * @author Bean
     * @date 2016 1 21   11:18:56
     * @version 1.0
     *
     */
    public class MarketConfigLoader extends AbstractConfigLoader<MarketConfig, Document> {
    
      /**
       * @param provider
       */
      protected MarketConfigLoader(IConfigProvider<Document> provider) {
        super(provider);
      }
    
      /* 
       * AbstractConfigLoader#load(java.lang.Object)
       */
      @Override
      public MarketConfig load(Document document) throws ConfigException {
    
        MarketConfig marketConfig = new MarketConfig();
        AppleConfig appleConfig = new AppleConfig();
        EggConfig eggConfig = new EggConfig();
        /**
         *  document, 
         * AppleConfig EggConfg
         * 
         *  
         */
        marketConfig.setAppleConfig(appleConfig);
        marketConfig.setEggConfig(eggConfig);
    
        /**
         *  OwnerConfig properties , xml
         *  OwnerConfigLoader, OwnerConfig
         */
    
        OwnerConfigLoader ownerConfigLoader = new OwnerConfigLoader(ConfigProviderFactory.createPropertiesProvider(YOUR_FILE_PATH));
        OwnerConfig ownerConfig = ownerConfigLoader.load();
    
        marketConfig.setOwnerConfig(ownerConfig);
    
        return marketConfig;
      }
    }
    
    
    그리고 우리는 응용 차원에서 어떻게 MarketConfig를 얻을 수 있을까
    
    MarketConfigLoader marketConfigLoader = new MarketConfigLoader(ConfigProviderFactory.createDocumentProvider(YOUR_FILE_PATH));
    MarketConfig marketConfig = marketConfigLoader.load();
    
    이상한 점이 있을지도 몰라요. 분명히 네 개의 설정 종류가 있는데 왜 두 개의 설정 캐리어만 있습니까?MarketConfig, EggConfig, AppleConfig는 모두 같은 xml 프로필에서 불러오기 때문에 문서 대상만 있으면 MarketConfigLoader를 통해 모두 불러올 수 있습니다.
    OwnerConfig는 다른 로딩 방식이기 때문에 다른 로더가 필요합니다.
    총결산
    본고에서 제시한 설정 불러오는 메커니즘은 실제적으로 설정을 불러오는 것을 도울 수 없다. 이 일은 DOM, SAX, 그리고 다른 소스 라이브러리, 예를 들어dom4j, Digester에 남겨 두어야 한다.그러나 본고에서 제시한 설정 로드 메커니즘은 설정 로드 메커니즘을 더욱 유연하고 확장하기 쉬우며 다양한 설정 로드 방식을 통합시켜 하나의 메커니즘으로 융합시켜 각자의 장점을 발휘할 수 있다.
    실제로 일부 소프트웨어는 여러 가지 다른 형식의 프로필에서 프로필을 동시에 불러와야 한다. 예를 들어struts2, 그리고 내가 최근에 연구하고 피를 토하는 모 국산 소스 데이터베이스 중간부품 소프트웨어를 연구했다. 만약에 완전한 프로필 불러오는 메커니즘이 없다면 코드가 비교적 산란하고 유지보수성이 높지 않을 것이다.피를 토하기 쉽다.
    이 글을 통해 여러분은 자바 설정 로딩 메커니즘에 대한 지식을 이해하고 파악하시기 바랍니다. 본 사이트에 대한 지지에 감사드립니다!

    좋은 웹페이지 즐겨찾기