@PostConstruct spring does not get called without bean declaration
Asked Answered
M

6

5

Why post construct does not get called without putting bean in applicationContext.xml

Here is my class which contains @PostConstruct annotation.

package org.stalwartz.config;

import javax.annotation.PostConstruct;
import javax.inject.Singleton;

@Singleton
public class PropertyLoader {

    @PostConstruct
    public void init() {
         System.out.println("PropertyLoader.init()");
    }
}

Below is my applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
 http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans.xsd 
 http://www.springframework.org/schema/context 
 http://www.springframework.org/schema/context/spring-context.xsd 
 http://www.springframework.org/schema/mvc 
 http://www.springframework.org/schema/mvc/spring-mvc.xsd 
 http://www.springframework.org/schema/tx 
 http://www.springframework.org/schema/tx/spring-tx.xsd 
 http://www.directwebremoting.org/schema/spring-dwr
 http://www.directwebremoting.org/schema/spring-dwr/spring-dwr-3.0.xsd">

<dwr:annotation-config />
<dwr:annotation-scan base-package="org.stalwartz" scanDataTransferObject="true" scanRemoteProxy="true" />
<dwr:url-mapping />

<!--  <bean id="proeprtyLoader" class="org.stalwartz.config.PropertyLoader"></bean>  -->

<dwr:controller id="dwrController" debug="false">
    <dwr:config-param name="activeReverseAjaxEnabled" value="true" />
</dwr:controller>

<context:annotation-config>
    <context:component-scan base-package="org.stalwartz" annotation-config="true"></context:component-scan>
</context:annotation-config>

<mvc:annotation-driven />
...
...
...
</beans>

Looks simple, but it does not work without uncommenting bean declaration.

Millisent answered 29/3, 2016 at 14:32 Comment(0)
G
4

In Spring environment initialization callback method (the one annotated by @PostConstruct) make sense only on spring-managed-beans. To make instance(s) of your PropertyLoader class managed, you must do one of the following:

  1. Explicitly register your class in context configuration (as you did)
    <bean id="proeprtyLoader" class="org.stalwartz.config.PropertyLoader"></bean>
  2. Let component scanning do the work (as you nearly did), but classes must be annotated by one of @Component, @Repository, @Service, @Controller.

Note from Spring documentation: The use of <context:component-scan> implicitly enables the functionality of <context:annotation-config>. There is usually no need to include the <context:annotation-config> element when using <context:component-scan>.

Gelid answered 29/3, 2016 at 14:56 Comment(3)
Yes, tried @ Service & @ Component but seems like component scan is not functioning as expected.Millisent
The problem is with your nested <context:annotation-config><context:component-scan> declarations. See the last note of my edited post.Gelid
bullseye @ Component in class & <context:component-scan base-package="org.stalwartz"></context:component-scan> in applicationContext.xmlMillisent
R
1

Singleton is a scope annotation. It can be used to declare 'singletone' scope for a particular bean, but not instantiate it. See this article.

If you want to instantiate your class as singleton you can try Spring Service annotation.

@Service
public class PropertyLoader {

    @PostConstruct
    public void init() {
         System.out.println("PropertyLoader.init()");
    }
}

Also, you can replace annotation-config tag with component-scan. Here is a good article about differences of annotation-config and component-scan tags.

Racoon answered 29/3, 2016 at 14:40 Comment(3)
Just tried with @Service annotation, result negative.Millisent
just didn't saw it before: why do you use component-scan inside annotation-config? annotation-config tag can be replaced with component-scan. just updated my answerRacoon
Thanks that resolved the issue. My bad, mixed up JSF & Spring annotations.Millisent
D
1

Because putting bean in applicationContext.xml you are adding bean to Spring container, which has interceptor for this annotation. When Spring inject beans it checks @PostConstruct annotation, between others.

When you call simple new PropertyLoader() JVM will not search for the @PostConstruct annotation.

From doc of @PostConstruct annotation:

The PostConstruct annotation is used on a method that needs to be executed after dependency injection is done to perform any initialization. This method MUST be invoked before the class is put into service. This annotation MUST be supported on all classes that support dependency injection. The method annotated with PostConstruct MUST be invoked even if the class does not request any resources to be injected.

Dyadic answered 29/3, 2016 at 14:55 Comment(0)
I
1

you are using @Singleton from javax.inject package which is not picked up as bean by spring container. Change it to :

package org.stalwartz.config;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class PropertyLoader {

    @PostConstruct
    public void init() {
        System.out.println("PropertyLoader.init()");
    }
}

and the spring will auto detect PropertyLoader and will include it in Spring container as bean via the @Component annotation and this bean will be with singleton scope

Isothermal answered 29/3, 2016 at 14:57 Comment(0)
W
1

by default a bean is singleton scoped in Spring, and @PostConstruct is usually used for service beans and service beans must scoped prototype and here because you need multiple objects for that particular class, Spring will provide you singleton instance.

also by doing this spring will attempt multiple times to find this service bean and finally throws below exception:

java.lang.NoClassDefFoundError: Could not initialize class org.springframework.beans.factory.BeanCreationException

so try like this in annotation way:

package org.stalwartz.config;

import javax.annotation.PostConstruct;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype") //you have to make it prototype explicitly
public class PropertyLoader {

    @PostConstruct
    public void init() {
         System.out.println("PropertyLoader.init()");
    }
}

Now every thing is good, and work fine for you.

Winfredwinfrey answered 14/2, 2018 at 11:34 Comment(0)
Y
1

add this dependency to pom.xml

<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>

  
Yuk answered 18/12, 2022 at 15:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.