Spring4 How to customize @ES1en function details
- 2020-10-23 20:57:25
- OfStack
preface
This article mainly introduces the Spring4 custom @Value function. The Spring version 4.3.10.RELEASE is used. Let's start with the detailed introduction.
In Spring, @ES9en is very powerful. You can inject 1 configuration item, refer to Bean in the container (calling its methods), or do 1 simple operation
Here is a simple demo to demonstrate the use of @Value
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;
}
}
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class AppRunner implements InitializingBean {
/**
* reference 1 A configuration item
*/
@Value("${app.port}")
private int port;
/**
* Calling the container's 1 a bean Method to get the value
*/
@Value("#{userService.count()}")
private int userCount;
/**
* Calling the container's 1 a bean , and passed in 1 Values of the configuration items as parameters
*/
@Value("#{userService.max(${app.size})}")
private int max;
/**
* Simple operation
*/
@Value("#{${app.size} <= '12345'.length() ? ${app.size} : '12345'.length()}")
private int min;
// test
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();
}
}
Run, output the result
port : 9090
userCount : 10
max : 10
min : 3
This is the 1-like usage for injecting 1 value.
So, can I do, given an expression or a specific value, that will help me evaluate the expression? In other words, how about one @Value?
The methods are as follows:
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();
/**
* parsing 1 An expression, get 1 A value
* @param beanFactory
* @param value 1 A fixed value or 1 It's an expression. If it is 1 Returns a fixed value, otherwise resolved 1 An expression that returns the parsed 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));
}
}
Specific USES are as follows:
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);
// To calculate 1 A specific value (non-expression)
System.out.println(ValueUtil.resolveExpression(context.getBeanFactory(), "1121"));
// implementation @Value The function of the
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 operation output is as follows:
1121
9090
10
10
3
We found that @Value has been implemented
And then finally, some of you might wonder, what's the use? Shouldn't I just use @Value?
For most scenarios, you do just use @Value. However, there are some special scenarios that @Value can't do
Let's say we define an annotation
@Retention(RUNTIME)
@Target(TYPE)
public @interface Job {
String cron();
}
This annotation requires an cron expression. The requirement is that the user can either use an cron expression directly or support a reference to a configuration item (configuring the value to a configuration file).
For instance
@Job(cron = "0 0 12 * * ?")
@Job(cron = "${app.job.cron}")
In this case @Value won't do it, but you can use my solution above.
conclusion