简体   繁体   English

与Spring Batch阅读器结合使用时无法调用@PostConstruct

[英]@PostConstruct fails to be called when combined with Spring Batch readers

I've been trying to implement @PostConstruct and @PreDestroy methods in an Account class of mine. 我一直在尝试在我的Account类中实现@PostConstruct@PreDestroy方法。 Neither of them worked in the following situation, but for the sake of brevity, I'll only talk about @PostConstruct . 他们都不在以下情况下工作,但是为了简洁起见,我只谈论@PostConstruct

I'm using Spring Batch's readers to load these accounts from a fixed-length file. 我正在使用Spring Batch的阅读器从固定长度的文件加载这些帐户。 So far, so good, except when my reader creates these accounts, it apparently does not call the @PostConstruct method (debug breakpoints are never activated, and log messages are not printed out). 到目前为止,一切都很好,除非我的读者创建了这些帐户,否则它显然不会调用@PostConstruct方法(永远不会激活调试断点,并且不会输出日志消息)。
The reader is only custom in the sense that it's a custom class extending FlatFileItemReader<Account> and setting values in the constructor. 读者是自定义的,这是因为它是扩展FlatFileItemReader<Account>并在构造函数中设置值的自定义类。

Adding the exact same initialization method (that never got called in the Account class) to the reader itself works just fine. 将完全相同的初始化方法(在Account类中从未调用过)添加到读取器本身即可正常工作。
Ie if the @PostConstruct method should be called upon reader initialization, it works. 即,如果应该在读取器初始化时调用@PostConstruct方法,它将起作用。 Just not when the reader itself initializes accounts annotated with @PostConstruct . 只是当读者自己初始化带有@PostConstruct注释的帐户时,才不会。

If I add a breakpoint or log message in the constructor of Account directly, it also works without an issue. 如果直接在Account的构造函数中添加断点或日志消息,它也可以正常工作。


Is this desired behaviour by Spring Batch? 这是Spring Batch的理想行为吗? Or could this be caused by any configuration of mine? 还是这可能是由我的任何配置引起的?

Another question's answer mentioned that annotations such as @PostConstruct "only apply to container-managed beans", not if "you are simply calling new BlogEntryDao() yourself". 另一个问题的回答提到了注释,比如@PostConstruct “仅适用于容器管理豆”,如果不是“你只是调用new BlogEntryDao()自己”。

Is this what's happening here - Spring Batch calling new Account(...) directly, without registering them in the container? 这是这里发生的事情吗-Spring Batch直接调用new Account(...) ,而无需在容器中注册它们? After all, I never have these accounts available as beans or anything. 毕竟,我从来没有将这些帐户用作bean或其他任何东西。

Is your Account class annotated with @Component , @Bean or @Service ? 是否使用@Component @Bean@Service @Bean@Service注释您的Account类? If you create objects of account class like Account c = new Account() the nSpring doesn't know about creation of such objects. 如果您创建帐户类的对象,例如Account c = new Account()则nSpring不会创建此类对象。 Because of that Spring doesn't call method annotated with @postConstruct 因此,Spring不会调用以@postConstruct注释的方法

when my reader creates these accounts, it apparently does not call the @PostConstruct method 当我的读者创建这些帐户时,它显然未调用@PostConstruct方法

@PostConstruct and @PreDestroy methods are called by the Spring container after creating and before destroying the instance of your bean. 在创建容器之后并销毁bean实例之前,Spring容器将调用@PostConstruct@PreDestroy方法。 If your object is not managed by Spring, those methods will not be called. 如果您的对象不是由Spring管理的,则不会调用这些方法。

I'm using Spring Batch's readers to load these accounts from a fixed-length file 我正在使用Spring Batch的阅读器从固定长度的文件加载这些帐户

In this case, you should have already configured a FieldSetMapper to map fields to an Account instance. 在这种情况下,您应该已经配置了FieldSetMapper以将字段映射到Account实例。 If you use the BeanWrapperFieldSetMapper , you can set the PrototypeBeanName which is the name of a bean (for example of type Account ) of scope prototype (so that an instance is created for each line). 如果使用BeanWrapperFieldSetMapper ,则可以设置PrototypeBeanName ,它是作用域原型的Bean(例如Account类型)的名称(以便为每行创建一个实例)。 This way, Account instances will be managed by Spring, used by Spring Batch reader, and your method annotated with PostConstruct will be called. 这样, Account实例将由Spring管理,由Spring Batch阅读器使用,并且将调用用PostConstruct注释的方法。 Here is an example: 这是一个例子:

@Bean
@Scope("prototype")
public Account account() {
    return new Account();
}

@Bean
public BeanWrapperFieldSetMapper<Account> beanMapper() {
    BeanWrapperFieldSetMapper<Account> fieldSetMapper = new BeanWrapperFieldSetMapper<>();
    fieldSetMapper.setPrototypeBeanName("account");
    return fieldSetMapper;
}

@Bean
public FlatFileItemReader<Account> accountReader() {
    return new FlatFileItemReaderBuilder<Account>()
            .name("accountsItemReader")
            .resource(new ClassPathResource("accounts.txt"))
            .fixedLength()
            .columns(new Range[] {new Range(1, 1), new Range(2, 4)})
            .names(new String[]{"id", "name"})
            .fieldSetMapper(beanMapper())
            .build();
}

More details about this in the Javadoc . Javadoc中对此有更多详细信息。

Hope this helps. 希望这可以帮助。

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

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