是否有任何有据可查的Apache ZooKeeper用例用于分发Java应用程序(尤其是Spring服务)的配置?
像许多云服务用户一样,我需要更改数量可变的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; } } }