autowire从外部库用newinstance创建的javabean

liwlm1x9  于 2021-06-29  发布在  Java
关注(0)|答案(1)|浏览(379)

我正在做一个springboot项目,并使用opencsv库将一些csv解析为pojo以持久化到db。
opencsv使用注解 @CsvCustomBindByName 将csv字段Map到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中,我需要使用springjparepository来检索一些数据。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
        ...
    }
}
vc6uscn9

vc6uscn91#

这个 newInstance() 你所指的电话在电话亭里 HeaderColumnNameMappingStrategy 类,它调用 instantiateCustomConverter() 方法来执行 newInstance() 打电话。
创建子类并重写方法:

@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;
}

正如在一个类新示例上对spring@autowired的回答中所看到的,您可以按如下方式进行自动连接:

autowireCapableBeanFactory.autowireBean(c);

所以子类应该是这样的:

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() 调用,并且代码本身在springbean中,因此它可以访问bean工厂。

相关问题