开发者

使用@Value为静态变量导入并使用导入的静态变量进行初始化方式

开发者 https://www.devze.com 2023-02-14 10:25 出处:网络 作者: 思影影思
目录1 问题描述2 问题结构2.1 服务方2.2 客户方3总结总结1 问题描述 在南京出差时,在开始开发,自己把一些相对紧密联系的不变得配置放进一个类中,这些字段为static的,待交付时heXLwb,由于这些配置也要是可以通过
目录
  • 1 问题描述
  • 2 问题结构
    • 2.1 服务方
    • 2.2 客户方
  • 3总结
    • 总结

      1 问题描述

      在南京出差时,在开始开发,自己把一些相对紧密联系的不变得配置放进一个类中,这些字段为static的,待交付时heXLwb,由于这些配置也要是可以通过配置文件进行配置的,因此无形之中就引入了一个问题。

      即使用@Value对静态变量进行导入的问题。并且还有一种更加复杂的情形,即需要在生成相关的Bean时,需要进行一些资源的初始化,在当时自己结结实实的踩了一把坑。

      在项目开始时TomcatConfig类是如下的:

      public class TomcatConfig {
          public static String ip = "192.168.1.112";
          public static int port=8080;
          public  static String username=admin;
          public  static String password=admin;
      }
      

      但在交付之前,要把这些配置值放入配置文件,例如application.properties

      tomcat.ip=10.30.102.111
      tomcat.port=8080
      tomcat.username=admin
      tomcat.password=admin
      

      并且要在该类再开始时通过HTTP调用,使用这些参数进行一次初始化。

      2 问题结构

      2.1 服务方

      可以理解自己开发的模块依赖于其他的模块,模块之间通过HTTP通信获取数据和状态。可以通过Spring Boot起一个程序提供一个对外的接口,即相当于提供服务。

      这就是服务提供的类。

      该程序所在的服务器ip和端口即上边已经写进配置文件的ip和端口。

      package com.wisely.ch6_2_3.controller;
      
      import com.alibaba.fastjson.JSON;
      import com.alibaba.fastjson.JSONObject;
      import com.wisely.ch6_2_3.config.TomcatSetting;
      import lombok.extern.Java.Log;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.http.MediaType;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RequestParam;
      import org.springframework.web.bind.annotation.RestController;
      
      import java.util.UUID;
      
      /**
       * 测试注入
       *
       * @Owner:
       * @Time: 2019/3/31-16:29
       */
      @RestController
      @Log
      public class TestValue {
          @Autowired
          private TomcatSetting serverConfig;
      
          @RequestMapping(value = "/getImg",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
          public String getImgeLoc() {
              log.info("Enter getImgeLoc");
              System.out.println("--   Handling   --");
              String fileName = UUID.randomUUID().toString()+".jpg";
              JSONObject result = new JSONObject();
              result.put("imgUrl", serverConfig.getUrl()+"/"+fileName);
              System.out.println("--   over   --");
              return result.toJSONString();
          }
      
          @RequestMapping("/getmapping")
          public String service(@RequestParam("username") String username, @RequestParam("password") String password) {
              if (!username.equals("admin") ||!password.equals("admin")) {
                  JSONObject res = new JSONObject();
                  res.put("state", -1);
                  res.put("msg", "fail");
                  return res.toJSONString();
              }
              JSONObject result = new JSONObject();
              result.put("state", 0);
              result.put("msg", "success");
              JSONObject data = new JSONObject();
      
              data.put("aaa", "bbb");
              data.put("ccc", "ddd");
              result.put("data", data);
              return result.toJSONString();
        javascript  }
      }
      
      

      2.2 客户方

      由于之前写的代码是硬编码,肯定要重构这部分的代码,@Value可以灵活的实现注入,但通过在互联网上查询相关的页面可以得到如下的知识:

      • SpringBoot中使用@Value()只能给普通变量注入值,不能直接给静态变量赋值,并且@Value使用设值函数为成员注入值。
      • 为了给静态变量注入值,需要使用特殊的语法

      2.2.1核心类 TomcatConfig

      package com.example.staticvalue.config;
      
      import com.alibaba.fastjson.JSONObject;
      import com.example.staticvalue.HttpClientUtil.HttpClientUtil;
      import com.fasterXML.jackson.databind.util.JSONPObject;
      import lombok.Getter;
      import lombok.extern.java.Log;
      import org.apache.http.protocol.HTTP;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.boot.context.properties.ConfigurationProperties;
      import org.springframework.context.annotation.ComponentScan;
      i开发者_Go入门mport org.springframework.stereotype.Component;
      
      import java.util.HashMap;
      import java.util.Map;
      
      /**
       * tomcat配置
       *
       * @Owner:
       * @Time: 2019/3/31-19:25
       */
      
      @Component
      @Log
      public class TomcatConfig {
          @Getter
          private static String ip;
          @Getter
          private static int port;
          @Getter
          private static String username;
          @Getter
          private static String password;
          private static JSONObject data = new JSONObject();
      
          # 在静态初始化块中调用set()是无效的,因为此时ip等变量尚未注入。应该是在该Bean已经生成了,即ip,port,usernam,password已经注入之后再调用set()这样才有效。
          static {
              log.info("静态化块");
              log.info("TomcatConfig.ip: "+ TomcatConfig.ip);
              ~~~~try {
                  ~~set();~~ 
              ~~} catch (Exception e) {~~ 
                  ~~e.printStackTrace();~~ 
              }~~~~   
          }
          
          @Value("${tomcat.ip}")
          public void setIp(String ip) {
              TomcatConfig.ip = ip;
          }
      
          @Value("${tomcat.password}")
          public void setPassword(String password) {
              TomcatConfig.password = password;
          }
      
          @Value("${tomcat.port}")
          public void setPort(int port) {
              TomcatConfig.port = port;
          }
      
          @Value("${tomcat.username}")
          public void setUsername(String username) {
              TomcatConfig.username = username;
          }
      
         // 注意该函数应在类外进行调用,比如set()可以放置在其他标注了雷瑟@Componet的Bean类中,这样可以保证在TomcatConfig的bean已经生成。
          public static void set() throws Exception {
              log.info("Enter set");
              log.info("TomcatConfig.ip: "+ TomcatConfig.ip);
              String AccessUrl = "http://"+getIp()+":"+getPort()+"/getmapping?";
              accessUrl += python"username="+username+"&"+"password="+password;
              log.info("accessUrl = "+accessUrl);
              String result = HttpClientUtil.postJson(accessUrl, "{}");
              JSONObject ret = JSONObject.parseobject(result);
              if (ret.getIntValue("state") == 0) {
                  data = ret.getJSONObject("data");
              }
          }
      }
      
      

      注意:set()方法完成了类似初始化的工作,即通过调用一次http请求,填充了static成员data的值。

      set()的调用不可以放在本类的静态环境下,尤其在war包运行在tomcat之下更是这样,在jar包中set()函数的调用放在静态函数main之中是有效的。

      这可以通过日志进行证明,如果是war包跑在tomcat环境下,若为如下代码:

      public static void main(String[] args) throws Exception{
              log.info("Enter main");
              SpringApplication.run(StaticvalueApplication.class, args);
              log.info("after run");
              TomcatConfig.set();
              log.info("after set");
          }
      

      程序会仅执行到after run日志打印,不会执行TomcatConfig.set()的调用,切记,切记

      如果真的是在war包跑在tomcat下,可以使用如下的方式解决,可以把TomcatConfig.set()的调用放在其他Bean类的静态初始化块中。

      2.2.2 项目结构

      使用@Value为静态变量导入并使用导入的静态变量进行初始化方式

      2.2.3辅助类HttpClientUtil

      package com.example.staticvalue.HttpClientUtil;
      
      import org.apache.http.HttpEntity;
      import org.apache.http.client.ClientProtocolException;
      import org.apache.http.client.methods.CloseableHttpResponse;
      import org.apache.http.client.methods.HttpPost;
      import org.apache.http.entity.ByteArrayEntity;
      import org.apache.http.impl.client.CloseableHttpClient;
      import org.apache.http.impl.client.HttpClients;
      import org.apache.http.util.CharArrayBuffer;
      import org.apache.http.util.EntityUtils;
      
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.UnsupportedEncodingException;
      
      /**
       * 辅助类,使用http获取数据
       *
       * @Owner:
       * @Time: 2019/3/31-19:49
       */
      public class HttpClientUtil {
          public static String postJson(String url,String jsonString) throws Exception
          {
              String result = null;
              CloseableHttpClient httpClient = HttpClients.createDefault();
              HttpPost post = new HttpPost(url);
      
              CloseableHttpResponse response = null;
              try {
                  post.setEntity(new ByteArrayEntity(jsonString.getBytes("UTF-8")));
                  post.setHeader("Content-Type","application/json" );
                  response = httpClient.execute(post);
                  if(response != null && response.getStatusLine().getStatusandroidCode() == 200)
                  {
                      HttpEntity entity = response.getEntity();
                      result = entityToString(entity);
                  }
                  return result;
              } catch (UnsupportedEncodingException e) {
                  e.printStackTrace();
              } catch (ClientProtocolException e) {
                  e.printStackTrace();
              } catch (IOException e) {
                  e.printStackTrace();
              }finally {
                  try {
                      httpClient.close();
                      if(response != null)
                      {
                          response.close();
                      }
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
              return null;
          }
      
          private static String entityToString(HttpEntity entity) throws IOException {
              String result = null;
              if(entity != null)
              {
                  long lenth = entity.getContentLength();
                  if(lenth != -1 && lenth < 2048)
                  {
                      result = EntityUtils.toString(entity,"UTF-8");
                  }else {
                      InputStreamReader reader1 = new InputStreamReader(entity.getContent(), "UTF-8");
                      CharArrayBuffer buffer = new CharArrayBuffer(2048);
                      char[] tmp = new char[1024];
                      int l;
      www.devze.com                while((l = reader1.read(tmp)) != -1) {
                          buffer.append(tmp, 0, l);
                      }
                      result = buffer.toString();
                  }
              }
              return result;
          }
      
      
      }
      
      

      2.2.4 启动类

      package com.example.staticvalue;
      
      import com.example.staticvalue.config.TomcatConfig;
      import lombok.extern.java.Log;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      
      @SpringBootApplication
      @Log
      public class StaticvalueApplication {
      
          public static void main(String[] args) throws Exception{
              log.info("Enter main");
              SpringApplication.run(StaticvalueApplication.class, args);
              log.info("after run");
              //在Jar包中运行时,下句是可以生效的,但在war包运行在tomcat中时,TomcatConfig。set()以及之后的语句不会执行。把Tomcat.set()放在某个Bean的静态初始化块中即可
              TomcatConfig.set();
              log.info("after set");
          }
      
      }
      
      

      2.2.5 TaskService

      package com.example.staticvalue.service;
      
      import com.example.staticvalue.config.TomcatConfig;
      import lombok.extern.java.Log;
      import org.springframework.stereotype.Component;
      
      /**
       * 任务类
       *
       * @Owner:
       * @Time: 2019/3/31-19:39
       */
      @Component
      @Log
      public class TaskService {
          static {
              try {
                  log.info("TaskService: before set");
                  TomcatConfig.set();
                  log.info("TaskService: after set");
      
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }
      
      

      3总结

      上述注入静态变量的主要原因是静态变量因为一些遗留的原因,为了解决硬编码的问题而引入的,至于在静态变量通过@Value注入时同时在该类中进行初始化,则是非常不优雅的一种编程风格,这种初始化的方式更加建议放置在类似开机自启动的应用程序中,在Spring Boot中也确实有这样的实现场景。

      即CommandLineRunner接口,实现该接口的类必须实现run()方法,而该方法会在所有Bean均已正确生成之后开始执行。

      关于CommandLineRunner,可以参考CommandLineRunner或者ApplicationRunner接口,至于这种用法,改天再来写一篇阐述的文章吧。

      总结

      以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

      0

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      关注公众号