Pregunta

I'm having a problem with the creation of my Spring context. One of my @Autowired attribute is null during the creation of one of my bean but is normally set during the creation of an other.

Here is my code :

@Configuration
@ComponentScan({ "packages" })
public class SpringContext {

@Autowired
// other attributes 
@Autowired
private CustomerRepository customerRepository;

@Bean
public Launcher launcher(){
    System.out.println("XXX Launcher " + customerRepository);
    return new Launcher(tcpServer, webServer,customerRepository);
}

@Bean 
public MessageSender messageSender() throws TechnicalException{
    System.out.println("XXX MessageSender " + customerRepository);
    return new MessageSenderImpl(customerRepository);
}

@Bean 
// other beans

and

@Repository
public class CustomerRepositoryImpl implements CustomerRepository {

private MongoTemplate mongoTemplate;

@Autowired
public CustomerRepositoryImpl(MongoTemplate mongoTemplate) {
    this.mongoTemplate = mongoTemplate;
}

And my output is :

 XXX MessageSender null
 XXX Launcher packages.CustomerRepositoryImpl@3fa801ba

Any idea why ? Thank by advance,

UPDATE Here is the solution I used :

@Configuration
@ComponentScan({ "packages" })
public class SpringContext {

@Autowired
// other attributes 

//-- deleted
// @Autowired
// private CustomerRepository customerRepository;
// --

@Bean
public Launcher launcher(**CustomerRepository customerRepository**){
    System.out.println("XXX Launcher " + customerRepository);
    return new Launcher(tcpServer, webServer,customerRepository);
}

@Bean 
public MessageSender messageSender(**CustomerRepository customerRepository**) throws TechnicalException{
    System.out.println("XXX MessageSender " + customerRepository);
    return new MessageSenderImpl(customerRepository);
}

@Bean 
// other beans

Thanks to both of you Stéphane Nicoll and Matt Metlisfor these two solutions !

¿Fue útil?

Solución

When using autowiring with fields, you can't assume ordering of spring building or injection the way your code does, because you're not telling Spring about any ordering. Since the launcher and messageSender methods are annotated with @Bean, Spring might call those methods to build those beans before it injects the customerRepository into the field.

One solution is what Stephane commented, specifying arguments to those bean building methods to force some ordering - Spring won't call the method until it can provide the parameters.

Another solution to guarantee ordering of bean creation, and what I generally use, is constructor injection - add the beans you want as parameters in a constructor, and put the @Autowired annotation on the constructor. I've been moving away from field and setter injection towards constructor injection because even though it's more verbose, that guaranteed ordering helps you avoid circular dependencies.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top