在spring中基于属性文件创建bean列表
我想在spring中创建基于属性文件的bean列表。为了说明这个问题,让我们假设我有一个在spring中基于属性文件创建bean列表,spring,properties,Spring,Properties,我想在spring中创建基于属性文件的bean列表。为了说明这个问题,让我们假设我有一个教室 public class ClassRoom { private List<Student> students; public void setStudents(List<Student> students) { this.students = students; } } public class Student { private Strign
教室
public class ClassRoom {
private List<Student> students;
public void setStudents(List<Student> students) {
this.students = students;
}
}
public class Student {
private Strign firstName;
private String lastName;
/* cosntructor, setters, getters ... */
}
还有一些很好的实用程序,可以将这样的文件转换成我的学生
类的列表
到目前为止,我已经为我的spring配置中包含的学生列表创建了单独的.xml配置文件,但我并不特别喜欢向客户机提供部分xml配置的想法。我认为这应该分开
所以问题是:有没有冷泉实用程序可以为我做到这一点?还是由我来写 所以我决定证明我没有那么懒。该解决方案有一些明显的限制,如1级属性或只能对基本类型进行操作。但是满足了我的需要。因此,作为记录: 属性文件:
student.1.firstName=Jan
student.1.lastName=Zyka
student.1.age=30
student.2.firstName=David
student.2.lastName=Kalita
student.2.age=55
学生班级:
package com.jan.zyka.test.dao;
public class Student {
private String firstName;
private String lastName;
private int age;
private String common;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getCommon() {
return common;
}
public void setCommon(String common) {
this.common = common;
}
@Override
public String toString() {
return "Student{" +
"firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", age=" + age +
", common='" + common + '\'' +
'}';
}
}
弹簧定义:
<bean id="studentFactory" class="com.jan.zyka.test.BeanListFactory">
<property name="propertyPrefix" value="student" />
<property name="commonProperties">
<map>
<entry key="common" value="testCommonValue" />
</map>
</property>
<property name="targetType">
<value type="java.lang.Class">com.jan.zyka.test.dao.Student</value>
</property>
<property name="properties">
<util:properties location="classpath:testListFactory.properties" />
</property>
</bean>
工厂bean本身:
package com.jan.zyka.test;
import com.google.common.primitives.Primitives;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.FactoryBean;
import java.beans.PropertyDescriptor;
import java.util.*;
/**
* <p>
* Creates list of beans based on property file.
* </p>
* <p>
* Each object should be defined in the property file as follows:
* <pre>
* <prefix>.<index>.<property>
* </pre>
*
* So one example might be:
* <pre>
* student.1.firstName=Paul
* student.1.lastName=Verlaine
* student.2.firstName=Alex
* student.2.lastName=Hamburger
* </pre>
*
* The target class must provide default constructor and setter for each property defined in the configuration file as per
* bean specification.
* </p>
*
* @param <T> type of the target object
*/
public class BeanListFactory<T> implements FactoryBean<List<T>> {
private String propertyPrefix;
private Map<String, Object> commonProperties = Collections.emptyMap();
private Class<T> targetType;
private Properties properties;
private List<T> loadedBeans;
public String getPropertyPrefix() {
return propertyPrefix;
}
public void setPropertyPrefix(String propertyPrefix) {
this.propertyPrefix = propertyPrefix;
}
public Map<String, Object> getCommonProperties() {
return commonProperties;
}
public void setCommonProperties(Map<String, Object> commonProperties) {
this.commonProperties = commonProperties;
}
public Class<T> getTargetType() {
return targetType;
}
public void setTargetType(Class<T> targetType) {
this.targetType = targetType;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public List<T> getObject() throws Exception {
loadedBeans = new ArrayList<T>();
int lastIndex = -1;
T item = null;
for (String property: prefixFilteredProperties()) {
// The actual value
final String propertyValue = properties.getProperty(property);
// Remove Prefix
property = property.substring(propertyPrefix.length() + 1);
// Split by "."
String tokens[] = property.split("\\.");
if (tokens.length != 2) {
throw new IllegalArgumentException("Each list property must be in form of: <prefix>.<index>.<property name>");
}
final int index = Integer.valueOf(tokens[0]);
final String propertyName = tokens[1];
// New index
if (lastIndex != index) {
if (lastIndex !=-1) {
loadedBeans.add(item);
}
lastIndex = index;
item = targetType.newInstance();
setCommonProperties(item, commonProperties);
}
// Set the property
setProperty(item, propertyName, convertIfNecessary(propertyName, propertyValue));
}
// Add last item
if (lastIndex != -1) {
loadedBeans.add(item);
}
return loadedBeans;
}
@Override
public Class<?> getObjectType() {
return ArrayList.class;
}
@Override
public boolean isSingleton() {
return false;
}
private Object convertIfNecessary(String propertyName, String propertyValue) throws Exception {
PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(targetType, propertyName);
Class<?> propertyType = Primitives.wrap(descriptor.getPropertyType());
if (propertyType == String.class) {
return propertyValue;
}
return propertyType.getDeclaredMethod("valueOf", String.class).invoke(propertyType, propertyValue);
}
private Set<String> prefixFilteredProperties() {
Set<String> filteredProperties = new TreeSet<String>();
for (String propertyName: properties.stringPropertyNames()) {
if (propertyName.startsWith(this.propertyPrefix)) {
filteredProperties.add(propertyName);
}
}
return filteredProperties;
}
private void setCommonProperties(T item, Map<String, Object> commonProperties) throws Exception {
for (Map.Entry<String, Object> commonProperty: commonProperties.entrySet()) {
setProperty(item, commonProperty.getKey(), commonProperty.getValue());
}
}
private static void setProperty(Object item, String propertyName, Object value) throws Exception {
PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(item.getClass(), propertyName);
descriptor.getWriteMethod().invoke(item, value);
}
}
package com.jan.zyka.test;
导入com.google.common.primitives.primitives;
导入org.springframework.beans.BeanUtils;
导入org.springframework.beans.factory.FactoryBean;
导入java.beans.PropertyDescriptor;
导入java.util.*;
/**
*
*基于属性文件创建bean列表。
*
*
*每个对象应在属性文件中定义如下:
*
*prefix.index.property
*
*
*因此,一个例子可能是:
*
*学生1.名字=保罗
*学生1.姓氏=Verlaine
*学生2.名字=亚历克斯
*学生2.姓氏=汉堡包
*
*
*根据,目标类必须为配置文件中定义的每个属性提供默认构造函数和setter
*bean规范。
*
*
*@param目标对象的类型
*/
公共类BeanListFactory实现FactoryBean{
私有字符串propertyPrefix;
私有映射commonProperties=Collections.emptyMap();
私有类targetType;
私人物业;;
私有列表加载bean;
公共字符串getPropertyPrefix(){
返回propertyPrefix;
}
公共void setPropertyPrefix(字符串propertyPrefix){
this.propertyPrefix=propertyPrefix;
}
公共映射getCommonProperties(){
归还公共财产;
}
公共void setCommonProperties(映射commonProperties){
this.commonProperties=commonProperties;
}
公共类getTargetType(){
返回目标类型;
}
public void setTargetType(targetType类){
this.targetType=targetType;
}
公共属性getProperties(){
归还财产;
}
公共void集合属性(属性){
这个。属性=属性;
}
@凌驾
公共列表getObject()引发异常{
loadedBeans=newArrayList();
int lastIndex=-1;
T项=null;
for(字符串属性:prefixFilteredProperties()){
//实际值
最后一个字符串propertyValue=properties.getProperty(property);
//删除前缀
property=property.substring(propertyPrefix.length()+1);
//以“.”分割
字符串标记[]=property.split(“\\”);
if(tokens.length!=2){
抛出新的IllegalArgumentException(“每个列表属性的格式必须为:…);
}
final int index=Integer.valueOf(令牌[0]);
最终字符串propertyName=tokens[1];
//新索引
if(lastIndex!=索引){
如果(lastIndex!=-1){
loadedBeans.add(项);
}
lastIndex=指数;
item=targetType.newInstance();
setCommonProperties(项目,commonProperties);
}
//设置属性
setProperty(item、propertyName、ConvertifEssential(propertyName、propertyValue));
}
//添加最后一项
如果(lastIndex!=-1){
loadedBeans.add(项);
}
返回加载的bean;
}
@凌驾
公共类getObjectType(){
返回ArrayList.class;
}
@凌驾
公共布尔isSingleton(){
返回false;
}
私有对象ConvertifEssential(String propertyName、String propertyValue)引发异常{
PropertyDescriptor描述符=BeanUtils.getPropertyDescriptor(targetType,propertyName);
类propertyType=Primitives.wrap(descriptor.getPropertyType());
if(propertyType==String.class){
返回属性值;
}
返回propertyType.getDeclaredMethod(“valueOf”,String.class).invoke(propertyType,propertyValue);
}
专用集prefixFilteredProperties(){
Set filteredProperties=new TreeSet();
对于(String propertyName:properties.stringPropertyNames()){
if(propertyName.startsWith(this.propertyPrefix)){
filteredProperties.add(propertyName);
}
}
返回过滤器属性;
}
私有void setCommonProperties(T项,映射commonProperties)引发异常{
对于(Map.Entry commonProperty:commonProperties.entrySet()){
setProperty(item,commonProperty.getKey(),commonProperty.getValue());
}
}
私有静态void setProperty(对象项、字符串propertyName、对象值)引发异常{
PropertyDescriptor描述符=BeanUtils.getPropertyDescriptor(item.getClass(),propertyName);
descriptor.getWriteMethod().invoke(项,值);
}
}
发布这个针对Spring Boot的解决方案,希望能帮助其他仍在寻找答案的人。使用spring可以将属性文件映射到bean列表。您需要有一个包含bean集合的ConfigurationProperties bean,并使用适当的命名约定,如下所示
调查
<bean id="studentFactory" class="com.jan.zyka.test.BeanListFactory">
<property name="propertyPrefix" value="student" />
<property name="commonProperties">
<map>
<entry key="common" value="testCommonValue" />
</map>
</property>
<property name="targetType">
<value type="java.lang.Class">com.jan.zyka.test.dao.Student</value>
</property>
<property name="properties">
<util:properties location="classpath:testListFactory.properties" />
</property>
</bean>
[
Student{firstName='Jan', lastName='Zyka', age=30, common='testCommonValue'},
Student{firstName='David', lastName='Kalita', age=55, common='testCommonValue'}
]
package com.jan.zyka.test;
import com.google.common.primitives.Primitives;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.FactoryBean;
import java.beans.PropertyDescriptor;
import java.util.*;
/**
* <p>
* Creates list of beans based on property file.
* </p>
* <p>
* Each object should be defined in the property file as follows:
* <pre>
* <prefix>.<index>.<property>
* </pre>
*
* So one example might be:
* <pre>
* student.1.firstName=Paul
* student.1.lastName=Verlaine
* student.2.firstName=Alex
* student.2.lastName=Hamburger
* </pre>
*
* The target class must provide default constructor and setter for each property defined in the configuration file as per
* bean specification.
* </p>
*
* @param <T> type of the target object
*/
public class BeanListFactory<T> implements FactoryBean<List<T>> {
private String propertyPrefix;
private Map<String, Object> commonProperties = Collections.emptyMap();
private Class<T> targetType;
private Properties properties;
private List<T> loadedBeans;
public String getPropertyPrefix() {
return propertyPrefix;
}
public void setPropertyPrefix(String propertyPrefix) {
this.propertyPrefix = propertyPrefix;
}
public Map<String, Object> getCommonProperties() {
return commonProperties;
}
public void setCommonProperties(Map<String, Object> commonProperties) {
this.commonProperties = commonProperties;
}
public Class<T> getTargetType() {
return targetType;
}
public void setTargetType(Class<T> targetType) {
this.targetType = targetType;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public List<T> getObject() throws Exception {
loadedBeans = new ArrayList<T>();
int lastIndex = -1;
T item = null;
for (String property: prefixFilteredProperties()) {
// The actual value
final String propertyValue = properties.getProperty(property);
// Remove Prefix
property = property.substring(propertyPrefix.length() + 1);
// Split by "."
String tokens[] = property.split("\\.");
if (tokens.length != 2) {
throw new IllegalArgumentException("Each list property must be in form of: <prefix>.<index>.<property name>");
}
final int index = Integer.valueOf(tokens[0]);
final String propertyName = tokens[1];
// New index
if (lastIndex != index) {
if (lastIndex !=-1) {
loadedBeans.add(item);
}
lastIndex = index;
item = targetType.newInstance();
setCommonProperties(item, commonProperties);
}
// Set the property
setProperty(item, propertyName, convertIfNecessary(propertyName, propertyValue));
}
// Add last item
if (lastIndex != -1) {
loadedBeans.add(item);
}
return loadedBeans;
}
@Override
public Class<?> getObjectType() {
return ArrayList.class;
}
@Override
public boolean isSingleton() {
return false;
}
private Object convertIfNecessary(String propertyName, String propertyValue) throws Exception {
PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(targetType, propertyName);
Class<?> propertyType = Primitives.wrap(descriptor.getPropertyType());
if (propertyType == String.class) {
return propertyValue;
}
return propertyType.getDeclaredMethod("valueOf", String.class).invoke(propertyType, propertyValue);
}
private Set<String> prefixFilteredProperties() {
Set<String> filteredProperties = new TreeSet<String>();
for (String propertyName: properties.stringPropertyNames()) {
if (propertyName.startsWith(this.propertyPrefix)) {
filteredProperties.add(propertyName);
}
}
return filteredProperties;
}
private void setCommonProperties(T item, Map<String, Object> commonProperties) throws Exception {
for (Map.Entry<String, Object> commonProperty: commonProperties.entrySet()) {
setProperty(item, commonProperty.getKey(), commonProperty.getValue());
}
}
private static void setProperty(Object item, String propertyName, Object value) throws Exception {
PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(item.getClass(), propertyName);
descriptor.getWriteMethod().invoke(item, value);
}
}
@Component
@ConfigurationProperties(prefix = "notification")
@Data
@Valid
public class NotificationProperties {
@NotNull
private Set<AlertThreshold> alertThresholds;
@NotNull
private Set<Subscriber> subscribers;
}
notification.alert-thresholds[0].step=PB
notification.alert-thresholds[0].status=RDY
notification.alert-thresholds[0].threshold=500
notification.alert-thresholds[1].step=LA
notification.alert-thresholds[1].status=RDY
notification.alert-thresholds[1].threshold=100
notification.subscribers[0].email=subscriber1@gmail.com
notification.subscribers[1].email=subscriber2@gmail.com
@Data
public class AlertThreshold {
@NotNull
private String step;
@NotNull
private String status;
@NotNull
private Integer threshold;
}
@Data
public class Subscriber {
@Email
private String email;
}