I have converted a Spring 4.0-based project from xml to javaconfig.
On initialization, one of my beans needs to access Hibernate to fetch some config-data from the DB, through a Spring @Service (buildingService
). The bean initialization looks like this:
@Bean
@DependsOn({ "transactionManager", "webSocketHandler", "buildingService" })
Smarty smarty() {
Smarty bean = new Smarty();
bean.init(); // I also tried @Bean(initMethod = "init") with no difference
return bean;
}
The problem is that in bean.init()
, the service is accessed, which fails with a NullPointerException
.
I added buildingService
to @DependsOn
but it did not help.
Probably the @Service
-annotated classes are processed after the @Bean
!?
Can I initialize the @Service
-annotated class myself upfront?
Edit 1
Thanks so far for all the feedback !
I need to add some details:
buildingService is not a @Bean
, it's, well, a @Service
and looks like this:
@Service("buildingService")
@Transactional
public class BuildingService {
...
public List<Building> getAll() {
final Session session = sessionFactory.getCurrentSession();
final Query query = session.createQuery("from Building order by name");
return query.list();
}
...
}
Smarty is a Spring managed Bean, and initialized in an @Configuration
-annotated class which is doing the initialization of the root-context.
Smarty has a direct dependency on buildingService, like so:
@Resource(name = "buildingService")
private BuildingService buildingService;
I tried annotating Smarty.init()
with @PostConstruct
but this did not change anything.
Note that the first thing Smarty.init()
does is calling buildingService.getAll();
Or maybe the @Service("customUserDetailsService") syntax does not set the bean id, but the bean name instead. If these both are not the cause, then probably Spring is just unable to refer to a bean that is yet to be scanned (a bit sad if this is the case).
Using Annotation: To provide the facility to the created bean to invoke custom init() method on the startup of a spring container and to invoke the custom destroy() method on closing the container, we need annotate init() method by @PostConstruct annotation and destroy() method by @PreDestroy annotation.
But if you want to initialize a bean lazily, you can use the @Lazy annotation over the class. This means that the bean will be created and initialized only when it is first requested for. You can also use this annotation on @Configuration classes.
Spring @Bean Annotation is applied on a method to specify that it returns a bean to be managed by Spring context. Spring Bean annotation is usually declared in Configuration classes methods. In this case, bean methods may reference other @Bean methods in the same class by calling them directly.
You're confused about the lifecycle of a bean. Spring has to first create the bean before it can inject anything. In your @Bean
method, you've created your bean
Smarty bean = new Smarty();
then immediately called one of its methods
bean.init();
that seems to depend on a field being injected.
There's nothing between those two calls. How do you expect Spring to do anything?
Instead, you could annotate your init()
method with @PostConstruct
. Once Spring is done initializing your bean, ie. when your @Bean
method returns and Spring injects all the object's injection targets, it will invoke the method automatically.
@DependsOn
is not necessary here.
@Sevice
annotated beans are autodiscovered and initialized via component scanning, to enable this use @ComponentScan
on Spring Configuration.
@ComponentScan
Configures component scanning directives for use with
@Configuration
classes.
@Bean
are used for manual creating beans, without using special annotation like @Service
or component scanning.
@Bean
Indicates that a method produces a bean to be managed by the Spring container. (...) Typically, @Bean methods are declared within @Configuration classes. In this case, bean methods may reference other @Bean methods in the same class by calling them directly.
Context configuration
@Autowired
EntityManager entityManager; //needs to access Hibernate
@Bean
Smarty smarty() {
return = new Smarty(entityManager);
}
And your Smarty
bean
public Smarty {
final EntityManager entityManager;
public Smarty(EntityManager entityManager){
this.entityManager = entityManager;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With