简体   繁体   English

Autowire Java 使用来自外部库的 NewInstance 创建的 Bean

[英]Autowire Java Bean created with NewInstance from an external library

I am doing a Spring Boot Project and using the OpenCSV library to parse some csvs into POJOs to be persisted to db.我正在做一个 Spring 引导项目并使用 OpenCSV 库将一些 csv 解析为 POJO 以持久保存到数据库。

OpenCSV uses the annotation @CsvCustomBindByName to map a CSV field to a Java object. OpenCSV 使用注释@CsvCustomBindByName到 map 一个 CSV 字段到一个 Java ZA8CFDE6331BD54B62ZF88119ZF81119。

The converter = DepartmentConverter.class is a custom converter that is instantiated with: converter = DepartmentConverter.class是一个自定义转换器,实例化为:

Class<? extends AbstractBeanField<T,K>>.newInstance() 

by the library, at runtime.由库,在运行时。

The problem is that because the custom field converter is instantiated reflectively by the OpenCSV library, it cant autowire beans because it is not registered in the Spring Context.问题是因为自定义字段转换器是由 OpenCSV 库反射实例化的,它不能自动装配 bean,因为它没有在 Spring 上下文中注册。

How can i make that dynamically instantiated converter be aware of the Spring context or the other way around.我怎样才能让动态实例化的转换器知道 Spring 上下文或其他方式。 Some kind of interceptor?某种拦截器? Thanks!谢谢!

//Spring Managed class
public class Specialization { 
   
    @CsvCustomBindByName(required = true, converter = DepartmentConverter.class)
    private Department department;
    
    ....
}

In my DepartmentConverter i need to use a Spring JPARepository to retrieve some data.在我的 DepartmentConverter 中,我需要使用 Spring JPARepository 来检索一些数据。 DepartmentRepository can not be autowired. 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
        ...
    }
}

The newInstance() call you're referring to is in the HeaderColumnNameMappingStrategy class, which calls the instantiateCustomConverter() method to do the newInstance() call.您所指的newInstance()调用位于HeaderColumnNameMappingStrategy class 中,它调用instantiateCustomConverter()方法来执行newInstance()调用。

Create a subclass and override the method:创建一个子类并覆盖该方法:

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

As can be seen in this answer to Spring @Autowired on a class new instance , you can do the autowiring as follows:Spring @Autowired on a class new instance 的答案中可以看出,您可以按如下方式进行自动装配:

autowireCapableBeanFactory.autowireBean(c);

So the subclass would be something like:所以子类会是这样的:

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

To use it, you'd need something like this:要使用它,你需要这样的东西:

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

That is of course just an example.这当然只是一个例子。 Your CsvToBean setup may be more complex, but the key part is the withMappingStrategy() call, and that the code is itself in a Spring Bean, so it has access to the bean factory.您的CsvToBean设置可能更复杂,但关键部分是withMappingStrategy()调用,并且代码本身位于 Spring Bean 中,因此它可以访问 bean 工厂。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM