Spring Boot application.properties - spring

I'm developing a Spring Boot application and I used application.properties to configure db connections ,server port etc..
# ===============================
# = SERVER CONFIGURATION
# ===============================
server.port=8173
# ===============================
# = DATABASE CONFIGURATION
# ===============================
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springBootApps
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create
# ===============================
# = SPRING CONFIG
# ===============================
server.error.whitelabel.enabled = false
spring.view.prefix =/WEB-INF/jsp/
spring.view.suffix = .jsp
Can I use an application.properties file instead of spring-configuration.xml or do I need to use both configurations inside my project?
Can I write all my Spring configuration in the application.properties file?
(in previous spring versions I did this using springConfiguration file)
As a example how can I implement the following XML configuration in application.properties
<bean id="daoImpl" class="com.mycompany.loginapp.dao.UserDaoImpl"/>
<bean id="data" class="org.springframework.jdbc.core.JdbcTemplate" >
<property name="dataSource" ref="dataSource" />
</bean>

Spring's application.properties are meant for externalizing your properties such as JNDI names, file system paths, etc. This property file is not meant to replace earlier XML based the bean definition and bean wiring.
For bean definitions, you can use either XML based bean definitions or Spring annotations (like #Autowired, #ComponentScan, etc) to get rid of XMLs.

You are correct, everything can be done within the application.properties.
Full list here docs.spring.io
In some cases if you are overriding Spring Boot's auto configuration capabilities the properties may not work.

Related

Property placeholders with YamlPropertiesFactoryBean and Spring Boot

I am migrating a small "legacy" application to Spring Boot and ran into an issue with property placeholders in combination with a YamlPropertiesFactoryBean. The application uses Spring XML configuration.
I added a Spring Boot "main" to the project like so:
#SpringBootApplication
#ImportResource("classpath:spring-config.xml")
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
I have placed an application.yaml into /config. It is being picked up by Spring boot and I can access properties defined in it via property replacement (${some.prop}) in bean declarations in the imported spring-config.xml. E.g.
<bean id="myRouteBuilder" class="org.camelSpringBoot.test.MyRouteBuilder">
<property name="someProp" value="${prop.from.application.yaml}"/>
</bean>
Except when using a org.springframework.beans.factory.config.YamlPropertiesFactoryBean to read an additional, external configuration file: A property for the file location in the constructor arg of a org.springframework.core.io.FileSystemResource does not get resolved:
<bean id="yamlProperties" class="org.springframework.beans.factory.config.YamlPropertiesFactoryBean">
<property name="resources">
<list>
<bean class="org.springframework.core.io.FileSystemResource">
<constructor-arg value="${service.config.loc}" />
</bean>
</list>
</property>
</bean>
yields
java.io.FileNotFoundException: ${service.config.loc}
If I hard-code the location of the external configuration then properties used in the external YAML file are not resolved either.
application.yaml:
security:
keystore:
loc: /security/my.keystore
external config:
services:
a:
ssl:
secret: ${security.keystore.loc}
java.lang.RuntimeException: Cannot open keystore/truststore ${security.keystore.loc}
Note that the error complains about the verbatim property.
The YamlPropertiesFactoryBean instance is declared in spring-config.xml like the other beans that successfully use property placeholders (meaning properties get replaced by their values). Why would it fail for the YamlPropertiesFactoryBean
Is it possible to enable placeholder resolution for the external YAML document?
I do not know if it is working what you are trying to do. The Property resolving takes place after a BeanDefinition is done, and therefore only working with Spring Beans, but not arbitrary files like your yaml file.
Most build tools (gradle, maven) contain a functionality to resolve those placeholder during build time. Might that be a solution for you?

logback: FileNamePattern from application.properties

I would like to get the file name of my logback file from a property defined in the
application.properties
but I don't know if it is possible
<fileNamePattern>${user.home}/logs/>${logFileName}.%i.log.zip</fileNamePattern>
You can register your application.properties file in the logback.xml configuration file. logback will then recognize the properties defined in that file.
logback.xml:
<property resource="application.properties"/>
More details: https://logback.qos.ch/manual/configuration.html#definingProps

Can Spring support multiple messages.properties files in classpath?

There are a JAR A and JAR B, both have messages.properties in classpath /
And there is WAR C, which has dependencies on JAR A and JAR B.
And when I start WAR C I can only get i18n message from JAR A or JAR B.
So, how can Spring support multiple messages.properties files in classpath?
BTW, WAR C is a spring boot project, and spring.messages.basename=messages
Problem solved.
According to this question Does Spring MessageSource Support Multiple Class Path?
have to ditch ResourceBundleMessageSource and write a custom implementation of MessageSource (most likely by subclassing AbstractMessageSource) which uses PathMatchingResourcePatternResolver to locate the various resources and expose them via the MessageSource
I make a copy of ReloadableResourceBundleMessageSource and write the code by this guide and problem solved.
Yes, Spring supports loading multiple Properties. But properties should be unique. If we have same properties in the two Properties Files then the file which will be loaded later will override the previous Properties from previous file.
For example, if the Properties file from JAR A has two properties {USERNAME, PASSWORD} and JAR B Properties file also has the same two properties then you'll get {USERNAME, PASSWORD} from the file which is loading later.
You can use wildcard to import all the Property Files with same name on your classpath.
In Spring you can mention different Properties files in the form of Array as follows:
<context:property-placeholder
location="classpath:war.properties,
classpath*:message.properties"
ignore-unresolvable="true"/>
or
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:war.properties</value>
<value>classpath*:message.properties</value>
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>

Tomcat Context-Params ignored in Spring webapp when using PropertyPlaceholder

I was previously using, the now deprecated, class org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer to load a properties file from the server's filesystem. I had the following bean definied:
<bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer">
<property name="locations" value="${config}"/>
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="searchContextAttributes" value="true"/>
<property name="contextOverride" value="false"/>
<property name="ignoreResourceNotFound" value="true"/>
<property name="searchSystemEnvironment" value="false"/>
</bean>
The config is an argument that is passed when starting Tomcat, i.e.
-Dconfig=/path/to/application.properties
For the webapp I also have a context file:
<Context docBase="/path/to/application.war">
<Parameter name="host" value="localhost" override="false"/>
<Parameter name="port" value="8080" override="false"/>
</Context>
If the .properties file, specified by the -Dconfig argument, contains the property that some other bean references then the value from the .properties file is used, otherwise the value from the the context xml file is used.
This allowed me to have a set of default properties deployed with the WAR and if required, I was able to specify a .properties file to override particular values.
Now, I'm updating to use the new property abstractions in Spring 3.1 but I can't seem to figure out what the equivalent approach to this is?
I have the same context file and war deployed in the same way, and I now have the following in the application:
<context:property-placeholder
location="${config}"
system-properties-mode="OVERRIDE"
ignore-resource-not-found="true"
ignore-unresolvable="true"/>
This finds and uses the properties from the properties file, BUT it does not use the values from the context XML file.
How do I get my application to use the context params when using this new property-placeholder?
Thanks.
To summarise the problem is that the Context Parameters from the servlet context file were not being used to resolve placeholders when using the new Property Placeholder namespace introduced in Spring 3.1.
I have figured out a solution, with the following
<context:property-placeholder location="${config}" local-override="true" ignore-resource-not-found="true"/>
I can specify one or more *.properties files on the local filesystem using a JVM arg, eg:
-Dconfig=/path/app.properties
If a placeholder property cannot be resolved after checking the app.properties file then the Servlet Context Parameters are checked.
This allows me to have default values using context params in a the web.xml and where I need to I can override these values by specifying the location of *.properties files using the config JVM arg.
The key to getting it to work this way was to include local-override="true", which is false by default. I'm not fully sure that it makes sense, since the description for that attribute is:
Specifies whether local properties override properties from files. Default
is "false": Properties from files override local defaults.
If the same property key exists in the app.properties and the web.xml the value from the app.properties is used.
Spring uses a default property file unless the user-based property file is defined. If you want to control .properties file, please follow the instructions posted here.
If you want to take advantage of application.properties there are two ways to do it.
<!-- allows for ${} replacement in the spring xml configuration from the
system.properties file on the classpath -->
<util:properties id="appProperties" location="classpath:application.properties"/>
<context:property-placeholder location="classpath:application.properties"/>
util tag lets you to use a Property class to read the properties across your application. For example:
#Autowired
public MyPropertyReader(Properties appProperties) {
String prop1 = appProperties.getProperty("my.address");
String prop2 = appProperties.getProperty("my.version");
}
If you want to use the values within your context file use the context:property-placeholder tag. Then you can use your values as
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory" p:brokerURL="${jms.primary.server}"/>
where for example jms.primary.server=172.168.10.18:6161 in application.properties.

Spring session factory not finding mapping files in multiple directories with same class path

I am having problems when loading hibernate mappings from multiple paths.
My Spring session factory is define as follows:
<beans>
...
<bean id="sessionFactory" class="org.springframwork.orm.hibernate3.LocalSessionFactory">
</bean>
<property name="mappingLocations">
<list>
<value>classpath:/mapping/*.hbm.xml</value>
</list>
</property>
When I put my mappings Foo.hbm.xml and Bar.hbm.xml into the directory src/main/resources/mappings, then both mappings are found when Hibernate is initialized.
But when I put Foo.hbm.xml into the directory src/main/resources/mapping and Bar.hbm.xml into the directory src/test/resources/mapping, then only the latter mapping file can be found. Hibernate will fail with "cannot find mapping for Foo" error.
I can see that the mappings are copied to the directories target/classes/mapping and target/test-classes/mapping, so why cannot hibernate (or the spring local session factory bean) find both mapping files? I thought that "classpath:/mapping/*.hbm.xml" would find both target/classes/mapping and target/test-classes/mapping directories?
edit: I am getting this problem when running unit tests, so I expect that mappings found in both src/main/resources and src/test/resources would be found.
You are using maven. And since you put your Bar mapping into the test resource directory, it is only available when running tests.
I assume you have a persistence-unit configured similar to the example below
<persistence-unit ...>
<class>something.Foo</class>
<class>something.Bar</class>
</persistence-unit>
What happens at start-up is that Spring starts Hibernate, hibernates reads the persistence-unit and asks the factory for the mappings. But remember, Bar is only a test class. So Spring finds the mappings from src/main/resources, but since it does not run as a test, it does not see src/test/resources.

Resources