说一下思路,方法
@Value 注入参数数值
最基础的使用方式
@Value("${some.key:my default value}")
private String stringWithDefaultValue;
当然@value 还可以 注入List、Map等,可以看这里
https://www.baeldung.com/spring-value-annotation
如果想初始化带有一个pojo的map怎么办?比如给
HashMap<String, Student>
默认值
{"studentOne":{"age":"25","name":"老王"}}
我们创建的默认值是String,然后我们需要转成对应的类
创建类Student:
public class Student {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
我们需要引入 Spring类型转换(Converter)
可以看https://www.cnblogs.com/baka-sky/archive/2018/12/30/10200845.html 或者其他文章学习
创建两个转换类:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@Component
public class BeanGenericConverterConfig implements ConditionalGenericConverter {
private static final Logger LOGGER = LoggerFactory.getLogger(BeanGenericConverterConfig.class);
protected static final Set<ConvertiblePair> CONVERTIBLE_TYPES = new HashSet<>();
protected final ObjectMapper objectMapper;
/**
* Constructor.
*/
public BeanGenericConverterConfig() {
this.objectMapper = new ObjectMapper();
}
/**
* Add convertible types to this converter.
*
* @param set Set for convertible types.
*/
public void addConvertibleTypes(Set<ConvertiblePair> set) {
CONVERTIBLE_TYPES.addAll(set);
}
/**
* Get a set for convertible types.
*
* @return Set for convertible types.
*/
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return CONVERTIBLE_TYPES;
}
/**
* Determine whether object can be converted.
*
* @param sourceType Source type.
* @param targetType Target type.
* @return True if the type matches, otherwise false.
*/
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return CONVERTIBLE_TYPES.stream().anyMatch(p -> p.getTargetType() == targetType.getType());
}
/**
* Convert String to concrete bean instance.
*
* @param source Object to be converted.
* @param sourceType Source type.
* @param targetType Target type.
* @return Converted bean object.
*/
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
Object value = null;
try {
final Class<?> clazz = targetType.getType();
if (Map.class.isAssignableFrom(clazz) || Collection.class.isAssignableFrom(clazz)) {
value = convertContainerBean(source, targetType);
} else {
value = convertObjectBean(source, targetType);
}
} catch (Exception e) {
String exceptionMessage = "Failed to convert a bean for " + targetType.getResolvableType().toString();
LOGGER.error(exceptionMessage, e);
}
return value;
}
/**
* Convert object to concrete bean.
*
* @param source Source type.
* @param targetType Target type.
* @return Converted bean object.
* @throws IOException Exception during conversion.
*/
private Object convertObjectBean(Object source, TypeDescriptor targetType) throws IOException {
Class targetClazz = targetType.getResolvableType().getGenerics()[0].getRawClass();
return objectMapper.readValue(source.toString(), targetClazz);
}
/**
* Convert object to map or list bean.
*
* @param source Source type.
* @param targetType Target type.
* @return Converted bean object.
* @throws IOException Exception during conversion.
*/
private Object convertContainerBean(Object source, TypeDescriptor targetType) throws IOException {
return objectMapper.readValue(source.toString(),
TypeFactory.defaultInstance().constructFromCanonical(targetType.getResolvableType().toString()));
}
}
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair;
import org.springframework.core.convert.support.DefaultConversionService;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
@Configuration
public class BeanConverterConfig {
protected static final Set<ConvertiblePair> CONVERTIBLE_PAIRS = new HashSet<>();
/**
* Initialize the static variable CONVERTIBLE_PAIRS.
*/
static {
CONVERTIBLE_PAIRS.add(new ConvertiblePair(String.class, HashMap.class));
}
@Bean
public BeanFactoryPostProcessor coreBeanFactoryPostProcessor(BeanGenericConverterConfig converter) {
return beanFactory -> {
ConversionService conversionService = beanFactory.getConversionService();
if (conversionService == null) {
conversionService = DefaultConversionService.getSharedInstance();
beanFactory.setConversionService(conversionService);
}
converter.addConvertibleTypes(CONVERTIBLE_PAIRS);
((DefaultConversionService) conversionService).addConverter(converter);
};
}
}
这块大体是需要matches方法进行判断之后进行转换,如果你想直接转换Student单个对象,需要自己进行格外进行处理
@Value 具体源码
https://www.jianshu.com/p/933669270a9f
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
这块很重要。
创建ConfigService:
import com.example.demo.entity.Student;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
@Configuration
public class ConfigService {
@Value("${init.student}")
private HashMap<String, Student> student;
public HashMap<String, Student> getStudent() {
return student;
}
}
更新application.properties
init.student={"studentOne":{"age":"25","name":"老王"}}