博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring boot中参数注入,@Value失效以及解决方案
阅读量:4261 次
发布时间:2019-05-26

本文共 4371 字,大约阅读时间需要 14 分钟。

Spring boot中参数注入,@Value失效以及解决方案

2018年08月09日 10:15:06  阅读数 9907

 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011958281/article/details/81531676

问题

项目中我们都要要尽量避免将参数直接写进程序里,这样一旦需要需要修改配置,我们可以只需要在配置文件里做修改,而不必在程序里找,这样可以避免很多错误,个人项目可能不会注意这一点,但是需要上线发布的项目,Configure配置文件就显得非常重要!现在很多公司其实都有这方面的应用,甚至有专门的中间件可以专门管理配置文件,即时生效,不必去上线修改参数,这不是我们今天说的重点。先看内容:

application-dev.properties

#URLconfirmURL=http://127.0.0.1:8081/confirm
  • 1
  • 2

这里写图片描述

然后在Controller类里面通过@Value将参数注入进来,最后的确成功了。因此基于此经验,我便在其他使用的类里面也采用这样的方式注入参数,但是发现去失效了,报错为NULL,说明参数并没有我们料想的被注入进来。

原因

这是为什么呢?为什么在Controller类就成功了?在其他类里面我尝试过@Service,@Component,@Configure,但是我没有成功,经过查询,原来,在使用这些参数生成Bean类的时候,我们注入的参数还没有生效,因此获取不到,而不是由于参数注入的问题,而在某些场景,spring可能做了优化,是的参数优先注入,再生成Bean。那么有没有好的方法可以解决这个问题呢?

方案

首先,我们的参数的直接注入是肯定不行了,那么我们就采用初始化类的方式,将配置信息集中初始化。

public class PropertyUtil {  private static final Logger logger = LoggerFactory.getLogger(PropertyUtil.class);  private static Properties props;  static {    loadProps();  }  synchronized static private void loadProps() {    logger.info("start to load properties.......");    props = new Properties();    InputStream in = null;    try {      in = PropertyUtil.class.getClassLoader().      getResourceAsStream("application.properties");      props.load(in);      logger.info(name);    } catch (FileNotFoundException e) {      logger.error("properties not found!");    } catch (IOException e) {      logger.error("IOException");    } finally {      try {        if (null != in) {          in.close();        }      } catch (IOException e) {        logger.error("properties close Exception!");      }    }    // logger.info(props);    logger.info("load properties over...........");  }  public static String getProperty(String key) {    if (null == props) {      loadProps();    }    return props.getProperty(key);  }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

通过Util类我们一次行加载参数,在需要获取的地方,直接通过

private static String    unsubscribeUrl = PropertyUtil.getProperty("unsubscribeUrl");
  • 1
  • 2

这样就可以获取我们所需要的参数了,直接定义为静态变量,一次读取,后面都可以直接使用。

引申

在Spring boot中参数配置有三个 application.properties, application-dev.properties, application-prod.properties

application.properties

spring.profiles.active=dev
  • 1

通过在这里修改dev 或者 prod 我可以配置两套配置,一套用于产品,一套是开发,那么我如果来根据我配置的信息来读取不同的配置呢,这又让我头疼了,看着代码,我想到,既然他可以读取配置文件了,那么我为何不先获取一下 application.properties里面的信息,然后看dev,或者prod来加载不同的配置呢,因此,我加了一段判断代码:

in = PropertyUtil.class.getClassLoader().getResourceAsStream("application.properties");      props.load(in);      String name = getProperty("spring.profiles.active");      if (name.equals("dev")) {        in = PropertyUtil.class.getClassLoader().getResourceAsStream("application-dev.properties");      } else if (name.equals("prod")) {        in = PropertyUtil.class.getClassLoader().getResourceAsStream("application-prod.properties");      }      props.load(in);      logger.info(name);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

通过测试,name的确是我 在application.properties配置的信息,因此,这具很好的解决了两套配置,在线下测试跟发布,我只需要修改一个配置文件就可以完成转换,节省时间的同时,也避免了错误发生,很多上线的问题都是因为配置的问题,因此这个问题一定要小心,当然还有很多方案,后面接触到我会继续总结,最近在代码的重构,发现自己的代码有很多问题。

@Componentpublic class ExchangeServiceUtil {  private static String mailServer;  private static String user;  private static String password;  private Logger logger = LoggerFactory.getLogger(this.getClass());  @Autowired  private ExchangeServiceUtil(@Value("${spring.EWS.mailServer}") String mailServer,      @Value("${spring.EWS.user}") String user,      @Value("${spring.EWS.password}") String password) {    this.mailServer = mailServer;    this.user = user;    this.password = password;  }  private static ExchangeServiceUtil instance = new ExchangeServiceUtil(mailServer, user, password);  public static ExchangeServiceUtil getExchangeServiceUtil() {    return instance;  }  public ExchangeService getExchangeService() throws URISyntaxException {    ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);    ExchangeCredentials credentials = new WebCredentials(user, password);    service.setCredentials(credentials);    service.setUrl(new URI(mailServer));    //    service.autodiscoverUrl("
"); return service; }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

我通过构造函数的方式,也成功的把参数注入到了里面,这个方法也是偶然接触到的,在某些工具,比如数据池,这是微软的邮件发送配置,都是可以采用这样的方法,构造函数可以加载参数,然后在生成Bean,很好的避开了那个问题,这个问题我还会继续深究,看看有什么发现,如果你有高见,欢迎留言!

你可能感兴趣的文章
Java NIO 系列教程
查看>>
fork() || fork()和fork() && fork()笔试题
查看>>
Qt:事件处理
查看>>
sublime Text3使用笔记
查看>>
使用webstom或者idea上传代码到github或coding
查看>>
YAML 语法
查看>>
AES加密
查看>>
使用Github进行合作开发
查看>>
Hadoop常用命令
查看>>
Impala入门笔记(转载)
查看>>
大数据分析:机器学习算法实现的演化
查看>>
自学大数据:用以生产环境的Hadoop版本比较
查看>>
Cloudera Manager和Managed Service的数据库
查看>>
cloudera Manager中监控数据的存储
查看>>
Kafka简要介绍
查看>>
Maven环境的搭建
查看>>
hbase 学习梳理
查看>>
浅谈医学大数据(中)
查看>>
阿里巴巴数据产品经理工作总结
查看>>
大数据的特点及作用
查看>>