spring-boot integrate with archaius

本文介绍如何通过Consul实现应用程序的动态配置加载。通过整合Archaius和Commons Configuration等库,实现从Consul中读取配置并定时更新。同时介绍了如何创建自定义属性源及环境后处理器来实现这一目标。

Prerequistion

I will use Consul-KV as the property source, you can refer to below article to setup the consul environment
https://blog.youkuaiyun.com/yaominhua/article/details/82316287
Also you need integrate with consul client first, please refer to below article
https://blog.youkuaiyun.com/yaominhua/article/details/82317368

Objective

To retrieve the configuration dynamically

Steps

Add below dependency to pom.xml

<dependency>
    <groupId>com.netflix.archaius</groupId>
    <artifactId>archaius-core</artifactId>
    <version>0.7.6</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-configuration2</artifactId>
    <version>2.3</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
</dependency>

Implements the interface PolledConfigurationSource

public class ConsulConfigurationSource implements PolledConfigurationSource {

    private String keyName;

    public ConsulConfigurationSource(String keyName) {
        this.keyName = keyName;
    }

    @Override
    public PollResult poll(boolean initial, Object checkPoint) throws Exception {
        KeyValueClient kvClient = Consul.newClient().keyValueClient();
        Optional<String> kvOpt = kvClient.getValueAsString(keyName);
        String kvStr = StringUtils.EMPTY;
        if (kvOpt.isPresent()) {
            kvStr = kvOpt.get();
        }
        Properties props = new Properties();
        props.load(new StringReader(kvStr));
        Map<String, Object> propMap = new HashMap<>();
        props.keySet().forEach(x -> {
            propMap.put((String)x, props.get(x));
        });
        return PollResult.createFull(propMap);
    }

}

Create custom spring application initializer

public class ConsulPropertySourceInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    // default value is 60000 (60s)
    private static final String ARCHAIUS_DELAY_KEY_MILLS = "archaius.fixedDelayPollingScheduler.delayMills";

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.setProperty(ARCHAIUS_DELAY_KEY_MILLS, "10000");
        // This key/value has been added from Consul-UI
        String keyName = "service/config/dev";
        PolledConfigurationSource configSource = new ConsulConfigurationSource(keyName);
        AbstractPollingScheduler scheduler = new FixedDelayPollingScheduler();
        DynamicConfiguration configuration = new DynamicConfiguration(configSource, scheduler);
        ConfigurationManager.install(configuration);
    }

}

Add this initializer into spring application before run

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication sa = new SpringApplication(Application.class);
        // add custom initializer
        sa.addInitializers(new ConsulPropertySourceInitializer());
        sa.run(args);
    }

}

Write the test controller to retrieve the data

@RestController
@RequestMapping("helloWorld")
public class HelloWorldController {
    @RequestMapping(value="property/{propName}")
    public String getPropertyValue(@PathVariable("propName") String propName) {
        DynamicStringProperty dsp = DynamicPropertyFactory.getInstance().getStringProperty(propName, "");
        return dsp.get();
    }
}

We can use below URL to have a test:
http://localhost:8080/helloWorld/property/person.first.name

Put the data into spring application property source

Create custom property source

public class ConsulPropertySource extends MapPropertySource {
    public ConsulPropertySource(String name, Map<String, Object> source) {
        super(name, source);
    }
}

Create custom environment post processor

public class LoadConsulEnv implements EnvironmentPostProcessor, Ordered {

    @Override
    public int getOrder() {
        return ConfigFileApplicationListener.DEFAULT_ORDER + 1;
    }

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        Map<String, Object> propMap = new HashMap<>();
        KeyValueClient kvClient = Consul.newClient().keyValueClient();
        Optional<String> kvOpt = kvClient.getValueAsString("service/config/dev");
        String kvStr = StringUtils.EMPTY;
        if (kvOpt.isPresent()) {
            kvStr = kvOpt.get();
        }
        Properties props = new Properties();
        try {
            props.load(new StringReader(kvStr));
        } catch (IOException e) {
            e.printStackTrace();
        }
        props.keySet().forEach(x -> {
            propMap.put((String)x, props.get(x));
        });
        ConsulPropertySource propertySource = new ConsulPropertySource("thirdEnv", propMap);
        MutablePropertySources propertySources = environment.getPropertySources();
        propertySources.addLast(propertySource);
    }
}

Register the processor to spring.factories

  • Create folder “META-INF” under src/main/resources
  • Create file “spring.factories” under folder “META-INF”
  • Copy below content to the file
org.springframework.boot.env.EnvironmentPostProcessor=\
 com.xuya.app.demo.config.archaius.LoadConsulEnv
  • LoadConsulEnv will be loaded when application run

Create a test controller to have a test

@RestController
@RequestMapping("helloWorld")
public class HelloWorldController {
    @Autowired
    private Environment env;
    @RequestMapping(value="envprop/{propName}")
    public String getEnvPropertyValue(@PathVariable("propName") String propName) {
        return env.getProperty(propName);
    }
}

We can use below URL to have a test:
http://localhost:8080/helloWorld/envprop/person.first.name

### 如何集成 Spring Session Data Redis 和 Redisson 或者解决相关问题 #### 背景介绍 Spring Session 是一个用于管理 HTTP 会话的框架,支持多种存储后端(如 Redis)。通过使用 `spring-session-data-redis`,可以将用户的会话数据存储到 Redis 中[^1]。而 Redisson 则是一个基于 Netty 的高性能 Java 客户端库,提供了丰富的分布式对象和服务功能。 当尝试将两者结合起来时,可能会遇到一些挑战,因为它们都依赖于 Redis 进行操作,但实现方式不同。以下是关于如何结合使用这两种技术以及可能解决方案的具体说明: --- #### 解决方案一:配置独立的 Redis 实例 如果希望同时使用 `spring-session-data-redis` 和 Redisson,则可以通过为每种工具分配不同的 Redis 数据库实例来避免冲突。例如,在 Redis 配置文件中定义多个数据库索引,并分别指定给这两个组件。 ```properties # Application properties for spring-session-data-redis spring.redis.database=0 spring.session.store-type=redis # Configuration for Redisson client pointing to different database index redisson.config.singleServerConfig.address="redis://127.0.0.1:6379" redisson.config.singleServerConfig.database=1 ``` 这种方式能够有效隔离两者的键空间,防止互相干扰[^1]。 --- #### 解决方案二:自定义命名前缀策略 另一种方法是让两个模块共享同一个 Redis 实例,但是通过设置唯一的键名前缀区分各自的数据范围。对于 `spring-session-data-redis` 来说,默认情况下它已经会对所有的 session 键附加特定前缀;而对于 Redisson 用户则可以在初始化客户端的时候手动添加类似的机制。 下面展示了一个简单的例子演示如何修改 Redisson 的默认行为以便兼容这种需求: ```java import org.redisson.Redisson; import org.redisson.api.RBucket; import org.redisson.api.RedissonClient; import org.redisson.config.Config; public class CustomizedRedissonExample { public static void main(String[] args) { Config config = new Config(); // Set custom key prefix here. String customPrefix = "myapp:"; config.useSingleServer() .setAddress("redis://127.0.0.1:6379"); RedissonClient redisson = Redisson.create(config); RBucket<String> bucket = redisson.getBucket(customPrefix + "testKey"); bucket.set("value"); System.out.println(bucket.get()); } } ``` 这样做的好处是可以减少资源消耗并简化运维流程,缺点则是增加了开发复杂度[^2]。 --- #### 方案三:利用 Redis Cluster 提供更高可用性和扩展能力 考虑到实际生产环境中的高并发场景,建议采用 Redis Cluster 架构作为底层支撑平台。在这种模式下,即使单台节点发生故障也不会影响整体服务稳定性。更重要的是,由于集群内部实现了自动分片(sharding),因此无论你是运行了多少个应用程序副本还是部署了几套业务逻辑单元,都可以轻松应对海量请求压力而不必担心性能瓶颈问题出现。 需要注意的一点在于,无论是 Spring Boot Starter Redis 还是官方推荐使用的 Jedis/Lettuce 库版本都需要满足最低要求才能正常连接至 Clustersetup 上去工作[^3]。 --- #### 总结 综上所述,针对 “How To Integrate Spring-Session-Data-Redis With Redisson Or Solve Related Issues” 这个主题给出了三种可行的技术路线图解法。具体选择哪一种取决于项目实际情况比如团队技术水平、预算成本等因素综合考量之后再做决定最为合适不过啦! ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值