Spring reload properties without restarting TOMCAT - spring

I have this Spring MVC application that makes use of PropertyPlaceholderConfigurer to load properties using #Value annotation.
I understand that all properties are loaded at server startup when context is initialized.
Howevver, is there a way that I can access updated properties without having to restart TOMCAT? (perhaps making use of Apache Commons PropertiesConfiguration)?
Is there a way I can configure Apache Commons PropertiesConfiguration to work with Spring PropertyPlaceholderconfigurer?

Add #RefreshScope annotation above the class which consumes the properties (ie has #Value annotation). Example goes as follows:
#RefreshScope
class PropertiesConsumer {
....
#Value(..)
private consumerFoo;
....
}

Related

Creating a custom FactoryBean in Sprint Boot 2.3/Spring 5

I've got a spring-boot web application that's mostly working; my DataSource is properly configured by an external application.properties file.
Now I want to add properties to that file to help me instantiate and configure two instances of a class in my app. I have a APNsFactory that I currently instantiate manually and configure using JNDI, but I want to get away from JNDI calls:
#Bean
public
APNsFactory
apnsFactory()
throws
javax.naming.NamingException
{
sLogger.info("Configuring APNsFactory");
InitialContext ctx = new InitialContext();
APNsFactory f = new APNsFactory();
f.setProductionKeystorePath((String) ctx.lookup("java:comp/env/apns/prod/keystorePath"));
f.setProductionKeystorePassword((String) ctx.lookup("java:comp/env/apns/prod/keystorePassword"));
f.setDevelopmentKeystorePath((String) ctx.lookup("java:comp/env/apns/dev/keystorePath"));
f.setDevelopmentKeystorePassword((String) ctx.lookup("java:comp/env/apns/dev/keystorePassword"));
return f;
}
When running before in a standalone webapp container, Spring properly called that method and the JNDI context from the container’s <env-entry> tags was available.
I'm trying to update my APNsFactory to be a proper Spring FactoryBean<>, and I’ve given it a couple of #Autowire String variables that I want to be set by Spring Boot from the application.properties file.
For bonus points, I want this to be usable both in Spring Boot and in a standalone container like Tomcat or Resin.
For the life of me, I can't figure out how to get Spring to do this. There are dozens of examples for DataSources and other Beans already implemented by Spring, but none for a completely custom one, using application.properties, in a Spring Boot web environment.
I've seen some examples that use an XML config file, but I'm not sure how to do that with Spring Boot.
I don't think you need a factory bean here.
You already have spring boot that can read application.properties out-of-the-box:
So try the following:
Create key/values in the application.properties file:
myapp.keystore.path=...
myapp.keystore.passwd=...
// the same for other properties
Create ConfigurationProperties class
#ConfigurationProperties(prefix="myapp.keystore")
public class MyAppKeyStoreConfigProperties {
private String path; // the names must match to those defined in the properties file
private String passwd;
... getters, setters
}
In the class marked with #Configuration (the one where you create #Bean public APNsFactory apnsFactory()) do the following:
#Configuration
// Note the following annotation:
#EnableConfigurationProperties(MyAppKeyStoreConfigProperties.class)
public class MyConfiguration {
// Note the injected configuration parameter
#Bean public APNsFactory apnsFactory(MyAppKeyStoreConfigProperties config) {
APNsFactory f = new APNsFactory();
f.setProductionKeystorePath(config.getKeyPath());
and so on
}
}
I've intentionally didn't show the separation between production/dev stuff.
In spring boot you have profiles so that the same artifact (WAR, JAR whatever) can be configured to run with different profile and depending on that the corresponding properties will be read.
Example:
If you're running with prod profile, then in addition to application.properties that will be loaded anyway, you can put these keystore related definitions to application-prod.properties (the suffix matches the profile name) - spring boot will load those automatically. The same goes for dev profile of course.
Now I haven't totally understand the "bonus points" task :) This mechanism is spring boot proprietary way of dealing with configuration. In "standalone" server it should still have a WAR with spring boot inside so it will use this mechanism anyway. Maybe you can clarify more, so that I / our colleagues could provide a better answer

Upgrading from Java Config to Spring Boot

Upgrading an existing system to Spring Boot with Auto config. Currently the system is all Java config. I'm confused over whether to continue the use of #Profile. Is this annotation no longer needed? I searched extensively about upgrading and found only references to non-Spring Java migration and creating new projects.
Typical #Profile usage in our configuration classes looks something like:
#Bean
#Profile("is-standalone")
public Service unsecuredService(SomeApi someApi) {
return new ...
}
I inferred from the Spring Boot examples that using one of the #Conditional annotations is recommended like this:
#Bean
#ConditionalOnProperty("unsecured.enabled")
public Service unsecuredService(SomeApi someApi) {
return new ...
}
Then in a YAML file the is-standalone Profile enables or disables all the various properties for that Profile. Is this the proper way to upgrade? To repeat a question from above differently, can the #Profile usage be left as is? This is for a fairly large project, the upgrade is non-trivial, so I would like to do this only once!
Depends where your previous #Profile annotation is coming from. If you're using Spring's #Profile, the functionality is as follows:
Annotating a class with #Profile("dev") will load the class and register it in the Spring context only when the dev profile is active
Annotating a class with #Profile("!dev") will load the class and register it in the Spring context only when the dev profile is inactive
If this sounds like what you have already, no change is needed.

Spring boot #ConfigurationProperties not loading from external properties file or class path property file

Hi I am trying to use a reusable library that I have created using spring boot(2.0.5) from 2 applications I am able to bind properties from application.properties which is in my classpath to my bean as follows and I see the schemas being set through the setters in my debug in my first spring batch application which is also created with spring boot(2.0.5)
This is the property bean class in my library which holds some service api- this library is just a jar package created with spring boot.
package com.test.lib.config
#ConfigurationProperties("job")
#PropertySources({
#PropertySource(value = "${ext.prop.dir}", ignoreResourceNotFound = true),
#PropertySource(value = "classpath:application.properties", ignoreResourceNotFound = true)
})
public class ServiceProperties {
/**
* Schema for the service
*/
private String schema;
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
}
And the config bean for this library is as follows in the same package.
#Configuration
#EnableConfigurationProperties(ServiceProperties.class)
#ComponentScan("com.test.lib")
public class LibraryModuleConfig {
}
This code works perfectly fine when called from a sprint boot spring batch application which includes this library as a dependency and the corresponding setters are called and I can see the schema set when I add job.schema=testSchema in application.properties
I try to use this same library in an existing spring mvc web application started from a tomcat server with external files directory as launch arguments( This application was not created with spring boot) and added the appropriate context:component-scan to include the beans (java config beans) from the library in the application-context(appn-context.xml). The job.schema property is passed from both application.properties file and even a external file in C drive as given by the ${ext.prop.dir}" in the #propertySources annotation. The schema property in ServiceProperties Bean never gets set and even the setters never get called in the debug. Why will this libray config bean not work in an existing spring mvc application but work with the spring batch application. Both of them add the library as a dependency. I have been at this at a long time and except for the spring property binding the other functionality seem to work.
#EnableConfigurationProperties is a handy annotation that Spring Boot provides. (Spring MVC doesn't provides in default)
For a legacy Spring MVC app (specifically for Spring 3.x), you can use #Value annotation for the properties.
#Value annotation also works in Spring Boot so I guess you can make a change so that it works with older version (Spring 3.x) and newer version just works without changing anything at all.
Hope this helps! Happy Coding :)

Purpose of using #Configuration annotation

I have created a spring mvc based application but I didn't use this #Configuration annotation. What is the purpose of using #Configuration annotation? By using this, what are we communicating to springMVC container?
Assuming your application is using xml configuration rather than AnnotationConfig so it is not loaded to ApplicationContext at all.
#Configuration is used when ApplicationContext has been initialized and bean registration.
#Configuration annotation is a core Spring annotation, and not Spring MVC. It is a core entry point to configuring Spring-based application using Java config instead of XML config.
Please, use Spring Documentation more often because it is a place where you will find answers to most of your questions. Like this one:
Indicates that a class declares one or more Bean #Bean methods and may
be processed by the Spring container to generate bean definitions and
service requests for those beans at runtime

Using #ConfigurationProperties in Spring Boot Application doesn't work

I am using Spring Boot V 1.4.1 for a new application.
My app requires two JDBC data sources and I was following the example at http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-two-datasources how to set it up.
My Spring beans configuration class is annotated with #EnableConfigurationProperties and my first bean is defined as
#Primary
#Bean
#ConfigurationProperties(prefix = "first.database")
DataSource qivsDB() {
return DataSourceBuilder.create().build();
}
, the second one accordingly. My application.properties file has properties defined like
first.database.url=jdbc:[redacted]
first.database.username=[redacted]
first.database.password=[redacted]
For reasons I not transparent to me during debugging this is failing to initialize: Cannot determine embedded database driver class for database type NONE - debug showed me that the builder does not have any properties set when calling build().
What did I miss here?
Before you do all the debugging part, you should have a look to the auto-configuration report. If you define your own DataSource there's no reason for Spring Boot to start looking at what it can do for your app. So, for some reasons, that definition of yours is not applied in your app and the default in Spring Boot still applies, doesn't find any JDBC url in the default namespace and attempt to start an embedded database. You should see in the auto-config report that the DataSourceAutoConfiguration still matches.
I am not sure the public keyword has anything to do with it, though you won't get custom meta-data for that key since we only scan for public methods.

Resources