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就做不到,但是,可以用我上面的解决方案。

总结

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

时间: 2017-09-03

详解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",其实它指定的是配置文件的加载对

Spring中常用注解的详细介绍

spring中使用注解时配置文件的写法: <?xml version="1.0" encoding="UTF-8"?> <span style="font-size:18px;"><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-in

Spring中@Async注解执行异步任务的方法

引言 在业务处理中,有些业务使用异步的方式更为合理.比如在某个业务逻辑中,把一些数据存入到redis缓存中,缓存只是一个辅助的功能,成功或者失败对主业务并不会产生根本影响,这个过程可以通过异步的方法去进行. Spring中通过在方法上设置@Async注解,可使得方法被异步调用.也就是说该方法会在调用时立即返回,而这个方法的实际执行交给Spring的TaskExecutor去完成. 代码示例 项目是一个普通的Spring的项目,Spring的配置文件: <?xml version="1.0&

spring中AOP 注解开发示例详解

一.简介 AOP主要包含了通知.切点和连接点等术语,介绍如下: 通知(advice) 通知定义了切面是什么以及何时调用,何时调用包含以下几种 Before 在方法被调用之前调用通知 After 在方法完成之后调用通知,无论方法执行是否成功 After-returning 在方法成功执行之后调用通知 After-throwing 在方法抛出异常后调用通知 Around 通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为 切点(PointCut) 通知定义了切面的什么和何时,切

Spring boot中PropertySource注解的使用方法详解

前言 本文将重点讲解一下Spring中@PropertySource注解的使用,如何通过PropertySource注解加载指定的配置文件.以及PropertySource注解与@ConfigurationProperties两个注解的配合使用.下面话不多说了,来随着小编来一起学习学习吧. 1.1. PropertySource注解加载指定的属性文件 Spring框架提供了PropertySource注解,目的是加载指定的属性文件,接下来我们看一下如何使用该注解.首先我们定义一个配置类,并在类中

快速理解spring中的各种注解

Spring中的注解大概可以分为两大类: 1)spring的bean容器相关的注解,或者说bean工厂相关的注解: 2)springmvc相关的注解. spring的bean容器相关的注解,先后有:@Required, @Autowired, @PostConstruct, @PreDestory,还有Spring3.0开始支持的JSR-330标准javax.inject.*中的注解(@Inject, @Named, @Qualifier, @Provider, @Scope, @Singlet

关于spring中定时器的使用教程

前言 在很多实际的web应用中,都有需要定时实现的服务,如每天12点推送个新闻,每隔一个小时提醒用户休息一下眼睛,隔一段时间检测用户是否离线等等. spring框架提供了对定时器的支持,通过配置文件就可以很好的实现定时器,只需要应用启动,就自动启动定时器.下面介绍一下具体做法. 第一种,使用XML配置的方法 前期工作,配置spring的开发环境(这里用到了spring的web应用包,需要导入) 首先创建定时器的任务类,定时器要做什么工作,就在这里写什么方法. package org.time;

spring AOP自定义注解方式实现日志管理的实例讲解

今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在applicationContext-mvc.xml中要添加的 <mvc:annotation-driven /> <!-- 激活组件扫描功能,在包com.gcx及其子包下面自动扫描通过注解配置的组件 --> <context:component-scan base-package=&qu

详解Java的Spring框架中的注解的用法

1. 使用Spring注解来注入属性 1.1. 使用注解以前我们是怎样注入属性的 类的实现: class UserManagerImpl implements UserManager { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } ... } 配置文件: <bean id="userManagerImpl" class="com.

Spring 中 @Service 和 @Resource 注解的区别

Spring 中 @Service 和 @Resource 注解的区别 1 前言 在咱们使用 spring 框架的时候,注解是"不可或缺"的一部分,她帮我们脱离了配置繁琐的 XML 文件的工作,但有一点却需要我们自己去把握,那就是"3何",即"何时何地用何注解?"在本篇博文中,作者就简单介绍一下如何恰当的使用 @Service 和 @Resource 这两个注解. 2 注解 2.1 @Service 当咱们需要定义某个类为一个 bean 的时候,