Kaliappan
Kaliappan

Reputation: 660

Read Spring boot property inside listener

My requirement is, I need to initialize some application resources when server is started in spring boot. In order to initialize those resources, I need bunch of properties. So, I have kept those properties in external property file and I am trying to read the properties in my custom listener when spring boot is started. The problem is, I could not get any property values in the listener. I am able to read them after application started without any issues. But, I need them inside listener while application is starting. I am getting below exceptions...How to resolve it. help me pls!

    2015-08-20 02:58:59.585 ERROR 9376 --- [ost-startStop-1] o.a.c.c.C.[.[localhost].[/shared]        : Exception sending context initialized ev
ent to listener instance of class com.org.man.api.initializer.PropertyInitializerListener

java.lang.NoSuchMethodError: com.org.man.api.beans.property.ConfigProperties.getConfigNames()Ljava/util/List;
        at com.org.man.api.beans.property.PropertyBeanParser.initializeConfigProperties(PropertyBeanParser.java:33)
        at com.org.man.api.initializer.J2eeInitializer.getJ2eePresets(J2eeInitializer.java:79)
        at com.org.man.api.initializer.J2eeInitializer.initialize(J2eeInitializer.java:36)
        at com.org.man.api.initializer.PropertyInitializerListener.contextInitialized(PropertyInitializerListener.java:81)
        at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4727)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5167)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)

2015-08-20 02:58:59.592 ERROR 9376 --- [ost-startStop-1] o.apache.catalina.core.StandardContext   : One or more listeners failed to start. F
ull details will be found in the appropriate container log file
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Fac
tory method 'viewControllerHandlerMapping' threw exception; nested exception is java.lang.IllegalStateException: The resources may not be ac
cessed if they are not currently started
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
        ... 23 common frames omitted
Caused by: java.lang.IllegalStateException: The resources may not be accessed if they are not currently started
        at org.apache.catalina.webresources.StandardRoot.validate(StandardRoot.java:245)
        at org.apache.catalina.webresources.StandardRoot.getResource(StandardRoot.java:212)

Listener code

public class PropertyInitializerListener implements ServletContextListener {
private static final String INITIALIZED = PropertyInitializerListener.class.getName() + ".INITIALIZED";
private J2eeInitializer initializer;

@Autowired
PropertyBeanParser parser;

public void contextDestroyed(ServletContextEvent event) {
    if (initializer != null) {
        initializer.terminate();
    }

    ServletContext context = event.getServletContext();
    context.removeAttribute(FileSearcher.CONFIG_FILE_PROP);
}

public void contextInitialized(ServletContextEvent event) {
    ServletContext context = event.getServletContext();

    if (context.getAttribute(INITIALIZED) != null) {
        throw new IllegalStateException(
            "Already initialized - " +
            "check whether you have multiple <listener> definitions in your web.xml!");
    }
    ConfigBean presets = super.getPresets();
    presets = parser.initializeConfigProperties();
    SmapiDebug.setSaveMode(true);
    SmapiDebug.info("contextInitialized");

PropertyBeanparser code

@Configuration    

@EnableConfigurationProperties({ConfigProperties.class,LoggingProperties.class,
            InstrumentationProperties.class,KeyeventProperties.class})
        public class PropertyBeanParser {

            @Autowired
            private ConfigProperties configProperties;

            @Autowired
            private LoggingProperties loggingProperties;

            @Autowired
            private InstrumentationProperties instrumentationProperties;

            @Autowired
            private KeyeventProperties keyeventProperties;

            public ConfigBean initializeConfigProperties(){

                ConfigBean configBean = new ConfigBean();
                try{
                    if(configProperties.getConfigNames()!=null && configProperties.getConfigValues()!=null) {
                        if(configProperties.getConfigNames().size()==configProperties.getConfigValues().size()){
                            for(int i=0;i<=configProperties.getConfigNames().size();i++){
                                ConfigVarDefinitionBean var = new ConfigVarDefinitionBean(configProperties.getConfigNames().get(i),
                                        configProperties.getConfigValues().get(i));
                                configBean.addConfigVarDefinition(var);
                            }
                        }
                        else{
                            throw new Exception("number of names and values are not matching");
                        }
                    }

                }
                catch(Exception e){
                    e.getMessage();
                }
                return configBean;
            }
        }

ConfigProperties class

@Configuration
@ConfigurationProperties(locations = "file:config.properties", prefix = "config")
public class ConfigProperties {

    private List<String> configNames = new ArrayList<String>();
    private List<String> configValues = new ArrayList<String>();
    public List<String> getConfigNames() {
        return configNames;
    }
    public void setConfigNames(List<String> configNames) {
        this.configNames = configNames;
    }
    public List<String> getConfigValues() {
        return configValues;
    }
    public void setConfigValues(List<String> configValues) {
        this.configValues = configValues;
    }
}

Config.Properties

config.configNames[0]=test1
config.configNames[1]=Testserver
config.configNames[2]=ResourceId
config.configNames[3]=AdaptorName
config.configNames[4]=runLevel

config.configValues[0]=ServiceComp
config.configValues[1]=Test
config.configValues[2]=instance2
config.configValues[3]=test
config.configValues[4]=localhost

Upvotes: 2

Views: 4939

Answers (2)

Kaliappan
Kaliappan

Reputation: 660

The issue is, properties can't be retrieved inside listener during spring boot start up. So, in order to do some initialization in the start up, we can add run method in the class where @SpringBootApplication annotation is set by implementing CommandLineRunner . If you do so, that run method will be executed just before finishing the SpringApplication's run method.This is how I tried.

@SpringBootApplication
public class SpringResource implements CommandLineRunner {

    /**
     * @param args
     */
    @Autowired
    PropertyTest test;

    public void run(String... args){
        test.print();
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(SpringResource.class, args);

    }
}

PropertyTest Class

@Configuration
@EnableConfigurationProperties({ConfigProperties.class})
@Controller
public class PropertyTest {

    @Autowired
    ConfigProperties config;


    @RequestMapping(value = "/dummy", method = RequestMethod.GET)
    @ResponseBody
    public void print() {
        // TODO Auto-generated method stub
        for(int i=0;i<config.getConfigNames().size();i++)
        System.out.println("Im in Property test method. :)" +config.getConfigNames().get(i)+" "+config.getConfigValues().get(i));
    }

}

Upvotes: 2

accreativos
accreativos

Reputation: 161

I'm answer from my mobile, but may the problem it's in the listener, you not autowire PropertyBeanparser you create, and you broke spring magic... I think in main app class springboot to declare a listener and make inside spring "flow" hope that help

Upvotes: 0

Related Questions