Spring4如何自定义@Value功能详解

前言

本文主要给大家介绍了关于Spring4自定义@Value功能的相关内容,使用的Spring版本4.3.10.RELEASE,下面话不多说了,来一起看看详细的介绍吧。

@Value在Spring中,功能非常强大,可以注入一个配置项,可以引用容器中的Bean(调用其方法),也可以做一些简单的运算

如下的一个简单demo,演示@Value的用法

import org.springframework.stereotype.Service; 

/**
 * 测试Bean
 */
@Service("userService")
public class UserService { 

 public int count() {
  return 10;
 } 

 public int max(int size) {
  int count = count();
  return count > size ? count : size;
 }
} 
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; 

@Component
public class AppRunner implements InitializingBean { 

 /**
  * 引用一个配置项
  */
 @Value("${app.port}")
 private int port; 

 /**
  * 调用容器的一个bean的方法获取值
  */
 @Value("#{userService.count()}")
 private int userCount; 

 /**
  * 调用容器的一个bean的方法,且传入一个配置项的值作为参数
  */
 @Value("#{userService.max(${app.size})}")
 private int max; 

 /**
  * 简单的运算
  */
 @Value("#{${app.size} <= '12345'.length() ? ${app.size} : '12345'.length()}")
 private int min; 

 //测试
 public void afterPropertiesSet() throws Exception {
  System.out.println("port : " + port);
  System.out.println("userCount : " + userCount);
  System.out.println("max : " + max);
  System.out.println("min : " + min);
 }
} 

app.properties

app.port=9090 

app.size=3 
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource; 

@ComponentScan
@PropertySource("classpath:app.properties")
public class App { 

 public static void main( String[] args) {
  AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(App.class);
  context.close();
 }
} 

运行,输出结果

port : 9090

userCount : 10

max : 10

min : 3

一般的用法就是这样,用于注入一个值。

那么,能否做到,我给定一个表达式或者具体的值,它能帮忙计算出表达式的值呢? 也就是说,实现一个@Value的功能呢?

方法如下:

import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.BeanExpressionResolver;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.expression.StandardBeanExpressionResolver; 

public class ValueUtil { 

 private static final BeanExpressionResolver resolver = new StandardBeanExpressionResolver(); 

 /**
  * 解析一个表达式,获取一个值
  * @param beanFactory
  * @param value 一个固定值或一个表达式。如果是一个固定值,则直接返回固定值,否则解析一个表达式,返回解析后的值
  * @return
  */
 public static Object resolveExpression(ConfigurableBeanFactory beanFactory, String value) {
  String resolvedValue = beanFactory.resolveEmbeddedValue(value); 

  if (!(resolvedValue.startsWith("#{") && value.endsWith("}"))) {
   return resolvedValue;
  } 

  return resolver.evaluate(resolvedValue, new BeanExpressionContext(beanFactory, null));
 }
} 

具体使用如下:

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource; 

@ComponentScan
@PropertySource("classpath:app.properties")
public class App { 

 public static void main( String[] args) {
  AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(App.class);
  //计算一个具体的值(非表达式)
  System.out.println(ValueUtil.resolveExpression(context.getBeanFactory(), "1121"));
  //实现@Value的功能
  System.out.println(ValueUtil.resolveExpression(context.getBeanFactory(), "${app.port}"));
  System.out.println(ValueUtil.resolveExpression(context.getBeanFactory(), "#{userService.count()}"));
  System.out.println(ValueUtil.resolveExpression(context.getBeanFactory(), "#{userService.max(${app.size})}"));
  System.out.println(ValueUtil.resolveExpression(context.getBeanFactory(), "#{${app.size} <= '12345'.length() ? ${app.size} : '12345'.length()}"));
  context.close();
 }
} 

运行输出如下:

1121

9090

10

10

3

发现已经实现了@Value的功能

最后,可能有人就有疑问了,这有什么用呢?我直接用@Value难道不好吗?

对于大部分场景下,的确直接用@Value就可以了。但是,有些特殊的场景,@Value做不了

比如说,我们定义一个注解

@Retention(RUNTIME)
@Target(TYPE)
public @interface Job {
 String cron();
} 

这个注解需要一个cron的表达式,我们的需求是,使用方可以直接用一个cron表达式,也可以支持引用一个配置项(把值配置到配置文件中)

比如说

@Job(cron = "0 0 12 * * ?")
@Job(cron = "${app.job.cron}")

这种情况@Value就做不到,但是,可以用我上面的解决方案。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • 详解Spring通过@Value注解注入属性的几种方式

    场景 假如有以下属性文件dev.properties, 需要注入下面的tag tag=123 通过PropertyPlaceholderConfigurer <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="dev.properties" /&

  • spring中@value注解需要注意的问题

    首先,@value需要参数,这里参数可以是两种形式:@Value("#{configProperties['t1.msgname']}")或者@Value("${t1.msgname}"): 其次,下面我们来看看如何使用这两形式,在配置上有什么区别: 1. @Value("#{configProperties['t1.msgname']}")这种形式的配置中有"configProperties",其实它指定的是配置文件的加载对

  • Spring4如何自定义@Value功能详解

    前言 本文主要给大家介绍了关于Spring4自定义@Value功能的相关内容,使用的Spring版本4.3.10.RELEASE,下面话不多说了,来一起看看详细的介绍吧. @Value在Spring中,功能非常强大,可以注入一个配置项,可以引用容器中的Bean(调用其方法),也可以做一些简单的运算 如下的一个简单demo,演示@Value的用法 import org.springframework.stereotype.Service; /** * 测试Bean */ @Service("use

  • Java 自定义Spring框架与核心功能详解

    目录 Spring核心功能结构 核心容器 spring-beans和spring-core模块 spring-context模块 spring-context-support模块 spring-context-indexer模块 spring-expression模块 AOP和设备支持 数据访问与集成 Web组件 通信报文 集成测试 bean概述 在上一讲中,我们对Spring的基本使用进行了一个简单的回顾,接下来,我们就来看一下Spring核心功能结构. Spring核心功能结构 Spring

  • Angularjs自定义指令Directive详解

    今天学习angularjs自定义指令Directive. Directive是一个非常棒的功能.可以实现我们自义的的功能方法. 下面的例子是演示用户在文本框输入的帐号是否为管理员的帐号"Admin". 在网页上放一个文本框和一个铵钮: <form id="form1" name="form1" ng-app="app" ng-controller="ctrl" novalidate> <i

  • Kotlin之自定义 Live Templates详解(模板代码)

    想必大家都知道 android studio 的 live templates 功能,那真是各种方便,比如你想使用 newInstance 去生成一个类的实例: 简直不要太方便! 当今 kotlin 流行起来了,你在使用 kotlin 开发 android 的时候,是不是发现以前用的 logt.loge.newinstance-,这些快捷创建代码片段的方式都不能用了,没关系,来一起自定义吧年轻人~ 打开 android studio >> File >> Settings ,搜索

  • C++头文件algorithm中的函数功能详解

    目录 1. 不修改内容的序列操作 (1)all_of (2)any_of (3)none_of (6)find_if (7)find_if_not (8)find_end (10)adjacent_find (12)count_if (15)is_permutation (16)search 2. 修改内容的序列操作 (1)copy (2)copy_n (3)copy_if (4)copy_backward (5)move (6)move_backward (7)swap (8)swap_ran

  • PyQt5实现数据的增删改查功能详解

    通过这个布局思路来做一个简单的后台管理系统也是OK的,大家可以参考一下啦! 话不多说,还是先来梳理一下需要的第三方模块. PyQ5 的UI界面布局部分,同样是还是使用这三个模块就够了. from PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5.QtCore import * 将sys模块导入到代码块中,用于main函数里面的主体循环时使用. import sys add_dialog是一个自己写的添加数据的弹框. fro

  • 使用IOS AirPrint实现打印功能详解

    内容 1.什么是AirPrint 其实就是将iOS(iphone,ipad)上的内容,使用支持AirPrint的打印机打印出来.打印过程无线控制, 非常方便. 2.第一手资料 学习iOS, 第一手资料肯定非苹果官方文档莫属. here. (我下面叙述的内容基本上是对文档的总结, 英语可以的建议直接看文档...) 3.Printer Simulator,使用打印模拟器进行测试 既然涉及打印功能,那么就需要有一台支持AirPrint 功能的打印机进行测试喽,你没有?没关系!苹果已经为我们准备好了模拟

  • Go语言利用接口实现链表插入功能详解

    目录 1. 接口定义 1.1 空接口 1.2 实现单一接口 1.3 接口多方法实现 2. 多态 2.1 为不同数据类型的实体提供统一的接口 2.2 多接口的实现 3. 系统接口调用 4. 接口嵌套 5. 类型断言 5.1 断言判断 5.2 多类型判断 6. 使用接口实现链表插入 1. 接口定义 Interface 类型可以定义一组方法,不需要实现,并且不能包含任何的变量,称之为接口 接口不需要显示的实现,只需要一个变量,含有接口类型中的所有方法,那么这个变量就实现了这个接口,如果一个变量含有多个

  • 代号为Naruto的Vue 2.7正式发布功能详解

    目录 引言 向后移植的功能 注意事项 与 Vue 3 的行为差异 升级指南 Vue CLI / webpack Vite Volar 兼容性 Devtools 支持 2.7 版本的影响 额外细节 引言 Vue 正式发布了 2.7 版本, 版本名称为 Naruto,即火影忍者. 尽管现在 Vue 3 是默认版本,但由于仍有许多用户由于依赖兼容性.浏览器支持要求或没有足够的带宽升级而不得不继续使用 Vue 2.在 Vue 2.7 中,从 Vue 3 向后移植了一些最重要的功能,以便 Vue 2 用户

  • MyBatis-Plus实现公共字段自动填充功能详解

    目录 1.问题分析 2.实现步骤 3. 实现字段全局填充 1.问题分析 我们在开发中经常遇到多个实体类有共同的属性字段,例如在用户注册时需要设置创建时间.创建人.修改时间.修改人等字段,在用户编辑信息时需要设置修改时间和修改人等字段.这些字段属于公共字段,也就是很多表中都有这些字段,能不能对于这些公共字段在某个地方统一处理,来简化开发呢? 答案就是我们可是使用Mybatis Plus提供的公共字段自动填充功能. 2.实现步骤 Mybatis Plus公共字段自动填充,也就是在插入或者更新的时候为

随机推荐