Spring Framework之自定义属性编辑器
什么是spring属性编辑器?
简单点,就是在属性注入的时候,能够将配置的String类型转为bean属性真正的类型。
例如在spring的xml配置文件中配置
<bean id="sqlSessionFactorybbcbaseshop" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis/mybatis-sql.xml"></property>
<property name="dataSource" ref="dataSourceA"></property>
</bean>
这里配置的configLocation
看起来是个地址,是字符串类型,但是在SqlSessionFactoryBean
中是Resource
类型
private Resource configLocation;
然后进行一系列操作并不会报错,是因为spring内部有个默认的属性编辑器ResourceEditor
将属性转换了
xmlConfigBuilder = new XMLConfigBuilder(configLocation.getInputStream(), null, configurationProperties);
configuration = xmlConfigBuilder.getConfiguration();
ResourceEditor属性编辑器
public class ResourceEditor extends PropertyEditorSupport {
private final ResourceLoader resourceLoader;
@Nullable
private PropertyResolver propertyResolver;
private final boolean ignoreUnresolvablePlaceholders;
public ResourceEditor() {
this(new DefaultResourceLoader(), (PropertyResolver)null);
}
public ResourceEditor(ResourceLoader resourceLoader, @Nullable PropertyResolver propertyResolver) {
this(resourceLoader, propertyResolver, true);
}
public ResourceEditor(ResourceLoader resourceLoader, @Nullable PropertyResolver propertyResolver, boolean ignoreUnresolvablePlaceholders) {
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
this.resourceLoader = resourceLoader;
this.propertyResolver = propertyResolver;
this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
}
public void setAsText(String text) {
if (StringUtils.hasText(text)) {
String locationToUse = this.resolvePath(text).trim();
this.setValue(this.resourceLoader.getResource(locationToUse));
} else {
this.setValue((Object)null);
}
}
protected String resolvePath(String path) {
if (this.propertyResolver == null) {
this.propertyResolver = new StandardEnvironment();
}
return this.ignoreUnresolvablePlaceholders ? this.propertyResolver.resolvePlaceholders(path) : this.propertyResolver.resolveRequiredPlaceholders(path);
}
@Nullable
public String getAsText() {
Resource value = (Resource)this.getValue();
try {
return value != null ? value.getURL().toExternalForm() : "";
} catch (IOException var3) {
return null;
}
}
}
重点关注setAsText(String text)
方法,实现了属性转换。
自定义属性编辑器
自定义日期转换属性编辑器
仿照ResourceEditor
一样,继承PropertyEditorSupport
接口,主要重写getAsText()
与setAsText(String text)
方法
public class MyDateEditor extends PropertyEditorSupport {
private List<SimpleDateFormat> list;
{
list = new ArrayList<SimpleDateFormat>();
list.add(new SimpleDateFormat("yyyy-MM-dd"));
list.add(new SimpleDateFormat("yyyy年MM月dd日"));
}
public String getAsText() {
return getValue().toString();
}
public List<SimpleDateFormat> getList() {
return list;
}
public void setList(List<SimpleDateFormat> list) {
this.list = list;
}
public void setAsText(String text) throws IllegalArgumentException {
for (SimpleDateFormat format : list) {
try {
Date date = format.parse(text);
setValue(date);
return;
} catch (ParseException e) {
}
}
throw new RuntimeException("无法转换");
}
}
CustomEditorConfigurer添加自定义属性编辑器
在容器中,属性编辑器有两种存放方式
private final Set<PropertyEditorRegistrar> propertyEditorRegistrars = new LinkedHashSet(4);
private final Map<Class<?>, Class<? extends PropertyEditor>> customEditors = new HashMap(4);
从spring加载流程知道,spring内部默认的属性编辑器放在propertyEditorRegistrars
spring内部默认的属性编辑器
我们自定义的话,可以通过CustomEditorConfigurer
(它是一个BeanFactoryPostProcessor),它会将属性编辑器放入customEditors
public class CustomEditorConfigurer implements BeanFactoryPostProcessor, Ordered {
protected final Log logger = LogFactory.getLog(this.getClass());
private int order = 2147483647;
@Nullable
private PropertyEditorRegistrar[] propertyEditorRegistrars;
@Nullable
private Map<Class<?>, Class<? extends PropertyEditor>> customEditors;
public CustomEditorConfigurer() {
}
public void setOrder(int order) {
this.order = order;
}
public int getOrder() {
return this.order;
}
public void setPropertyEditorRegistrars(PropertyEditorRegistrar[] propertyEditorRegistrars) {
this.propertyEditorRegistrars = propertyEditorRegistrars;
}
public void setCustomEditors(Map<Class<?>, Class<? extends PropertyEditor>> customEditors) {
this.customEditors = customEditors;
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (this.propertyEditorRegistrars != null) {
PropertyEditorRegistrar[] var2 = this.propertyEditorRegistrars;
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
PropertyEditorRegistrar propertyEditorRegistrar = var2[var4];
beanFactory.addPropertyEditorRegistrar(propertyEditorRegistrar);
}
}
if (this.customEditors != null) {
this.customEditors.forEach(beanFactory::registerCustomEditor);
}
}
}
可以看到,在执行postProcessBeanFactory
时(spring执行BeanFactoryPostProcessor),会分别判断属性propertyEditorRegistrars
与customEditors
,进而添加属性编辑器。这里实现第二种方式,对customEditors
属性赋值
配置类MyConfig
@Bean
public CustomEditorConfigurer customEditorConfigurer(){
CustomEditorConfigurer configurer = new CustomEditorConfigurer();
Map<Class<?>, Class<? extends PropertyEditor>> customEditors = new HashMap<>();
// 参数1:转化后的类型,参数2:属性转换器
customEditors.put(Date.class, MyDateEditor.class);
configurer.setCustomEditors(customEditors);
return configurer;
}
属性转换测试
@Component
public class User {
@Value("浴缸")
private String name;
@Value("9")
private Integer id;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Value("2019年03月11日")
private Date date;
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", date=" + date +
'}';
}
public User(String name, Integer id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public User() {
}
}
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(MyConfig.class);
User user = context.getBean(User.class);
System.out.println(user.toString());
打印
User{name='浴缸', id=9, date=Mon Mar 11 00:00:00 CST 2019}