好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

spring 自定义让@Value被解析到

spring 自定义让@Value解析到

@Value 可以给字段赋值

背景

@Value通常与@PropertySource(value = [db.properties]) 组合使用读取配置注入参数,那如果我们的值是其它存储,如何才能自动赋值

实现原理

实现很简单

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

//自动注入此对象

  @Autowired

     private Environment environment;

     @PostConstruct

     public void init() {

       

        //拿到些对象

         MutablePropertySources propertySources = ((ConfigurableEnvironment) this .environment).getPropertySources();

         PropertySourceFactory factory = BeanUtils.instantiateClass(DefaultPropertySourceFactory. class );

         //构造pathResource

         PathResource pathResource = new PathResource( "/Users/xx/soft/sp.properties" );

         try {

             org.springframework.core.env.PropertySource<?> sd = factory.createPropertySource( "sd" , new EncodedResource(pathResource));

             //设置值

             propertySources.addFirst(sd);

         } catch (IOException e) {

             e.printStackTrace();

         }

     }

主要是通过代码得到PropertySource 这个对象,然后得到environment这个对象,设置值就可以了

Spring4自定义@Value功能

本文章使用的Spring版本4.3.10.RELEASE

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

如下的一个简单demo,

演示@Value的用法

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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;

  }

}

?

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

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

?

1

2

3

4

5

6

7

8

9

10

11

12

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的功能呢?

方法如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

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 ));

  }

}

具体使用如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

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做不了

比如说

我们定义一个注解

?

1

2

3

4

5

@Retention (RUNTIME)

@Target (TYPE)

public @interface Job {

  String cron();

}

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

比如说

?

1

2

@Job (cron = "0 0 12 * * ?" )

@Job (cron = "${app.job.cron}" )

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

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

原文链接:https://blog.csdn.net/qq_22222499/article/details/114682785

查看更多关于spring 自定义让@Value被解析到的详细内容...

  阅读:18次