为什么在非托管类中自动弹出@Autowitred字段

时间:2016-12-29 14:09:30

标签: java spring spring-boot dependency-injection autowired

据我所知,spring提供了一些方法将bean注入非托管类。 它可以使用AutowireCapableBeanFactory显式完成。 (How to inject dependencies into a self-instantiated object in Spring?

但是当弹簧自动执行这样的注射时,我遇到了奇怪的(恕我直言)行为。

这是一个弹簧批的例子,

配置:

@SpringBootConfiguration 
public class ProcessorJobConfig {

//.....

@Bean(name = "pullRestTemplate")
public RestTemplate createPullRestTemplate() {
    RestTemplate restTemplate = restTemplateBuilder.build();

    return restTemplate;
}

@Bean(name = "step")
public Step step(@Autowired ItemReader<Measurement> itemReader,
                 @Autowired ItemProcessor<Measurement, Event> itemProcessor,
                 @Autowired ItemWriter<Event> itemWriter) {
    return stepBuilderFactory.get("step")
            .<Measurement, Event>chunk(Integer.MAX_VALUE)
            .reader(itemReader)
            .processor(itemProcessor)
            .writer(itemWriter)
            .build();
}

@Bean(name = "restProcessorJob")
public Job job(@Qualifier("step") Step step) throws Exception {
    return jobBuilderFactory.get("restProcessorJob")
            .start(step)
            .build();
}

@Bean
public ItemReader<Measurement> itemReader() {
    RestMeasureReader restMeasureReader = new RestMeasureReader(); // Use new() explicitly
    return restMeasureReader;
}

//.....
}

阅读器:

public class RestMeasureReader implements ItemReader<Measurement> {
private static final Logger LOGGER = LoggerFactory.getLogger(RestMeasureReader.class);

/**
 * NOTE: This field will be injected automatically by spring, even we are using new() to create instance of this class.
 */
@Autowired
@Qualifier("pullRestTemplate")
private RestTemplate restTemplate;

@Override
public Measurement read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
    // do some stuff
}
}

申请本身

@EnableBatchProcessing
@EnableTask
@SpringBootApplication
public class TestAutowiredTaskApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestAutowiredTaskApplication.class, args);
}
}

即使我使用显式new()来实例化RestMeasureReader,它的RestTemplate字段也将在之后注入。 这是正常的行为吗?我不希望spring在使用new()创建对象时自动注入字段。

2 个答案:

答案 0 :(得分:3)

如果您正在讨论在new课程中使用@Configuration,那么这是正常行为。这是你的Spring java配置。所以这是Spring管理的上下文。您不会明确地在代码中调用itemReader()。 所以,当你要这样做时:

@Autowired
private ItemReader<Measurement> iterReader;

您将从Spring的IoC获得RestMeasureReader的实例。

但是如果您尝试在代码中明确调用new RestMesureReader(),您将获得RestMesureReader的新实例,而不是注入@Autowired字段的Spring代理。

尝试从@Bean方法声明中删除itemReader(),并且无法使用RestMesureReader自动加载。

所以基本上@Configuration类只是一个Spring配置,而不是真正的java代码。即使你打电话给new,Spring仍然会给你一个代理类。

有关详细信息,请查看this guide

答案 1 :(得分:1)

Spring处理由@Bean注释的方法返回的bean 这允许您在使用Java配置时使用自动装配或实时循环回调。

一个更简约的例子:

@Configuration
public class MyConfiguration {

  @Bean
  public A a() {
    return new A();
  }

  static class A {
    @Autowired
    private B b;

    @PostConstruct
    public void onPostConstruct() {
      System.out.println("postConstruct: " + b);
    }
  }

  @Component
  static class B {
  }
}

这里,即使手动创建名为a的bean,Spring也会注入依赖项(b)并调用@PostConstruct回调。