mirror of
https://gitee.com/dromara/hmily.git
synced 2024-12-04 20:28:20 +08:00
add hmily load config module
This commit is contained in:
parent
9118991b9d
commit
a703d8cacb
@ -43,5 +43,4 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
@ -56,37 +56,15 @@ public final class ConfigEnv {
|
||||
return INST;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a class Path that needs to be processed.
|
||||
*
|
||||
* @param classPath class path.
|
||||
*/
|
||||
public void addConfigClassPath(String classPath) {
|
||||
if (classPath.startsWith("java.")) {
|
||||
logger.warn("config class path Ignore {}", classPath);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Class<?> clazz = Class.forName(classPath);
|
||||
addConfigClass(clazz);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new ConfigException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add config class.
|
||||
* Register config.
|
||||
*
|
||||
* @param clazz the clazz
|
||||
* @param config the config
|
||||
*/
|
||||
public void addConfigClass(Class<?> clazz) {
|
||||
if (clazz.getSuperclass().isAssignableFrom(AbstractConfig.class)) {
|
||||
try {
|
||||
AbstractConfig configParent = (AbstractConfig) clazz.newInstance();
|
||||
putBean(configParent);
|
||||
} catch (IllegalAccessException | InstantiationException e) {
|
||||
throw new ConfigException(e);
|
||||
}
|
||||
public void registerConfig(final Config config) {
|
||||
if (config.getClass().getSuperclass().isAssignableFrom(AbstractConfig.class)) {
|
||||
putBean(config);
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +76,7 @@ public final class ConfigEnv {
|
||||
* @return the config
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Config> T getConfig(Class<T> clazz) {
|
||||
public <T extends Config> T getConfig(final Class<T> clazz) {
|
||||
return (T) configBeans.get(clazz);
|
||||
}
|
||||
|
||||
@ -107,7 +85,7 @@ public final class ConfigEnv {
|
||||
*
|
||||
* @param parent parent.
|
||||
*/
|
||||
public void putBean(Config parent) {
|
||||
public void putBean(final Config parent) {
|
||||
if (parent != null && StringUtils.isNotBlank(parent.prefix())) {
|
||||
if (configBeans.containsKey(parent.getClass())) {
|
||||
return;
|
||||
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements.See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License.You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.config.api;
|
||||
|
||||
import java.util.List;
|
||||
import org.dromara.hmily.spi.ExtensionLoaderFactory;
|
||||
|
||||
/**
|
||||
* ConfigScan
|
||||
* Scan config information to add.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public final class ConfigScan {
|
||||
|
||||
public static void scan() {
|
||||
List<Config> configs = ExtensionLoaderFactory.loadAll(Config.class);
|
||||
for (Config conf : configs) {
|
||||
ConfigEnv.getInstance().registerConfig(conf);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* Contributor license agreements.See the NOTICE file distributed with
|
||||
* This work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* he License.You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.config.api.constant;
|
||||
|
||||
/**
|
||||
* The interface Config constants.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public interface PrefixConstants {
|
||||
|
||||
/**
|
||||
* The constant SERVER_PREFIX.
|
||||
*/
|
||||
String SERVER_PREFIX = "hmily.server";
|
||||
|
||||
/**
|
||||
* The constant CONFIG_PREFIX.
|
||||
*/
|
||||
String CONFIG_PREFIX = "hmily.config";
|
||||
|
||||
/**
|
||||
* The constant APOLLO_PREFIX.
|
||||
*/
|
||||
String APOLLO_PREFIX = "hmily.apollo";
|
||||
|
||||
/**
|
||||
* The constant NACOS_PREFIX.
|
||||
*/
|
||||
String NACOS_PREFIX = "hmily.nacos";
|
||||
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.config.api.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import org.dromara.hmily.config.api.AbstractConfig;
|
||||
import org.dromara.hmily.config.api.constant.PrefixConstants;
|
||||
import org.dromara.hmily.spi.HmilySPI;
|
||||
|
||||
/**
|
||||
* hmily config.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
@Data
|
||||
@HmilySPI("hmilyConfig")
|
||||
public class HmilyConfig extends AbstractConfig {
|
||||
|
||||
/**
|
||||
* Resource suffix this parameter please fill in about is the transaction store path.
|
||||
* If it's a table store this is a table suffix, it's stored the same way.
|
||||
* If this parameter is not filled in, the applicationName of the application is retrieved by default
|
||||
*/
|
||||
private String appName;
|
||||
|
||||
/**
|
||||
* log serializer.
|
||||
*/
|
||||
private String serializer = "kryo";
|
||||
|
||||
/**
|
||||
* contextTransmittalMode.
|
||||
*/
|
||||
private String contextTransmittalMode = "threadLocal";
|
||||
|
||||
/**
|
||||
* scheduledPool Thread size.
|
||||
*/
|
||||
private int scheduledThreadMax = Runtime.getRuntime().availableProcessors() << 1;
|
||||
|
||||
/**
|
||||
* scheduledPool scheduledDelay unit SECONDS.
|
||||
*/
|
||||
private int scheduledRecoveryDelay = 60;
|
||||
|
||||
/**
|
||||
* scheduled clean delay.
|
||||
*/
|
||||
private int scheduledCleanDelay = 60;
|
||||
|
||||
/**
|
||||
* scheduledPhyDeletedDelay.
|
||||
*/
|
||||
private int scheduledPhyDeletedDelay = 600;
|
||||
|
||||
/**
|
||||
* scheduledPool scheduledInitDelay unit SECONDS.
|
||||
*/
|
||||
private int scheduledInitDelay = 30;
|
||||
|
||||
/**
|
||||
* recoverDelayTime Unit seconds
|
||||
* (note that this time represents how many seconds after the local transaction was created before execution).
|
||||
*/
|
||||
private int recoverDelayTime = 60;
|
||||
|
||||
/**
|
||||
* cleanDelayTime Unit seconds
|
||||
* (note that this time represents how many seconds after the local transaction was created before execution).
|
||||
*/
|
||||
private int cleanDelayTime = 180;
|
||||
|
||||
/**
|
||||
* query by limit.
|
||||
*/
|
||||
private int limit = 100;
|
||||
|
||||
/**
|
||||
* retry max.
|
||||
*/
|
||||
private int retryMax = 10;
|
||||
|
||||
/**
|
||||
* disruptor bufferSize.
|
||||
*/
|
||||
private int bufferSize = 4096 * 2 * 2;
|
||||
|
||||
/**
|
||||
* this is disruptor consumerThreads.
|
||||
*/
|
||||
private int consumerThreads = Runtime.getRuntime().availableProcessors() << 1;
|
||||
|
||||
/**
|
||||
* asyncRepository.
|
||||
*/
|
||||
private boolean asyncRepository = true;
|
||||
|
||||
/**
|
||||
* autoSql.
|
||||
*/
|
||||
private boolean autoSql = true;
|
||||
|
||||
/**
|
||||
* phyDeleted is true means physically deleted is false means update status to death.
|
||||
*/
|
||||
private boolean phyDeleted = true;
|
||||
|
||||
/**
|
||||
* when phyDeleted is false , store days.
|
||||
*/
|
||||
private int storeDays = 3;
|
||||
|
||||
/**
|
||||
* repository.
|
||||
*/
|
||||
private String repository = "mysql";
|
||||
|
||||
@Override
|
||||
public String prefix() {
|
||||
return PrefixConstants.CONFIG_PREFIX;
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.config.api.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import org.dromara.hmily.config.api.AbstractConfig;
|
||||
import org.dromara.hmily.config.api.constant.PrefixConstants;
|
||||
import org.dromara.hmily.spi.HmilySPI;
|
||||
|
||||
/**
|
||||
* The type Hmily server.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
@Data
|
||||
@HmilySPI("hmilyServer")
|
||||
public class HmilyServer extends AbstractConfig {
|
||||
|
||||
private String appName;
|
||||
|
||||
private String configMode;
|
||||
|
||||
@Override
|
||||
public String prefix() {
|
||||
return PrefixConstants.SERVER_PREFIX;
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
org.dromara.hmily.config.api.entity.HmilyConfig
|
||||
org.dromara.hmily.config.api.entity.HmilyServer
|
@ -20,8 +20,8 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>hmily-config</artifactId>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>hmily-config</artifactId>
|
||||
<version>2.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@ -34,15 +34,15 @@
|
||||
<artifactId>hmily-config-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
<version>1.9.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>1.23</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
<version>1.9.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.config.loader;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dromara.hmily.config.api.ConfigScan;
|
||||
import org.dromara.hmily.spi.ExtensionLoaderFactory;
|
||||
|
||||
/**
|
||||
* The type Hmily config server.
|
||||
*/
|
||||
@Slf4j
|
||||
public class ConfigLoaderServer {
|
||||
|
||||
/**
|
||||
* Load config.
|
||||
*/
|
||||
public static void load() {
|
||||
// Start processing the associated parameters.
|
||||
ConfigScan.scan();
|
||||
ServerConfigLoader loader = new ServerConfigLoader();
|
||||
loader.load(ConfigLoader.Context::new, (context, config) -> {
|
||||
if (config != null) {
|
||||
if (StringUtils.isNotBlank(config.getConfigMode())) {
|
||||
String configMode = config.getConfigMode();
|
||||
ConfigLoader<?> configLoader = ExtensionLoaderFactory.load(ConfigLoader.class, configMode);
|
||||
log.info("Load the configuration【{}】information...", configMode);
|
||||
configLoader.load(context, (contextAfter, configAfter) -> {
|
||||
log.info("Configuration information: {}", configAfter);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements.See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License.You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.config.loader;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
import org.dromara.hmily.config.api.Config;
|
||||
import org.dromara.hmily.config.api.ConfigEnv;
|
||||
import org.dromara.hmily.config.loader.bind.BindData;
|
||||
import org.dromara.hmily.config.loader.bind.Binder;
|
||||
import org.dromara.hmily.config.loader.bind.DataType;
|
||||
import org.dromara.hmily.config.loader.property.ConfigPropertySource;
|
||||
import org.dromara.hmily.config.loader.property.DefaultConfigPropertySource;
|
||||
import org.dromara.hmily.config.loader.property.PropertyKeyParse;
|
||||
import org.dromara.hmily.config.loader.property.PropertyKeySource;
|
||||
|
||||
/**
|
||||
* The type Original config loader.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public class OriginalConfigLoader implements ConfigLoader<Config> {
|
||||
|
||||
@Override
|
||||
public void load(Supplier<Context> context, LoaderHandler<Config> handler) {
|
||||
for (PropertyKeySource<?> propertyKeySource : context.get().getSource()) {
|
||||
ConfigPropertySource configPropertySource = new DefaultConfigPropertySource<>(propertyKeySource, PropertyKeyParse.INSTANCE);
|
||||
ConfigEnv.getInstance().stream().map(e -> {
|
||||
Binder binder = Binder.of(configPropertySource);
|
||||
return binder.bind(e.prefix(), BindData.of(DataType.of(e.getClass()), () -> e));
|
||||
}).filter(Objects::nonNull).peek(Config::flagLoad).forEach(e -> handler.finish(context, e));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements.See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License.You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.config.loader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import org.dromara.hmily.common.utils.StringUtils;
|
||||
import org.dromara.hmily.config.api.entity.HmilyServer;
|
||||
import org.dromara.hmily.config.api.exception.ConfigException;
|
||||
import org.dromara.hmily.config.loader.property.PropertyKeySource;
|
||||
import org.dromara.hmily.config.loader.yaml.YamlPropertyLoader;
|
||||
|
||||
/**
|
||||
* ParentConfigLoader .
|
||||
* Read basic BaseConfig information processing.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public class ServerConfigLoader implements ConfigLoader<HmilyServer> {
|
||||
|
||||
private final YamlPropertyLoader propertyLoader = new YamlPropertyLoader();
|
||||
|
||||
@Override
|
||||
public void load(final Supplier<Context> context, final LoaderHandler<HmilyServer> handler) {
|
||||
String filePath = System.getProperty("hmily.conf");
|
||||
File configFile;
|
||||
if (StringUtils.isBlank(filePath)) {
|
||||
String dirPath = getDirGlobal();
|
||||
configFile = new File(dirPath);
|
||||
if (configFile.exists()) {
|
||||
filePath = dirPath;
|
||||
throw new ConfigException("ConfigLoader:loader config error,error file path:" + filePath);
|
||||
} else {
|
||||
//Mainly used for development environment。
|
||||
ClassLoader loader = ConfigLoader.class.getClassLoader();
|
||||
URL url = loader.getResource("hmily.yml");
|
||||
if (url != null) {
|
||||
filePath = url.getFile();
|
||||
configFile = new File(filePath);
|
||||
} else {
|
||||
throw new ConfigException("ConfigLoader:loader config error,error file path:" + filePath);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
configFile = new File(filePath);
|
||||
if (!configFile.exists()) {
|
||||
throw new ConfigException("ConfigLoader:loader config error,error file path:" + filePath);
|
||||
}
|
||||
}
|
||||
try (FileInputStream inputStream = new FileInputStream(configFile)) {
|
||||
List<PropertyKeySource<?>> propertyKeySources = propertyLoader.load(filePath, inputStream);
|
||||
OriginalConfigLoader original = new OriginalConfigLoader();
|
||||
againLoad(() -> context.get().with(propertyKeySources, original), handler, HmilyServer.class);
|
||||
} catch (IOException e) {
|
||||
throw new ConfigException("ConfigLoader:loader config error,file path:" + filePath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current project path.
|
||||
*
|
||||
* @return Current project path
|
||||
*/
|
||||
private String getDirGlobal() {
|
||||
String userDir = System.getProperty("user.dir");
|
||||
String fileName = "hmily.yml";
|
||||
return String.join(String.valueOf(File.separatorChar), userDir, fileName);
|
||||
}
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements.See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License.You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.config.loader.yaml;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.LoaderOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.BaseConstructor;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
import org.yaml.snakeyaml.nodes.MappingNode;
|
||||
import org.yaml.snakeyaml.nodes.Node;
|
||||
import org.yaml.snakeyaml.nodes.NodeTuple;
|
||||
import org.yaml.snakeyaml.nodes.ScalarNode;
|
||||
import org.yaml.snakeyaml.nodes.Tag;
|
||||
import org.yaml.snakeyaml.representer.Representer;
|
||||
import org.yaml.snakeyaml.resolver.Resolver;
|
||||
|
||||
/**
|
||||
* Class to load {@code .yml} files into a map of {@code String} to
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public class OriginTrackedYamlLoader extends YamlProcessor {
|
||||
|
||||
private final InputStream resource;
|
||||
|
||||
public OriginTrackedYamlLoader(final InputStream resource) {
|
||||
this.resource = resource;
|
||||
setResources(resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Yaml createYaml() {
|
||||
BaseConstructor constructor = new OriginTrackingConstructor();
|
||||
Representer representer = new Representer();
|
||||
DumperOptions dumperOptions = new DumperOptions();
|
||||
LimitedResolver resolver = new LimitedResolver();
|
||||
LoaderOptions loaderOptions = new LoaderOptions();
|
||||
loaderOptions.setAllowDuplicateKeys(false);
|
||||
return new Yaml(constructor, representer, dumperOptions, loaderOptions, resolver);
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> load() {
|
||||
final List<Map<String, Object>> result = new ArrayList<>();
|
||||
process((properties, map) -> result.add(getFlattenedMap(map)));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Constructor} that tracks property origins.
|
||||
*/
|
||||
private static class OriginTrackingConstructor extends Constructor {
|
||||
|
||||
@Override
|
||||
protected Object constructObject(final Node node) {
|
||||
if (node instanceof ScalarNode) {
|
||||
if (!(node instanceof KeyScalarNode)) {
|
||||
return constructTrackedObject(node, super.constructObject(node));
|
||||
}
|
||||
} else if (node instanceof MappingNode) {
|
||||
replaceMappingNodeKeys((MappingNode) node);
|
||||
}
|
||||
return super.constructObject(node);
|
||||
}
|
||||
|
||||
private void replaceMappingNodeKeys(final MappingNode node) {
|
||||
node.setValue(node.getValue().stream().map(KeyScalarNode::get).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private Object constructTrackedObject(final Node node, Object value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
private Object getValue(final Object value) {
|
||||
return (value != null ? value : "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ScalarNode} that replaces the key node in a {@link NodeTuple}.
|
||||
*/
|
||||
private static class KeyScalarNode extends ScalarNode {
|
||||
|
||||
public KeyScalarNode(final ScalarNode node) {
|
||||
super(node.getTag(), true, node.getValue(), node.getStartMark(), node.getEndMark(), node.getStyle());
|
||||
}
|
||||
|
||||
public static NodeTuple get(final NodeTuple nodeTuple) {
|
||||
Node keyNode = nodeTuple.getKeyNode();
|
||||
Node valueNode = nodeTuple.getValueNode();
|
||||
return new NodeTuple(KeyScalarNode.get(keyNode), valueNode);
|
||||
}
|
||||
|
||||
private static Node get(final Node node) {
|
||||
if (node instanceof ScalarNode) {
|
||||
return new KeyScalarNode((ScalarNode) node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Resolver} that limits {@link Tag#TIMESTAMP} tags.
|
||||
*/
|
||||
private static class LimitedResolver extends Resolver {
|
||||
|
||||
@Override
|
||||
public void addImplicitResolver(final Tag tag, final Pattern regexp, final String first) {
|
||||
if (tag == Tag.TIMESTAMP) {
|
||||
return;
|
||||
}
|
||||
super.addImplicitResolver(tag, regexp, first);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,380 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements.See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License.You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.config.loader.yaml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.yaml.snakeyaml.LoaderOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.reader.UnicodeReader;
|
||||
|
||||
/**
|
||||
* Base class for YAML factories.
|
||||
* <p>
|
||||
* Requires SnakeYAML 1.18 or higher, as of Spring Framework 5.0.6.
|
||||
* ref: org.springframework.beans.factory.config.YamlProcessor
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Juergen Hoeller
|
||||
* @author xiaoyu
|
||||
* @since 4.1
|
||||
*/
|
||||
public abstract class YamlProcessor {
|
||||
|
||||
private ResolutionMethod resolutionMethod = ResolutionMethod.OVERRIDE;
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(YamlProcessor.class);
|
||||
|
||||
private List<DocumentMatcher> documentMatchers = Collections.emptyList();
|
||||
|
||||
private boolean matchDefault = true;
|
||||
|
||||
private InputStream[] resources = new InputStream[0];
|
||||
|
||||
/**
|
||||
* A map of document matchers allowing callers to selectively use only
|
||||
* some of the documents in a YAML resource. In YAML documents are
|
||||
* separated by <code>---<code> lines, and each document is converted
|
||||
* to properties before the match is made. E.g.
|
||||
* <pre class="code">
|
||||
* environment: dev
|
||||
* url: http://dev.bar.com
|
||||
* name: Developer Setup
|
||||
* ---
|
||||
* environment: prod
|
||||
* url:http://foo.bar.com
|
||||
* name: My Cool App
|
||||
* </pre>
|
||||
* when mapped with
|
||||
* <pre class="code">
|
||||
* setDocumentMatchers(properties ->
|
||||
* ("prod".equals(properties.getProperty("environment")) ? MatchStatus.FOUND : MatchStatus.NOT_FOUND));
|
||||
* </pre>
|
||||
* would end up as
|
||||
* <pre class="code">
|
||||
* environment=prod
|
||||
* url=http://foo.bar.com
|
||||
* name=My Cool App
|
||||
* </pre>
|
||||
*/
|
||||
public void setDocumentMatchers(final DocumentMatcher... matchers) {
|
||||
this.documentMatchers = Arrays.asList(matchers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag indicating that a document for which all the
|
||||
* {@link #setDocumentMatchers(DocumentMatcher...) document matchers} abstain will
|
||||
* nevertheless match. Default is {@code true}.
|
||||
*/
|
||||
public void setMatchDefault(final boolean matchDefault) {
|
||||
this.matchDefault = matchDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to use for resolving resources. Each resource will be converted to a Map,
|
||||
* so this property is used to decide which map entries to keep in the final output
|
||||
* from this factory. Default is {@link ResolutionMethod#OVERRIDE}.
|
||||
*/
|
||||
public void setResolutionMethod(final ResolutionMethod resolutionMethod) {
|
||||
this.resolutionMethod = resolutionMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set locations of YAML {@link InputStream resources} to be loaded.
|
||||
*
|
||||
* @see ResolutionMethod
|
||||
*/
|
||||
public void setResources(final InputStream... resources) {
|
||||
this.resources = resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide an opportunity for subclasses to process the Yaml parsed from the supplied
|
||||
* resources. Each resource is parsed in turn and the documents inside checked against
|
||||
* the {@link #setDocumentMatchers(DocumentMatcher...) matchers}. If a document
|
||||
* matches it is passed into the callback, along with its representation as Properties.
|
||||
* Depending on the {@link #setResolutionMethod(ResolutionMethod)} not all of the
|
||||
* documents will be parsed.
|
||||
*
|
||||
* @param callback a callback to delegate to once matching documents are found
|
||||
* @see #createYaml()
|
||||
*/
|
||||
protected void process(final MatchCallback callback) {
|
||||
Yaml yaml = createYaml();
|
||||
for (InputStream resource : this.resources) {
|
||||
boolean found = process(callback, yaml, resource);
|
||||
if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND && found) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the {@link Yaml} instance to use.
|
||||
* <p>The default implementation sets the "allowDuplicateKeys" flag to {@code false},
|
||||
* enabling built-in duplicate key handling in SnakeYAML 1.18+.
|
||||
*
|
||||
* @see LoaderOptions#setAllowDuplicateKeys(boolean)
|
||||
*/
|
||||
protected Yaml createYaml() {
|
||||
LoaderOptions options = new LoaderOptions();
|
||||
options.setAllowDuplicateKeys(false);
|
||||
return new Yaml(options);
|
||||
}
|
||||
|
||||
private boolean process(final MatchCallback callback, final Yaml yaml, final InputStream resource) {
|
||||
int count = 0;
|
||||
try {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loading from YAML: " + resource);
|
||||
}
|
||||
try (Reader reader = new UnicodeReader(resource)) {
|
||||
for (Object object : yaml.loadAll(reader)) {
|
||||
if (object != null && process(asMap(object), callback)) {
|
||||
count++;
|
||||
if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loaded " + count + " document" + (count > 1 ? "s" : "") +
|
||||
" from YAML resource: " + resource);
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
handleProcessError(resource, ex);
|
||||
}
|
||||
return (count > 0);
|
||||
}
|
||||
|
||||
private void handleProcessError(final InputStream resource, final IOException ex) {
|
||||
if (this.resolutionMethod != ResolutionMethod.FIRST_FOUND &&
|
||||
this.resolutionMethod != ResolutionMethod.OVERRIDE_AND_IGNORE) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Could not load map from " + resource + ": " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Object> asMap(final Object object) {
|
||||
// YAML can have numbers as keys
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
if (!(object instanceof Map)) {
|
||||
// A document can be a text literal
|
||||
result.put("document", object);
|
||||
return result;
|
||||
}
|
||||
|
||||
Map<Object, Object> map = (Map<Object, Object>) object;
|
||||
map.forEach((key, value) -> {
|
||||
if (value instanceof Map) {
|
||||
value = asMap(value);
|
||||
}
|
||||
if (key instanceof CharSequence) {
|
||||
result.put(key.toString(), value);
|
||||
} else {
|
||||
// It has to be a map key in this case
|
||||
result.put("[" + key.toString() + "]", value);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean process(final Map<String, Object> map, final MatchCallback callback) {
|
||||
Properties properties = new Properties();
|
||||
properties.putAll(getFlattenedMap(map));
|
||||
if (this.documentMatchers.isEmpty()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Merging document (no matchers set): " + map);
|
||||
}
|
||||
callback.process(properties, map);
|
||||
return true;
|
||||
}
|
||||
MatchStatus result = MatchStatus.ABSTAIN;
|
||||
for (DocumentMatcher matcher : this.documentMatchers) {
|
||||
MatchStatus match = matcher.matches(properties);
|
||||
result = MatchStatus.getMostSpecific(match, result);
|
||||
if (match == MatchStatus.FOUND) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Matched document with document matcher: " + properties);
|
||||
}
|
||||
callback.process(properties, map);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == MatchStatus.ABSTAIN && this.matchDefault) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Matched document with default matcher: " + map);
|
||||
}
|
||||
callback.process(properties, map);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Unmatched document: " + map);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a flattened version of the given map, recursively following any nested Map
|
||||
* or Collection values. Entries from the resulting map retain the same order as the
|
||||
* source. When called with the Map from a {@link MatchCallback} the result will
|
||||
* contain the same values as the {@link MatchCallback} Properties.
|
||||
*
|
||||
* @param source the source map
|
||||
* @return a flattened map
|
||||
* @since 4.1.3
|
||||
*/
|
||||
protected final Map<String, Object> getFlattenedMap(final Map<String, Object> source) {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
buildFlattenedMap(result, source, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void buildFlattenedMap(final Map<String, Object> result, final Map<String, Object> source, final String path) {
|
||||
source.forEach((key, value) -> {
|
||||
if (StringUtils.isNotBlank(path)) {
|
||||
if (key.startsWith("[")) {
|
||||
key = path + key;
|
||||
} else {
|
||||
key = path + '.' + key;
|
||||
}
|
||||
}
|
||||
if (value instanceof String) {
|
||||
result.put(key, value);
|
||||
} else if (value instanceof Map) {
|
||||
// Need a compound key
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) value;
|
||||
buildFlattenedMap(result, map, key);
|
||||
} else if (value instanceof Collection) {
|
||||
// Need a compound key
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Object> collection = (Collection<Object>) value;
|
||||
if (collection.isEmpty()) {
|
||||
result.put(key, "");
|
||||
} else {
|
||||
int count = 0;
|
||||
for (Object object : collection) {
|
||||
buildFlattenedMap(result, Collections.singletonMap(
|
||||
"[" + (count++) + "]", object), key);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result.put(key, (value != null ? value : ""));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback interface used to process the YAML parsing results.
|
||||
*/
|
||||
public interface MatchCallback {
|
||||
|
||||
/**
|
||||
* Process the given representation of the parsing results.
|
||||
*
|
||||
* @param properties the properties to process (as a flattened
|
||||
* representation with indexed keys in case of a collection or map)
|
||||
* @param map the result map (preserving the original value structure
|
||||
* in the YAML document)
|
||||
*/
|
||||
void process(Properties properties, Map<String, Object> map);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Strategy interface used to test if properties match.
|
||||
*/
|
||||
public interface DocumentMatcher {
|
||||
|
||||
/**
|
||||
* Test if the given properties match.
|
||||
*
|
||||
* @param properties the properties to test
|
||||
* @return the status of the match
|
||||
*/
|
||||
MatchStatus matches(Properties properties);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Status returned from {@link DocumentMatcher#matches(Properties)}
|
||||
*/
|
||||
public enum MatchStatus {
|
||||
|
||||
/**
|
||||
* A match was found.
|
||||
*/
|
||||
FOUND,
|
||||
|
||||
/**
|
||||
* The matcher should not be considered.
|
||||
*/
|
||||
ABSTAIN;
|
||||
|
||||
/**
|
||||
* Compare two {@link MatchStatus} items, returning the most specific status.
|
||||
*/
|
||||
public static MatchStatus getMostSpecific(MatchStatus a, MatchStatus b) {
|
||||
return (a.ordinal() < b.ordinal() ? a : b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method to use for resolving resources.
|
||||
*/
|
||||
public enum ResolutionMethod {
|
||||
|
||||
/**
|
||||
* Replace values from earlier in the list.
|
||||
*/
|
||||
OVERRIDE,
|
||||
|
||||
/**
|
||||
* Replace values from earlier in the list, ignoring any failures.
|
||||
*/
|
||||
OVERRIDE_AND_IGNORE,
|
||||
|
||||
/**
|
||||
* Take the first resource in the list that exists and use just that.
|
||||
*/
|
||||
FIRST_FOUND
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements.See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License.You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.config.loader.yaml;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.dromara.hmily.config.loader.PropertyLoader;
|
||||
import org.dromara.hmily.config.loader.property.MapPropertyKeySource;
|
||||
import org.dromara.hmily.config.loader.property.PropertyKeySource;
|
||||
|
||||
/**
|
||||
* The type Yaml property loader.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public class YamlPropertyLoader implements PropertyLoader {
|
||||
|
||||
@Override
|
||||
public boolean checkFile(final String fileName) {
|
||||
String fileExtName = fileName.substring(fileName.lastIndexOf("."));
|
||||
String extName = ".yml";
|
||||
return extName.equals(fileExtName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PropertyKeySource<?>> load(final String name, final InputStream resource) {
|
||||
if (!checkFile(name)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<Map<String, Object>> loaded = new OriginTrackedYamlLoader(resource).load();
|
||||
if (loaded.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<PropertyKeySource<?>> propertySources = new ArrayList<>(loaded.size());
|
||||
for (int i = 0; i < loaded.size(); i++) {
|
||||
propertySources.add(new MapPropertyKeySource(name + (loaded.size() != 1 ? " (document #" + i + ")" : ""), loaded.get(i)));
|
||||
}
|
||||
return propertySources;
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements.See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License.You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.config.loader.bind;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
import org.dromara.hmily.config.loader.property.ConfigPropertySource;
|
||||
import org.dromara.hmily.config.loader.property.DefaultConfigPropertySource;
|
||||
import org.dromara.hmily.config.loader.property.MapPropertyKeySource;
|
||||
import org.dromara.hmily.config.loader.property.PropertyKeyParse;
|
||||
import org.dromara.hmily.config.loader.property.PropertyKeySource;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public final class CollectionBinderTest {
|
||||
|
||||
@Test
|
||||
public void testArrayList() {
|
||||
String name = "hmily.yml";
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("hmily.list[0]", 123);
|
||||
map.put("hmily.list[1]", 234);
|
||||
PropertyKeySource<?> propertySource = new MapPropertyKeySource(name, map);
|
||||
ConfigPropertySource configPropertySource = new DefaultConfigPropertySource<>(propertySource, PropertyKeyParse.INSTANCE);
|
||||
Binder binder = Binder.of(configPropertySource);
|
||||
BindData<CollectionPojo> data = BindData.of(DataType.of(CollectionPojo.class), CollectionPojo::new);
|
||||
CollectionPojo bind = binder.bind("hmily", data);
|
||||
Assert.assertEquals(bind.getList().get(0), 123);
|
||||
Assert.assertEquals(bind.getList().get(1), 234);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotSetArrayList() {
|
||||
String name = "hmily.yml";
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("hmily.list[0]", 123);
|
||||
map.put("hmily.list[1]", 234);
|
||||
PropertyKeySource<?> propertySource = new MapPropertyKeySource(name, map);
|
||||
ConfigPropertySource configPropertySource = new DefaultConfigPropertySource<>(propertySource, PropertyKeyParse.INSTANCE);
|
||||
Binder binder = Binder.of(configPropertySource);
|
||||
BindData<CollectionPojo2> data = BindData.of(DataType.of(CollectionPojo2.class), CollectionPojo2::new);
|
||||
CollectionPojo2 bind = binder.bind("hmily", data);
|
||||
Assert.assertNull(bind);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListGeneric() {
|
||||
String name = "hmily.yml";
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("hmily.list2[0]", "123");
|
||||
map.put("hmily.list2[1]", 234);
|
||||
PropertyKeySource<?> propertySource = new MapPropertyKeySource(name, map);
|
||||
ConfigPropertySource configPropertySource = new DefaultConfigPropertySource<>(propertySource, PropertyKeyParse.INSTANCE);
|
||||
Binder binder = Binder.of(configPropertySource);
|
||||
BindData<CollectionPojo> data = BindData.of(DataType.of(CollectionPojo.class), CollectionPojo::new);
|
||||
CollectionPojo bind = binder.bind("hmily", data);
|
||||
Assert.assertEquals(bind.getList2().get(0), Integer.valueOf(123));
|
||||
Assert.assertEquals(bind.getList2().get(1), Integer.valueOf(234));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArray() {
|
||||
String name = "hmily.yml";
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("hmily.intArray[0]", 123);
|
||||
map.put("hmily.intArray[1]", 234);
|
||||
PropertyKeySource<?> propertySource = new MapPropertyKeySource(name, map);
|
||||
ConfigPropertySource configPropertySource = new DefaultConfigPropertySource<>(propertySource, PropertyKeyParse.INSTANCE);
|
||||
Binder binder = Binder.of(configPropertySource);
|
||||
BindData<CollectionPojo> data = BindData.of(DataType.of(CollectionPojo.class), CollectionPojo::new);
|
||||
CollectionPojo bind = binder.bind("hmily", data);
|
||||
Assert.assertEquals(bind.getIntArray()[0], Integer.valueOf(123));
|
||||
Assert.assertEquals(bind.getIntArray()[1], Integer.valueOf(234));
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
public static class CollectionPojo {
|
||||
|
||||
private List list;
|
||||
|
||||
private List<Integer> list2;
|
||||
|
||||
private Integer[] intArray;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class CollectionPojo2 {
|
||||
|
||||
private List list;
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements.See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License.You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.config.loader.bind;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
import org.dromara.hmily.config.loader.property.ConfigPropertySource;
|
||||
import org.dromara.hmily.config.loader.property.DefaultConfigPropertySource;
|
||||
import org.dromara.hmily.config.loader.property.MapPropertyKeySource;
|
||||
import org.dromara.hmily.config.loader.property.PropertyKeyParse;
|
||||
import org.dromara.hmily.config.loader.property.PropertyKeySource;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
@Data
|
||||
public class JavaBeanBinderTest {
|
||||
|
||||
private String stringTest;
|
||||
|
||||
private Integer integerTest;
|
||||
|
||||
private Double doubleTest;
|
||||
|
||||
private Long longTest;
|
||||
|
||||
private Character chartTest;
|
||||
|
||||
private Float floatTest;
|
||||
|
||||
private Boolean boolTest;
|
||||
|
||||
@Test
|
||||
public void testJavaBeanBind() {
|
||||
String name = "hmily.yml";
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("hmily.stringTest", "123");
|
||||
map.put("hmily.integerTest", 456);
|
||||
map.put("hmily.doubleTest", 42.12);
|
||||
map.put("hmily.longTest", 100L);
|
||||
map.put("hmily.chartTest", 'a');
|
||||
map.put("hmily.floatTest", 12.1F);
|
||||
map.put("hmily.boolTest", true);
|
||||
PropertyKeySource<?> propertySource = new MapPropertyKeySource(name, map);
|
||||
ConfigPropertySource configPropertySource = new DefaultConfigPropertySource<>(propertySource, PropertyKeyParse.INSTANCE);
|
||||
Binder binder = Binder.of(configPropertySource);
|
||||
BindData<JavaBeanBinderTest> data = BindData.of(DataType.of(JavaBeanBinderTest.class), JavaBeanBinderTest::new);
|
||||
JavaBeanBinderTest bind = binder.bind("hmily", data);
|
||||
Assert.assertEquals(map.get("hmily.stringTest"), bind.getStringTest());
|
||||
Assert.assertEquals(map.get("hmily.integerTest"), bind.getIntegerTest());
|
||||
Assert.assertEquals(map.get("hmily.doubleTest"), bind.getDoubleTest());
|
||||
Assert.assertEquals(map.get("hmily.chartTest"), bind.getChartTest());
|
||||
Assert.assertEquals(map.get("hmily.longTest"), bind.getLongTest());
|
||||
Assert.assertEquals(map.get("hmily.floatTest"), bind.getFloatTest());
|
||||
Assert.assertEquals(map.get("hmily.boolTest"), bind.getBoolTest());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJavaBeanBindParse() {
|
||||
String name = "hmily.yml";
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("hmily.stringTest", 123);
|
||||
map.put("hmily.integerTest", "123");
|
||||
map.put("hmily.doubleTest", "123");
|
||||
map.put("hmily.longTest", "123");
|
||||
map.put("hmily.chartTest", "A");
|
||||
map.put("hmily.floatTest", "123");
|
||||
map.put("hmily.boolTest", "true");
|
||||
PropertyKeySource<?> propertySource = new MapPropertyKeySource(name, map);
|
||||
ConfigPropertySource configPropertySource = new DefaultConfigPropertySource<>(propertySource, PropertyKeyParse.INSTANCE);
|
||||
Binder binder = Binder.of(configPropertySource);
|
||||
BindData<JavaBeanBinderTest> data = BindData.of(DataType.of(JavaBeanBinderTest.class), JavaBeanBinderTest::new);
|
||||
JavaBeanBinderTest bind = binder.bind("hmily", data);
|
||||
Assert.assertEquals("123", bind.getStringTest());
|
||||
Assert.assertEquals(Integer.valueOf(123), bind.getIntegerTest());
|
||||
Assert.assertEquals(Double.valueOf(123), bind.getDoubleTest());
|
||||
Assert.assertEquals(Character.valueOf('A'), bind.getChartTest());
|
||||
Assert.assertEquals(Long.valueOf(123), bind.getLongTest());
|
||||
Assert.assertEquals(Float.valueOf(123), bind.getFloatTest());
|
||||
Assert.assertEquals(Boolean.TRUE, bind.getBoolTest());
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements.See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License.You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.config.loader.bind;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
import org.dromara.hmily.config.loader.property.ConfigPropertySource;
|
||||
import org.dromara.hmily.config.loader.property.DefaultConfigPropertySource;
|
||||
import org.dromara.hmily.config.loader.property.MapPropertyKeySource;
|
||||
import org.dromara.hmily.config.loader.property.PropertyKeyParse;
|
||||
import org.dromara.hmily.config.loader.property.PropertyKeySource;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class MapBinderTest {
|
||||
|
||||
@Test
|
||||
public void testMap() {
|
||||
String name = "hmily.yml";
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("hmily.map.userName", "sixh");
|
||||
map.put("hmily.map.passWord", 123456);
|
||||
PropertyKeySource<?> propertySource = new MapPropertyKeySource(name, map);
|
||||
ConfigPropertySource configPropertySource = new DefaultConfigPropertySource<>(propertySource, PropertyKeyParse.INSTANCE);
|
||||
Binder binder = Binder.of(configPropertySource);
|
||||
BindData<MapPojo> data = BindData.of(DataType.of(MapPojo.class), MapPojo::new);
|
||||
MapPojo bind = binder.bind("hmily", data);
|
||||
Assert.assertEquals(bind.getMap().get("userName"), map.get("hmily.map.userName"));
|
||||
Assert.assertEquals(bind.getMap().get("passWord"), map.get("hmily.map.passWord"));
|
||||
System.out.println(bind);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapGeneric() {
|
||||
String name = "hmily.yml";
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("hmily.map2.userName", "456");
|
||||
map.put("hmily.map2.passWord", 123456);
|
||||
PropertyKeySource<?> propertySource = new MapPropertyKeySource(name, map);
|
||||
ConfigPropertySource configPropertySource = new DefaultConfigPropertySource<>(propertySource, PropertyKeyParse.INSTANCE);
|
||||
Binder binder = Binder.of(configPropertySource);
|
||||
BindData<MapPojo> data = BindData.of(DataType.of(MapPojo.class), MapPojo::new);
|
||||
MapPojo bind = binder.bind("hmily", data);
|
||||
Assert.assertEquals(bind.getMap2().get("userName"), Integer.valueOf(456));
|
||||
Assert.assertEquals(bind.getMap2().get("passWord"), map.get("hmily.map2.passWord"));
|
||||
System.out.println(bind);
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class MapPojo {
|
||||
|
||||
private Map map;
|
||||
|
||||
private Map<String,Integer> map2;
|
||||
}
|
||||
}
|
@ -20,13 +20,20 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>hmily-config</artifactId>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>hmily-config</artifactId>
|
||||
<version>2.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>hmily-config-local</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>hmily-config-loader</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements.See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License.You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.config.local;
|
||||
|
||||
|
||||
import java.util.function.Supplier;
|
||||
import org.dromara.hmily.config.api.Config;
|
||||
import org.dromara.hmily.config.loader.ConfigLoader;
|
||||
import org.dromara.hmily.spi.HmilySPI;
|
||||
|
||||
/**
|
||||
* LocalConfigLoader .
|
||||
* Loading local yml file processing.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
@HmilySPI("local")
|
||||
public class LocalConfigLoader implements ConfigLoader<Config> {
|
||||
|
||||
@Override
|
||||
public void load(final Supplier<Context> context, final LoaderHandler<Config> handler) {
|
||||
ConfigLoader<Config> original = context.get().getOriginal();
|
||||
original.load(context, handler);
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
org.dromara.hmily.config.local.LocalConfigLoader
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements.See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License.You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.config.local;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dromara.hmily.config.api.ConfigEnv;
|
||||
import org.dromara.hmily.config.api.ConfigScan;
|
||||
import org.dromara.hmily.config.api.entity.HmilyConfig;
|
||||
import org.dromara.hmily.config.api.entity.HmilyServer;
|
||||
import org.dromara.hmily.config.loader.ConfigLoader;
|
||||
import org.dromara.hmily.config.loader.ServerConfigLoader;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Created by apa7 on 2019/10/10.
|
||||
*/
|
||||
public final class LocalConfigLoaderTest {
|
||||
|
||||
@Test
|
||||
public void load() {
|
||||
ConfigScan.scan();
|
||||
ServerConfigLoader loader = new ServerConfigLoader();
|
||||
loader.load(ConfigLoader.Context::new, (context, config) -> {
|
||||
System.out.println("config:---->" + config);
|
||||
if (config != null) {
|
||||
if (StringUtils.isNotBlank(config.getConfigMode())) {
|
||||
String configMode = config.getConfigMode();
|
||||
if (configMode.equals("local")) {
|
||||
new LocalConfigLoader().load(context, (context1, config1) -> System.out.println("config1:-->" + config1));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
HmilyServer server = ConfigEnv.getInstance().getConfig(HmilyServer.class);
|
||||
HmilyConfig config = ConfigEnv.getInstance().getConfig(HmilyConfig.class);
|
||||
System.out.println(server);
|
||||
System.out.println(config);
|
||||
}
|
||||
|
||||
}
|
11
hmily-config/hmily-config-local/src/test/resources/hmily.yml
Normal file
11
hmily-config/hmily-config-local/src/test/resources/hmily.yml
Normal file
@ -0,0 +1,11 @@
|
||||
hmily:
|
||||
server:
|
||||
configMode: local
|
||||
appName: xiaoyu
|
||||
# 如果server.mode eq local 的时候才会读取到这里的配置信息.
|
||||
config:
|
||||
serializer: kryo
|
||||
contextTransmittalMode: threadLocal
|
||||
scheduledRecoveryDelay: 120
|
||||
limit : 200
|
||||
|
@ -29,7 +29,7 @@ public final class TransactionTotalCounterMetricsTracker implements CounterMetri
|
||||
private static final Counter TRANSACTION_TOTAL = Counter.build()
|
||||
.name("transaction_total")
|
||||
.labelNames("type")
|
||||
.help("soul request total count")
|
||||
.help("hmily request total count")
|
||||
.register();
|
||||
|
||||
@Override
|
||||
|
18
pom.xml
18
pom.xml
@ -622,6 +622,24 @@
|
||||
</instrumentation>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce</id>
|
||||
<configuration>
|
||||
<rules>
|
||||
<DependencyConvergence />
|
||||
</rules>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- <plugin>-->
|
||||
<!-- <groupId>org.apache.maven.plugins</groupId>-->
|
||||
<!-- <artifactId>maven-checkstyle-plugin</artifactId>-->
|
||||
|
Loading…
Reference in New Issue
Block a user