quote
Preface
This article mainly introduces the relevant content about Spring4's custom @Value function, using Spring version 4.3.10.RELEASE, I won't say much more, let's take a look at the detailed introduction.
@Value is very powerful in Spring. It can inject a configuration item, refer to the bean in the container (call its method), or do some simple operations. The
following simple demo demonstrates the usage of @Value
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import org.springframework.stereotype.Service;
/**
* Test 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
39
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class AppRunner implements InitializingBean {
/**
* Refers to a configuration item
*/
@Value("${app.port}")
private int port;
/**
* Call a bean method of the container to get the value
*/
@Value("#{userService.count()}")
private int userCount;
/**
* Call the method of a bean of the container, and pass in the value of a configuration item as a parameter
*/
@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
?
1
2
3
app.port=9090
app.size=3
?
1
2
3
4
5
6
7
8
9
10
11
12
13
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();
}
}
run, output result
port : 9090
userCount : 10
max : 10
min : 3
The general usage is like this, for injecting a value.
So, can it be done, given an expression or a specific value, it can help to calculate the value of the expression? That is, what about implementing a @Value function?
The method is as follows:
?
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
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();
/**
* Parse an expression and get a value
* @param beanFactory
* @param value A fixed value or an expression. If it is a fixed value, return the fixed value directly, otherwise resolve an expression and return the resolved 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();
}
} The
output of running is as follows:
1121
9090
10
10
3
It is found that the function of @Value has been implemented
Finally , some people may have doubts, what is the use of this? Wouldn't it be bad for me to just use @Value?
For most scenarios, you can indeed use @Value directly. However, in some special cases, @Value cannot do it.
For example , we define an annotation
?
1
2
3
4
5
@Retention(RUNTIME)
@Target(TYPE)
public @interface Job {
String cron();
}
This annotation requires a cron The expression, our requirement is that the user can directly use a cron expression, or can support a configuration item (configure the value into the configuration file)
For example
?
1
2
@Job(cron = "0 0 12 * * ?")
@Job(cron = "${app.job.cron}")
@Value can't do this, but you can use me above solution.