Autowire Java 使用外部库中的 NewInstance 创建的 Bean
Autowire Java Bean created with NewInstance from an external library
我正在做一个 Spring 引导项目,并使用 OpenCSV 库将一些 csvs 解析为 POJO,以便持久保存到数据库中。
OpenCSV 使用注释 @CsvCustomBindByName
将 CSV 字段映射到 Java 对象。
converter = DepartmentConverter.class
是自定义转换器,实例化为:
Class<? extends AbstractBeanField<T,K>>.newInstance()
由图书馆在运行时提供。
问题是因为自定义字段转换器是由 OpenCSV 库反射实例化的,所以它不能自动装配 bean,因为它没有在 Spring 上下文中注册。
如何让动态实例化的转换器知道 Spring 上下文或相反。某种拦截器?谢谢!
//Spring Managed class
public class Specialization {
@CsvCustomBindByName(required = true, converter = DepartmentConverter.class)
private Department department;
....
}
在我的 DepartmentConverter 中,我需要使用 Spring JPARepository 来检索一些数据。 DepartmentRepository 无法自动装配。
@Component
public class DepartmentConverter extends AbstractBeanField<Department, String> {
@Autowired
private DepartmentRepository departmentRepository;
public DepartmentConverter() {
}
@Override protected Object convert(String val) throws CsvConstraintViolationException, ResourceNotFoundException {
//use departmentRepository
...
}
}
您所指的 newInstance()
调用在 HeaderColumnNameMappingStrategy
class 中,它调用 instantiateCustomConverter()
方法来执行 newInstance()
调用。
创建子class并覆盖方法:
@Override
protected BeanField<T, K> instantiateCustomConverter(Class<? extends AbstractBeanField<T, K>> converter) throws CsvBadConverterException {
BeanField<T, K> c = super.instantiateCustomConverter(converter);
// TODO autowire here
return c;
}
从 的回答中可以看出,您可以按如下方式进行自动装配:
autowireCapableBeanFactory.autowireBean(c);
所以子class会是这样的:
public class AutowiredConverterMappingStrategy extends HeaderColumnNameMappingStrategy {
private final AutowireCapableBeanFactory beanFactory;
public AutowiredConverterMappingStrategy(AutowireCapableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
protected BeanField<T, K> instantiateCustomConverter(Class<? extends AbstractBeanField<T, K>> converter) throws CsvBadConverterException {
BeanField<T, K> c = super.instantiateCustomConverter(converter);
this.beanFactory.autowireBean(c);
return c;
}
}
要使用它,您需要这样的东西:
@Component
class MyComponent {
@Autowired
private AutowireCapableBeanFactory beanFactory;
public <T> List<T> parseCsvToBean(Reader reader, Class<? extends T> type) {
return new CsvToBeanBuilder(reader)
.withType(type)
.withMappingStrategy(new AutowiredConverterMappingStrategy(this.beanFactory))
.build()
.parse();
}
}
这当然只是一个例子。您的 CsvToBean
设置可能更复杂,但关键部分是 withMappingStrategy()
调用,并且代码本身位于 Spring Bean 中,因此它可以访问 bean 工厂。
我正在做一个 Spring 引导项目,并使用 OpenCSV 库将一些 csvs 解析为 POJO,以便持久保存到数据库中。
OpenCSV 使用注释 @CsvCustomBindByName
将 CSV 字段映射到 Java 对象。
converter = DepartmentConverter.class
是自定义转换器,实例化为:
Class<? extends AbstractBeanField<T,K>>.newInstance()
由图书馆在运行时提供。
问题是因为自定义字段转换器是由 OpenCSV 库反射实例化的,所以它不能自动装配 bean,因为它没有在 Spring 上下文中注册。
如何让动态实例化的转换器知道 Spring 上下文或相反。某种拦截器?谢谢!
//Spring Managed class
public class Specialization {
@CsvCustomBindByName(required = true, converter = DepartmentConverter.class)
private Department department;
....
}
在我的 DepartmentConverter 中,我需要使用 Spring JPARepository 来检索一些数据。 DepartmentRepository 无法自动装配。
@Component
public class DepartmentConverter extends AbstractBeanField<Department, String> {
@Autowired
private DepartmentRepository departmentRepository;
public DepartmentConverter() {
}
@Override protected Object convert(String val) throws CsvConstraintViolationException, ResourceNotFoundException {
//use departmentRepository
...
}
}
您所指的 newInstance()
调用在 HeaderColumnNameMappingStrategy
class 中,它调用 instantiateCustomConverter()
方法来执行 newInstance()
调用。
创建子class并覆盖方法:
@Override
protected BeanField<T, K> instantiateCustomConverter(Class<? extends AbstractBeanField<T, K>> converter) throws CsvBadConverterException {
BeanField<T, K> c = super.instantiateCustomConverter(converter);
// TODO autowire here
return c;
}
从
autowireCapableBeanFactory.autowireBean(c);
所以子class会是这样的:
public class AutowiredConverterMappingStrategy extends HeaderColumnNameMappingStrategy {
private final AutowireCapableBeanFactory beanFactory;
public AutowiredConverterMappingStrategy(AutowireCapableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
protected BeanField<T, K> instantiateCustomConverter(Class<? extends AbstractBeanField<T, K>> converter) throws CsvBadConverterException {
BeanField<T, K> c = super.instantiateCustomConverter(converter);
this.beanFactory.autowireBean(c);
return c;
}
}
要使用它,您需要这样的东西:
@Component
class MyComponent {
@Autowired
private AutowireCapableBeanFactory beanFactory;
public <T> List<T> parseCsvToBean(Reader reader, Class<? extends T> type) {
return new CsvToBeanBuilder(reader)
.withType(type)
.withMappingStrategy(new AutowiredConverterMappingStrategy(this.beanFactory))
.build()
.parse();
}
}
这当然只是一个例子。您的 CsvToBean
设置可能更复杂,但关键部分是 withMappingStrategy()
调用,并且代码本身位于 Spring Bean 中,因此它可以访问 bean 工厂。