手写分布式配置中心(五)整合springboot(不自动刷新的)

本文详细介绍了在SpringBoot应用中使用environment、BeanDefinition、@Value和@ConfigurationProperties进行配置的方法,以及如何通过自定义EnvironmentPostProcessor在早期阶段加载配置,确保第三方jar包的兼容性。作者还提供了ConfigCenterClient的单例管理和配置注入的示例。
摘要由CSDN通过智能技术生成

springboot中使用配置方式有四种,分别是environment、BeanDefinition、@Value、@ConfigurationProperties。具体的原理可以看我之前的一篇文章https://blog.csdn.net/cjc000/article/details/132800290。代码在https://gitee.com/summer-cat001/config-center

原理

environment是存储配置的地方,其他的都是从这里获取的数据。所以只要在他们用到配置之前,把配置放到environment中就可以了,先看下springboot的启动流程图。

可以看到业务代码第一次用到配置的地方是PropertySourcesPlaceholderConfigurer,它是一个BeanFactoryPostProcessor默认的order是最低优先级的,所以只要在执行它之前把配置放到environment对象中即可,如图标红的地方

不过很多三方的jar包可能会会自定义ApplicationContextInitializer和BeanFactoryPostProcessor。所以为了让这些jar包也用到我们的配置,所以要在更早的阶段加载配置,既然springboot提供了加载配置的扩展点,那我们直接注册一个自定义的EnvironmentPostProcessor类即可,不过因为我们加载配置的时候也要使用application.yml的配置,比如设置连接地址什么的,所以需要把我们的EnvironmentPostProcessor的优先级设置的小于ConfigDataEnvironmentPostProcessor,ConfigDataEnvironmentPostProcessor的优先级是Ordered.HIGHEST_PRECEDENCE + 10,我们只要把order设置成Ordered.HIGHEST_PRECEDENCE + 11即可

代码

ConfigCenterClient改为单例

 private static volatile ConfigCenterClient client;

    private ConfigCenterClient(String url) {
        this.url = url;
        //将配置中心的配置转换成property格式,即user.name=xxx
        List<ConfigVO> configList = getAllValidConfig();
        this.configMap = configList2ConfigMap(configList);
    }

    public static ConfigCenterClient getInstance(String url) {
        return Optional.ofNullable(client).orElseGet(() -> {
            synchronized (ConfigCenterClient.class) {
                if (client == null) {
                    client = new ConfigCenterClient(url);
                }
                return client;
            }
        });
    }

自定义EnvironmentPostProcessor

可以看到我们是从application.yml文件中获取了配置中心的地址,然后再把配置中心的配置注入到springboot中

public class ConfigEnvironmentPostProcessor implements EnvironmentPostProcessor {

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        String configCenterUrl = environment.getProperty("config.center.url");
        ConfigCenterClient configCenterClient = ConfigCenterClient.getInstance(configCenterUrl);
        Map<String, Object> configProperty = configCenterClient.getConfigProperty();

        MutablePropertySources propertySources = environment.getPropertySources();
        MapPropertySource configCenter = new MapPropertySource("configCenter", configProperty);
        propertySources.addFirst(configCenter);
    }
}

注册EnvironmentPostProcessor

org.springframework.boot.env.EnvironmentPostProcessor=\
com.config.center.config.ConfigEnvironmentPostProcessor

效果

environment对象获取配置

@Autowired
    private Environment environment;

    @Test
    public void configTest() {
        String userName = environment.getProperty("user.name");
        System.out.println(userName);
    }

xml中获取配置

public class User {
    private String userName;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
	    "
       default-lazy-init="false">

    <bean id="user" class="com.config.center.test.User">
        <property name="userName" value="${user.name}"/>
    </bean>

</beans>

@Value获取配置

    @Value("${user.name}")
    private String name;

    @Test
    public void configTest() {
        System.out.println(name);
    }

@ConfigurationProperties

@Component
@ConfigurationProperties(prefix = "user")
public class UserConfig {
    private String name;
    private int age;
    private List<String> education;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<String> getEducation() {
        return education;
    }

    public void setEducation(List<String> education) {
        this.education = education;
    }
}
    @Autowired
    private UserConfig userConfig;

    @Test
    public void configTest() {
        System.out.println(userConfig);
    }

​​​​​​​

分布式事务是指跨多个数据库或服务的事务操作,保证数据一致性和可靠性。在 Java 中手写分布式事务可以使用以下几种方式实现: 1. 两阶段提交(2PC):在分布式环境中,协调者(通常是一个中心节点)与参与者(各个分布式节点)进行协调来保证事务的一致性。具体实现中,需要定义协议、消息的传递和处理等。这种方式实现相对复杂,但能够保证数据的强一致性。 2. 补偿事务(TCC):通过预先定义事务的 try、confirm 和 cancel 三个阶段,来实现自动或手动进行事务的补偿。如果某个参与者失败,则可以通过 cancel 阶段回滚之前的操作。这种方式实现相对简单,但可能会引入一定的不一致性。 3. 消息队列:使用消息队列可以将分布式事务拆解为独立的事务操作,并通过消息中间件来保证最终一致性。具体实现中,可以使用事务消息或者可靠消息传递机制,确保消息的可靠传递和处理。 4. 分布式锁:使用分布式锁可以在分布式环境下保证对共享资源的互斥访问。通过获取锁来进行事务操作,可以保证在同一时刻只有一个节点能够执行某个操作,从而保证数据的一致性。 需要注意的是,手写分布式事务比较复杂且易出现问题,建议使用成熟的分布式事务框架或者中间件,如 Spring Cloud、Atomikos、Seata 等来简化开发和保证数据一致性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值