19

Java アプリケーション、特に Spring サービスの構成を配布するために使用されている Apache ZooKeeper のよく文書化されたユースケースはありますか?

クラウド サービスの多くのユーザーと同様に、私はさまざまな量の Java サービスの構成を、できれば実行時にサービスを再起動する必要なく変更する必要があります。

アップデート

最終的には、ZooKeeper ノードをプロパティ ファイルとしてロードし、それを作成ResourcePropertySourceして Spring コンテキストに挿入するものを作成することになりました。これは、コンテキストが開始された後の ZooKeeper ノードの変更を反映しないことに注意してください。

public class ZooKeeperPropertiesApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    private static final Logger logger = LoggerFactory.getLogger(ZooKeeperPropertiesApplicationContextInitializer.class);

    private final CuratorFramework curator;
    private String projectName;
    private String projectVersion;

    public ZooKeeperPropertiesApplicationContextInitializer() throws IOException {
        logger.trace("Attempting to construct CuratorFramework instance");

        RetryPolicy retryPolicy = new ExponentialBackoffRetry(10, 100);
        curator = CuratorFrameworkFactory.newClient("zookeeper", retryPolicy);
        curator.start();
    }

    /**
     * Add a primary property source to the application context, populated from
     * a pre-existing ZooKeeper node.
     */
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        logger.trace("Attempting to add ZooKeeper-derived properties to ApplicationContext PropertySources");

        try {
            populateProjectProperties();
            Properties properties = populatePropertiesFromZooKeeper();
            PropertiesPropertySource propertySource = new PropertiesPropertySource("zookeeper", properties);
            applicationContext.getEnvironment().getPropertySources().addFirst(propertySource);

            logger.debug("Added ZooKeeper-derived properties to ApplicationContext PropertySources");
            curator.close();
        } catch (IOException e) {
            logger.error("IO error attempting to load properties from ZooKeeper", e);
            throw new IllegalStateException("Could not load ZooKeeper configuration");
        } catch (Exception e) {
            logger.error("IO error attempting to load properties from ZooKeeper", e);
            throw new IllegalStateException("Could not load ZooKeeper configuration");
        } finally {
            if (curator != null && curator.isStarted()) {
                curator.close();
            }
        }
    }

    /**
     * Populate the Maven artifact name and version from a property file that
     * should be on the classpath, with values entered via Maven filtering.
     * 
     * There is a way of doing these with manifests, but it's a right faff when
     * creating shaded uber-jars.
     * 
     * @throws IOException
     */
    private void populateProjectProperties() throws IOException {
        logger.trace("Attempting to get project name and version from properties file");

        try {
            ResourcePropertySource projectProps = new ResourcePropertySource("project.properties");
            this.projectName = (String) projectProps.getProperty("project.name");
            this.projectVersion = (String) projectProps.getProperty("project.version");
        } catch (IOException e) {
            logger.error("IO error trying to find project name and version, in order to get properties from ZooKeeper");
        }
    }

    /**
     * Do the actual loading of properties.
     * 
     * @return
     * @throws Exception
     * @throws IOException
     */
    private Properties populatePropertiesFromZooKeeper() throws Exception, IOException {
        logger.debug("Attempting to get properties from ZooKeeper");

        try {
            byte[] bytes = curator.getData().forPath("/distributed-config/" + projectName + "/" + projectVersion);
            InputStream in = new ByteArrayInputStream(bytes);
            Properties properties = new Properties();
            properties.load(in);
            return properties;
        } catch (NoNodeException e) {
            logger.error("Could not load application configuration from ZooKeeper as no node existed for project [{}]:[{}]", projectName, projectVersion);
            throw e;
        }

    }

}
4

6 に答える 6

6

Spring Cloud Config を検討する必要があります。

http://projects.spring.io/spring-cloud/

Spring Cloud Config git リポジトリに支えられた一元化された外部構成管理。構成リソースは Spring に直接マップEnvironmentされますが、必要に応じて非 Spring アプリケーションで使用できます。

ここで入手可能なソースコード:

https://github.com/spring-cloud/spring-cloud-config

サンプル アプリケーションはこちら:

https://github.com/spring-cloud/spring-cloud-config/blob/master/spring-cloud-config-sample/src/main/java/sample/Application.java

于 2014-09-14T17:56:45.440 に答える
2

https://github.com/james-wu-shanghai/spring-zookeeper.gitpropertyplaceholderconfigurerで、Spring Bean 統合 Zookeeper と springframework のセットを作成しましgithubた 。

于 2013-05-11T12:58:02.800 に答える
1

Zookeeper can be very nicely leveraged with higher abstraction using Curator APIs for configuration management in distributed applications. To get started just follow these two steps.

STEP 1 : Start zookeper server and then start zookeeper cli and create some znodes. Znodes are nothing but UNIX like files which contain values, and name of files depict property name.
To create/fetch/update properties use these commands on zookeeper cli.

create /system/dev/example/port 9091
get /system/dev/example/port
set /system/dev/example/port 9092

To fetch these properties in java program refer this code snippet.

import java.util.HashMap;
import java.util.Map;

import org.apache.curator.framework.CuratorFramework; 
import org.apache.curator.framework.CuratorFrameworkFactory; 
import org.apache.curator.retry.ExponentialBackoffRetry;
public class App 
{
    public static void main( String[] args ) throws Exception
    {
         final String ZK = "localhost:2181"; 

         final Map<String, String> data = new HashMap<String, String>();         
         CuratorFramework client = CuratorFrameworkFactory.newClient(ZK, new ExponentialBackoffRetry(100, 3)); 
         client.start();
         System.out.println(new String(client.getData().forPath("/system/dev/example/port")));
       }  
}
于 2017-01-11T09:33:50.197 に答える
1

特にSpringではありませんが、一般的にJavaの場合、ZooKeeperを検出サーバーとして使用して更新されたバンドルをコンテナーにプッシュする分散OSGI標準のCXF実装があります: http://cxf.apache.org/dosgi-discovery.html .

于 2012-03-30T14:59:03.967 に答える
0

私は先週、James Strachen による Apache Camel の講演に参加しました。彼は、構成情報のソースとして、クラウド内の Java ベースのサーバーの裏で ZooKeeper を使用していると述べました。

Adrian Colyer (SpringSource の CTO) が Spring のランタイム構成の変更について話しているのを見たことがありますが、Spring は現在これをサポートしていますか?

私の意見では、一般的に設計されたSpringアプリケーションから始めている場合、その上に動的構成の変更を簡単に後付けできるとは思えません。

于 2012-03-30T11:21:31.810 に答える
0

FactoryBeana を使用して通常のデータを入力するという提案を見つけた後、これを作成しPropertyPlaceholderConfigurerました:

package fms;

import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.AbstractFactoryBean;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Properties;

public class ZkPropertiesFactoryBean extends AbstractFactoryBean<Properties> implements Watcher {
    private Logger LOGGER = LoggerFactory.getLogger(ZkPropertiesFactoryBean.class);
    private String zkConnect;
    private String path;
    private int timeout = 1000;

    @Override protected Properties createInstance() throws Exception {
        long start = System.currentTimeMillis();
        Properties p = new Properties();
        p.load(new ByteArrayInputStream(loadFromZk()));
        double duration = (System.currentTimeMillis() - start)/1000d;
        LOGGER.info(String.format("Loaded %d properties from %s:%s in %2.3f sec", p.size(), zkConnect, path, duration));
        return p;
    }

    @Override public Class<Properties> getObjectType() {
        return Properties.class;
    }

    private byte[] loadFromZk() throws IOException, KeeperException, InterruptedException {Stat stat = new Stat();
        ZooKeeper zk = new ZooKeeper(zkConnect, timeout, this);
        return zk.getData(path, false, stat);
    }

    @Override public void process(WatchedEvent event) {}

    public void setPath(String path) {this.path = path;}

    public void setZkConnect(String zkConnect) {this.zkConnect = zkConnect;}
}

では、spring-config.xml次のように Bean を作成します。

<bean id="zkProperties" class="fms.ZkPropertiesFactoryBean" p:zkConnect="localhost:2181" p:path="/app/zk-properties"/>
<context:property-placeholder properties-ref="zkProperties"/>
于 2013-11-15T20:17:53.230 に答える