springboot 自定义属性文件加载(ConfigDataLocationResolver)

springboot 自定义属性文件加载

                            

                                                

*********************

相关类与接口

                

ConfigDataLocationResolver

public interface ConfigDataLocationResolver<R extends ConfigDataResource> {
    boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location);

    List<R> resolve(ConfigDataLocationResolverContext context, ConfigDataLocation location) throws ConfigDataLocationNotFoundException, ConfigDataResourceNotFoundException;

    default List<R> resolveProfileSpecific(ConfigDataLocationResolverContext context, ConfigDataLocation location, Profiles profiles) throws ConfigDataLocationNotFoundException {
        return Collections.emptyList();
    }
}

                     

ConfigTreeConfigDataLocationResolver

public class ConfigTreeConfigDataLocationResolver implements ConfigDataLocationResolver<ConfigTreeConfigDataResource> {
    private static final String PREFIX = "configtree:";
    private final LocationResourceLoader resourceLoader;

    public ConfigTreeConfigDataLocationResolver(ResourceLoader resourceLoader) {
        this.resourceLoader = new LocationResourceLoader(resourceLoader);
    }

    public boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) {
        return location.hasPrefix("configtree:");
    }

    public List<ConfigTreeConfigDataResource> resolve(ConfigDataLocationResolverContext context, ConfigDataLocation location) {
        try {
            return this.resolve(location.getNonPrefixedValue("configtree:"));
        } catch (IOException var4) {
            throw new ConfigDataLocationNotFoundException(location, var4);
        }
    }

    private List<ConfigTreeConfigDataResource> resolve(String location) throws IOException {
        Assert.isTrue(location.endsWith("/"), () -> {
            return String.format("Config tree location '%s' must end with '/'", location);
        });
        if (!this.resourceLoader.isPattern(location)) {
            return Collections.singletonList(new ConfigTreeConfigDataResource(location));
        } else {
            Resource[] resources = this.resourceLoader.getResources(location, ResourceType.DIRECTORY);
            List<ConfigTreeConfigDataResource> resolved = new ArrayList(resources.length);
            Resource[] var4 = resources;
            int var5 = resources.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                Resource resource = var4[var6];
                resolved.add(new ConfigTreeConfigDataResource(resource.getFile().toPath()));
            }

            return resolved;
        }
    }
}

                         

ConfigDataLocation

public final class ConfigDataLocation implements OriginProvider {
    public static final String OPTIONAL_PREFIX = "optional:";
    private final boolean optional;
    private final String value;
    private final Origin origin;

    private ConfigDataLocation(boolean optional, String value, Origin origin) {
        this.value = value;
        this.optional = optional;
        this.origin = origin;
    }

    public boolean isOptional() {
    public Origin getOrigin() {
    public String getValue() {
    public boolean hasPrefix(String prefix) {

    public String getNonPrefixedValue(String prefix) {
        return this.hasPrefix(prefix) ? this.value.substring(prefix.length()) : this.value;
    }

    public ConfigDataLocation[] split() {
        return this.split(";");
    }

    public ConfigDataLocation[] split(String delimiter) {
        String[] values = StringUtils.delimitedListToStringArray(this.toString(), delimiter);
        ConfigDataLocation[] result = new ConfigDataLocation[values.length];

        for(int i = 0; i < values.length; ++i) {
            result[i] = of(values[i]).withOrigin(this.getOrigin());
        }

        return result;
    }

    public boolean equals(Object obj) {
    public int hashCode() {
    public String toString() {

    ConfigDataLocation withOrigin(Origin origin) {
        return new ConfigDataLocation(this.optional, this.value, origin);
    }

    public static ConfigDataLocation of(String location) {
        boolean optional = location != null && location.startsWith("optional:");
        String value = !optional ? location : location.substring("optional:".length());
        return !StringUtils.hasText(value) ? null : new ConfigDataLocation(optional, value, (Origin)null);
    }
}

                          

                             

ConfigDataResource

public abstract class ConfigDataResource {
    private final boolean optional;

    public ConfigDataResource() {
        this(false);
    }

    protected ConfigDataResource(boolean optional) {
        this.optional = optional;
    }

    boolean isOptional() {
        return this.optional;
    }
}

                            

ConfigTreeConfigDataResource

public class ConfigTreeConfigDataResource extends ConfigDataResource {
    private final Path path;

    ConfigTreeConfigDataResource(String path) {
        Assert.notNull(path, "Path must not be null");
        this.path = Paths.get(path).toAbsolutePath();
    }

    ConfigTreeConfigDataResource(Path path) {
        Assert.notNull(path, "Path must not be null");
        this.path = path.toAbsolutePath();
    }

    Path getPath() {

    public boolean equals(Object obj) {
    public int hashCode() {
    public String toString() {

                                   

                                   

ConfigDataLoader

public interface ConfigDataLoader<R extends ConfigDataResource> {
    default boolean isLoadable(ConfigDataLoaderContext context, R resource) {
        return true;
    }

    ConfigData load(ConfigDataLoaderContext context, R resource) throws IOException, ConfigDataResourceNotFoundException;
}

                                 

ConfigTreeConfigDataLoader

public class ConfigTreeConfigDataLoader implements ConfigDataLoader<ConfigTreeConfigDataResource> {
    public ConfigTreeConfigDataLoader() {
    }

    public ConfigData load(ConfigDataLoaderContext context, ConfigTreeConfigDataResource resource) throws IOException, ConfigDataResourceNotFoundException {
        Path path = resource.getPath();
        ConfigDataResourceNotFoundException.throwIfDoesNotExist(resource, path);
        String name = "Config tree '" + path + "'";
        ConfigTreePropertySource source = new ConfigTreePropertySource(name, path, new Option[]{Option.AUTO_TRIM_TRAILING_NEW_LINE});
        return new ConfigData(Collections.singletonList(source), new org.springframework.boot.context.config.ConfigData.Option[0]);
    }
}

                        

ConfigData

public final class ConfigData {
    private final List<PropertySource<?>> propertySources;
    private final ConfigData.PropertySourceOptions propertySourceOptions;
    public static final ConfigData EMPTY = new ConfigData(Collections.emptySet(), new ConfigData.Option[0]);

    public ConfigData(Collection<? extends PropertySource<?>> propertySources, ConfigData.Option... options) {
    public ConfigData(Collection<? extends PropertySource<?>> propertySources, ConfigData.PropertySourceOptions propertySourceOptions) {

    public List<PropertySource<?>> getPropertySources() {
    public ConfigData.Options getOptions(PropertySource<?> propertySource) {


************
内部枚举:Option

    public static enum Option {
        IGNORE_IMPORTS,
        IGNORE_PROFILES,
        PROFILE_SPECIFIC;

        private Option() {
        }
    }


************
内部类:Options

    public static final class Options {
        public static final ConfigData.Options NONE = new ConfigData.Options(Collections.emptySet());
        private final Set<ConfigData.Option> options;

        private Options(Set<ConfigData.Option> options) {

        Set<ConfigData.Option> asSet() {
        public boolean contains(ConfigData.Option option) {

        public boolean equals(Object obj) {
        public int hashCode() {
        public String toString() {

        public ConfigData.Options without(ConfigData.Option option) {
            return this.copy((options) -> {
                options.remove(option);
            });
        }

        public ConfigData.Options with(ConfigData.Option option) {
            return this.copy((options) -> {
                options.add(option);
            });
        }

        private ConfigData.Options copy(Consumer<EnumSet<ConfigData.Option>> processor) {
            EnumSet<ConfigData.Option> options = EnumSet.noneOf(ConfigData.Option.class);
            options.addAll(this.options);
            processor.accept(options);
            return new ConfigData.Options(options);
        }

        public static ConfigData.Options of(ConfigData.Option... options) {
            Assert.notNull(options, "Options must not be null");
            return options.length == 0 ? NONE : new ConfigData.Options(EnumSet.copyOf(Arrays.asList(options)));
        }
    }


************
内部类:AlwaysPropertySourceOptions

    private static class AlwaysPropertySourceOptions implements ConfigData.PropertySourceOptions {
        private final ConfigData.Options options;

        AlwaysPropertySourceOptions(ConfigData.Options options) {
        public ConfigData.Options get(PropertySource<?> propertySource) {


************
内部类:PropertySourceOptions

    @FunctionalInterface
    public interface PropertySourceOptions {
        ConfigData.PropertySourceOptions ALWAYS_NONE = new ConfigData.AlwaysPropertySourceOptions(ConfigData.Options.NONE);

        ConfigData.Options get(PropertySource<?> propertySource);

        static ConfigData.PropertySourceOptions always(ConfigData.Option... options) {
        static ConfigData.PropertySourceOptions always(ConfigData.Options options) {

                             

                                              

*********************

示例:从redis加载配置信息

                      

redis 使用hash结构存储配置数据

hash key:redis-config

hash value
person.name ==> gtlx
person.value ==> 20

                              

*************

配置文件

                    

application.yml

spring:
  redis:
    host: 192.168.57.120
    port: 6379
  config:
    import: optional:redis://${spring.redis.host}:${spring.redis.port}/redis-config

                               

*************

pojo 层

                    

Person

@Data
@Component
@ConfigurationProperties("person")
public class Person {
    
    private String name;
    private Integer age;
}

                             

*************

config 层

                   

RedisConfigDataResource

@Getter
@EqualsAndHashCode(callSuper = true)
public class RedisConfigDataResource extends ConfigDataResource {

    private final String host;
    private final String port;
    private final String configKey;

    public RedisConfigDataResource(String host, String port, String configkey){
        this.host=host;
        this.port=port;
        this.configKey=configkey;
    }
}

                            

RedisConfigDataLocationResolver

public class RedisConfigDataLocationResolver implements ConfigDataLocationResolver<RedisConfigDataResource> {

    public final String prefix="redis://";

    @Override
    public boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) {
        return location.hasPrefix(prefix);
    }

    @Override
    public List<RedisConfigDataResource> resolve(ConfigDataLocationResolverContext context, ConfigDataLocation location) throws ConfigDataLocationNotFoundException, ConfigDataResourceNotFoundException {
        List<RedisConfigDataResource> resources=new ArrayList<>();
        String value= location.getNonPrefixedValue(prefix);
        String[] s=value.split("/");

        String[] s2=s[0].split(":");
        String host=s2[0];
        String port=s2[1];

        String[] keys=s[1].split(",");
        for (String key : keys){
            resources.add(new RedisConfigDataResource(host,port,key));
        }

        return resources;
    }
}

                     

RedisConfigDataLoader

public class RedisConfigDataLoader implements ConfigDataLoader<RedisConfigDataResource> {

    @Override
    public ConfigData load(ConfigDataLoaderContext context, RedisConfigDataResource resource) throws IOException, ConfigDataResourceNotFoundException {
        RedisStandaloneConfiguration configuration=new RedisStandaloneConfiguration(resource.getHost(),Integer.parseInt(resource.getPort()));
        LettuceConnectionFactory connectionFactory=new LettuceConnectionFactory(configuration);
        connectionFactory.afterPropertiesSet();

        StringRedisTemplate redisTemplate=new StringRedisTemplate(connectionFactory);

        Properties properties=new Properties();
        Set<Object> hashKeys=redisTemplate.boundHashOps(resource.getConfigKey()).keys();
        assert hashKeys != null;
        for (Object key : hashKeys){
            properties.put(key,redisTemplate.boundHashOps(resource.getConfigKey()).get(key));
        }

        return new ConfigData(Collections.singletonList(new PropertiesPropertySource("redis-config",properties)));
    }
}

                       

*************

controller 层

                     

HelloController

@RestController
public class HelloController {

    @Resource
    private Person person;

    @RequestMapping("/hello")
    public Person hello(){
        System.out.println(person);

        return person;
    }
}

                        

*************

META-INF

                         

                     

                               

spring.factories

org.springframework.boot.context.config.ConfigDataLoader=\
  com.example.demo.config.RedisConfigDataLoader
org.springframework.boot.context.config.ConfigDataLocationResolver=\
  com.example.demo.config.RedisConfigDataLocationResolver

                   

                              

*********************

使用测试

                                 

redis 设置数据

[root@centos ~]# docker exec -it redis-single bash
root@c2e2d338ed6b:/data# redis-cli
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> hset redis-config person.name gtlx
(integer) 1
127.0.0.1:6379> hset redis-config person.age 20
(integer) 1
127.0.0.1:6379> 

                          

localhost:8080/hello,控制台输出

2021-09-22 22:43:46.018  INFO 3496 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2021-09-22 22:43:46.019  INFO 3496 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
Person(name=gtlx, age=20)

成功读取redis中设置的数据

                           

                       

Guess you like

Origin blog.csdn.net/weixin_43931625/article/details/120381372