美文网首页
spring老项目升级spring-boot之dubbo升级

spring老项目升级spring-boot之dubbo升级

作者: 刘振宁的博客 | 来源:发表于2023-03-29 17:47 被阅读0次

    spring老项目升级spring-boot之dubbo升级

    巨大的建筑,总是由一木一石叠起来的,我们何妨做做这一木一石呢?我时常做些零碎事,就是为此。

    这是对的,但是我没有说过这句话! —— 鲁迅

    问题的开始

    之前老的spring项目使用dubbo的时候,都是使用的xml的方式。这篇文章主要是站在consumer端的角度出发,也就是 provider不变的情况下(仍然是xml),怎样先升级consumer端,来实现项目的正常运行。

    我相信,使用xml的老项目的配置文件一般长这样.

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
           xmlns="http://www.springframework.org/schema/beans"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
            http://code.alibabatech.com/schema/dubbo
            http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    
        <dubbo:application name="api-consumer" owner="ennz"/>
        <dubbo:registry group="${dubbo.group}" check="false" protocol="zookeeper"
                        address="${zookeeper.hosts}"/>
        
        <dubbo:reference version="0.0.1" check="false" id="service1"
                         interface="com.tms.bl.service.Service1"/>
    
        <dubbo:reference version="0.0.1" check="false" id="service2"
                         interface="com.tms.bl.service.Service2"/>
    </beans>
    
    

    Application中引入这个文件,会出现报错

    @SpringBootApplication
    @ImportResource(locations = {"classpath:dubbo_consumer.xml"})
    public class AdminApiApplication  {
      private static final Logger logger = LoggerFactory.getLogger(AdminApiApplication.class);
      public static void main(String[] args) {
          SpringApplication.run(AdminApiApplication.class, args);
      }
    }
    

    报错如下:

    2023-03-30 16:52:14.323 [main-SendThread()] WARN  org.apache.zookeeper.ClientCnxn - Session 0x0 for server ${zookeeper.hosts}:9090, unexpected error, closing socket connection and attempting reconnect
    java.lang.IllegalArgumentException: named capturing group is missing trailing '}'
        at java.util.regex.Matcher.appendReplacement(Matcher.java:841)
        at java.util.regex.Matcher.replaceAll(Matcher.java:955)
        at java.lang.String.replaceAll(String.java:2223)
        at org.apache.zookeeper.ClientCnxn$SendThread.startConnect(ClientCnxn.java:997)
        at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1064)
    

    也就是说,相应的 ${zookeeper.hosts} 类似于这样的值,无法注入.

    针对xml${zookeeper.hosts}无法注入的思考

    无法注入,是否可以通过使用 @Configuration注解的方式,来注入相应的值

    新增配置类,但是不完全取代xml

    在xml中,有两个标签如下:

     <!-- 对应java类是 ApplicationConfig -->
    <dubbo:application name="api-consumer" owner="ennz"/>
     <!-- 对应java类是 RegistryConfig -->
    <dubbo:registry group="${dubbo.group}" check="false" protocol="zookeeper"
                        address="${zookeeper.hosts}"/>
    

    把这两个用java配置类来实现,至于有很多已经写好的<dubbo:reference />则继续使用xml的方式,通过@ImportResource来实现。java配置类如下:

    @Configuration
    @ImportResource("classpath:dubbo-consumer.xml")
    public class DubboAdasConsumerConfig {
      private Logger logger = LoggerFactory.getLogger(DubboAdasConsumerConfig.class);
    
      @Value("${dubbo.zookeepers}")
      private String dubboZookeepers;
    
      @Value("${dubbo.group}")
      private String dubboGroup;
    
      /*相当于consumer.xml中的:<dubbo:application name="consumer"/>*/
      @Bean
      public ApplicationConfig gpsApplicationConfig() {
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("api-consumer");
        applicationConfig.setOwner("ennz");
        return applicationConfig;
      }
    
      /*相当于:<dubbo:registry address="39.108.125.227:2181" protocol="zookeeper"/>*/
      @Bean
      public RegistryConfig adasRegistryConfig() {
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setProtocol("zookeeper");
        registryConfig.setCheck(false);
        registryConfig.setAddress(dubboZookeepers);
        registryConfig.setGroup(dubboGroup);
        logger.info("adasRegistryConfig:{}", registryConfig.getAddress());
        return registryConfig;
      }
    }
    
    

    其中 dubbo-consumer.xml 中,去掉这两个类的配置,只剩下主要service的注入:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
           xmlns="http://www.springframework.org/schema/beans"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
            http://code.alibabatech.com/schema/dubbo
            http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
        
        <dubbo:reference version="0.0.1" check="false" id="service1"
                         interface="com.tms.bl.service.Service1"/>
    
        <dubbo:reference version="0.0.1" check="false" id="service2"
                         interface="com.tms.bl.service.Service2"/>
    </beans>
    

    但是运行之后,仍然报错,是dubbo中注入的service为空。我这里是生成shiro的时候,用到了某个dubbo服务。报错:register dubbo:null

    Caused by: java.lang.IllegalStateException: registry address == null
    

    然后,输出了一下 registryConfig.getAddress()的值,是null,也就是@Value("${dubbo.zookeepers}")失效,并没有注入成功.

    分析一下原因,应该跟加载顺序有关.

    1. 先加载bean
    2. 加载配置类,加载@Value值。
    3. 执行第一步的时候,发现有的是dubbo的,但是想要加载dubbo的,就需要先找到dubbo的配置,就先加载了dubbo的配置类.但是,此时@Value还未生效,是null.

    使用最基础的方法,读取文件,提前找到配置。

    配置文件一般都提取出来,放到config文件夹下面.

    直接读取它,获取属性配置。

    @SpringBootApplication
    @ImportResource(locations = {"classpath:applicationContext.xml"})
    public class AdminApiApplication  {
      private static final Logger logger = LoggerFactory.getLogger(AdminApiApplication.class);
    
      public static void main(String[] args) {
        try {
          setConfigProperties();
          SpringApplication.run(AdminApiApplication.class, args);
          System.out.println("print start");
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    
      public static void setConfigProperties() {
        Properties config = new Properties();
        try {
          File file = new File("/data/config/config.properties");
          FileInputStream fileInputStream = new FileInputStream(file);
          InputStream is = fileInputStream;
          config.load(is);
        } catch (IOException var5) {
          throw new RuntimeException("An error occurred while reaed exceptions", var5);
        }
        CacheManager.configProperties = config;
        logger.info("config:{}", JSON.toJSONString(config));
      }
    
    }
    
    

    其中 CacheManager.configProperties是一个静态变量,简单的存储器.

    public class CacheManager {
      /**
       * config中的变量.
       */
      public static Properties configProperties;
    }
    

    使用注入@Value的地方,不使用@Value来注入,直接取值

      @Bean
      public RegistryConfig gpsRegistryConfig() {
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setProtocol("zookeeper");
        registryConfig.setCheck(false);
        registryConfig.setAddress(CacheManager.configProperties.getProperty("dubbo.zookeepers"));
        registryConfig.setGroup(CacheManager.configProperties.getProperty("dubbo.group"));
        return registryConfig;
      }
    

    运行,可以启动成功.

    有没有更好的方法

    使用 EnvironmentPostProcessor,这里会在加载配置类之前执行。增加类,实现AdminApiApplication中的setConfigProperties方法.

    /**
     *
     * @author liuzhenning
     * @version 0.0.1
     * @since 0.0.1 2022-11-25
     */
    public class CustomerConfigLoadProcessor implements EnvironmentPostProcessor {
    
      private Logger logger = LoggerFactory.getLogger(CustomerConfigLoadProcessor.class);
    
      @Override
      public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        System.out.println("postProcessEnvironment begin=====================================");
        Properties config = new Properties();
    
        this.addProperties(config, "/data/config/config.properties");
        this.addProperties(config, "E://temp/config/config.properties");
    
        CacheManager.configProperties = config;
        System.out.println("postProcessEnvironment done");
      }
    
      private void addProperties(Properties config, String fileName) {
        try {
          Properties properties = new Properties();
          File file = new File(fileName);
          if (!file.exists()) {
            return;
          }
          InputStream is = new FileInputStream(file);
          properties.load(is);
          config.putAll(properties);
          is.close();
        } catch (IOException var5) {
          logger.error("error", var5);
        }
      }
    
    }
    

    增加该类后,spring并不会加载它,还需要配置一下

    resources下面增加文件夹META-INF/spring.factories,增加配置

    org.springframework.boot.env.EnvironmentPostProcessor=\
      com.xxxx.CustomerConfigLoadProcessor
    

    去掉AdminApiApplication 中的setConfigProperties(),运行,成功启动.

    相关文章

      网友评论

          本文标题:spring老项目升级spring-boot之dubbo升级

          本文链接:https://www.haomeiwen.com/subject/vxgfddtx.html