我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

1 问题描述

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

即使用@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;


@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();
    }
}

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;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;



@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 += "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 项目结构

在这里插入图片描述

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;


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().getStatusCode() == 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;
                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;


@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接口,至于这种用法,改天再来写一篇阐述的文章吧。

总结

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

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

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

这篇文章主要介绍了使用@Value为静态变量导入并使用导入的静态变量进行初始化方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-02-13

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录