about spring boot Profile can not work - spring

when I use command
mvn spring-boot:run -Dspring.profiles.active=web
my project is running,but #Profile("web") bean code not used,that only use
properties which the bean write by
#Profile("default")
how can I change for it,and the properties change to web profile?
#Profile("default")
#Bean
static public PropertySourcesPlaceholderConfigurer defaultPropertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer p = new PropertySourcesPlaceholderConfigurer();
Resource[] resourceLocations = new Resource[] { new ClassPathResource("job.core.properties") };
p.setLocations(resourceLocations);
return p;
}
#Profile("web")
#Bean
static public PropertySourcesPlaceholderConfigurer prodWebPropertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer p = new PropertySourcesPlaceholderConfigurer();
Resource[] resourceLocations = new Resource[] {new ClassPathResource("job.core.ris.properties") };
p.setLocations(resourceLocations);
return p;
}
job.core.ris.properties
db.driverClass=com.mysql.jdbc.Driver
db.jdbcUrl=jdbc:mysql://192.168.0.68:3306/job_ris?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=UTF-8
db.user=root
db.password=
job.core.properties
db.driverClass=com.mysql.jdbc.Driver
db.jdbcUrl=jdbc:mysql://192.168.0.68:3306/dev?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=UTF-8
when I use action then,show this

Work with the framework not against/around it. Spring Boot has build in support to load profile specific application.properties files.
Instead of trying to shoehorn multiple PropertyPlaceholderConfigurer into a Spring Boot application. Create an application.properties and application-web.properties containing your properties.
application.properties
db.driverClass=com.mysql.jdbc.Driver
db.jdbcUrl=jdbc:mysql://192.168.0.68:3306/dev?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=UTF-8
application-web.properties
db.jdbcUrl=jdbc:mysql://192.168.0.68:3306/job_ris?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=UTF-8
db.user=root
db.password=
(notice the missing db.driverClass you only need to include the different properties).
Next remove your custom #Bean annotated methods and let Spring Boot do the heavy lifting.
Pro Tip: Judging from the names of the properties you also have a custom #Bean for your DataSource. Instead of using custom names you probably want to use the spring.datasource.* properties and let Spring Boot create/manage your datasource.

Related

PropertySourcesPlaceholderConfigurer with highest priority

in my Spring Boot project I have the default application.properties in resources directory, I also configured Spring to load a properties file from file system (in working directory), called config.properties. some properties are redefined in the config.properties file, I want them have higher priority and overwrite properties defined in application.properties.
here is the PropertySourcesPlaceholderConfigurer bean :
#Configuration
public class Config {
#Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(){
PropertySourcesPlaceholderConfigurer properties =
new PropertySourcesPlaceholderConfigurer();
properties.setLocation(new FileSystemResource("config.properties"));
properties.setIgnoreResourceNotFound(false);
properties.setOrder(Ordered.HIGHEST_PRECEDENCE);
return properties;
}
}
but it does not work. the values in application.properties are applied, not config.properties. I tried to change setOrder(Ordered.HIGHEST_PRECEDENCE); to setOrder(Ordered.LOWEST_PRECEDENCE); nothing happened.
You can try call the method PropertySourcesPlaceholderConfigurer.setLocalOverride(boolean localOverride)
properties.setLocalOverride(true)
See for details: https://docs.spring.io/spring-framework/docs/4.1.6.RELEASE_to_4.2.0.RC1/Spring%20Framework%204.1.6.RELEASE/org/springframework/core/io/support/PropertiesLoaderSupport.html#setLocalOverride-boolean-

Spring configuration from yaml - combining #ConfigurationEnabled loading for parametrized file name

I'm having a problem probabably quite unique. I have two applications in the same project, using two different spring configuration files.
When I run them I manually load the context
context = new ClassPathXmlApplicationContext("hal.context.xml");
context.registerShutdownHook();
and I specify the required spring context file in each of them.
The problems comes from the configuration, because I have two configuration files stored in yaml files.
My best solution would be to use the Spring Boot facility to load the configuration (they have the same structure) in a POJO using
#org.springframework.context.annotation.Configuration("configuration")
#ConfigurationProperties
#EnableConfigurationProperties
and
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("filename"));
propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject());
return propertySourcesPlaceholderConfigurer;
}
I cannot find a way to load the configuration in a parametrised way... Is there any option combining this and perhaps
<bean id="yamlProperties" class="org.springframework.beans.factory.config.YamlPropertiesFactoryBean">
<property name="resources" value="classpath:hal.config.yml"/>
</bean>
but instead of using as property placeholder <context:property-placeholder properties-ref="yamlProperties"/> to find a way to automatically generate the POJO with the configuration.
Thank you in advance
Luca
You could separate the configuration values by using two different prefixes (one for each config file):
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
propertySourcesPlaceholderConfigurer.setPlaceholderPrefix("${app1:");
propertySourcesPlaceholderConfigurer.setPlaceholderSuffix("}");
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("app1_config_filename"));
propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject());
return propertySourcesPlaceholderConfigurer;
}
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
propertySourcesPlaceholderConfigurer.setPlaceholderPrefix("${app2:");
propertySourcesPlaceholderConfigurer.setPlaceholderSuffix("}");
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("app2_config_filename"));
propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject());
return propertySourcesPlaceholderConfigurer;
}
Then when injecting configuration values into your beans you can do:
#Value("{$app1:myVal}")
String myVal;
and
#Value("{$app2:myVal}")
String myVal;
Into beans from app1 and app2
Hope this helps

what is the Difference between spring.profiles.active=production vs spring.profiles.active=local

When I try to run an spring boot application.
There is a property available inapplication.properties file where it has the property spring.profiles.active=production.
While search the details about this property in web I got to know that spring.profiles.active=local.
Can anyone kindly explain these details?
Certain environment-specific choices made for development aren’t appropriate or won’t work when the application transitions from development to production.
Consider database configuration, for instance. In a development environment,
you’re likely to use an embedded database preloaded with test data like this:
#Bean(destroyMethod="shutdown")
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.addScript("classpath:schema.sql")
.addScript("classpath:test-data.sql")
.build();
}
In a production setting,
you may want to retrieve a DataSource from your container using JNDI:
#Bean
public DataSource dataSource() {
JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
jndiObjectFactoryBean.setJndiName("jdbc/myDS");
jndiObjectFactoryBean.setResourceRef(true);
jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
return (DataSource) jndiObjectFactoryBean.getObject();
}
Starting with Spring 3.1 you can use profiles. Method-leve #Profile annotation works starting from Spring 3.2. In Spring 3.1 it's only class-level.
#Configuration
public class DataSourceConfig {
#Bean(destroyMethod="shutdown")
#Profile("development")
public DataSource embeddedDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:schema.sql")
.addScript("classpath:test-data.sql")
.build();
}
#Bean
#Profile("production")
public DataSource jndiDataSource() {
JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
jndiObjectFactoryBean.setJndiName("jdbc/myDS");
jndiObjectFactoryBean.setResourceRef(true);
jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
return (DataSource) jndiObjectFactoryBean.getObject();
}
}
Each of the DataSource beans is in a profile and will only be created if the prescribed profile is active. Any bean that isn’t given a profile will always be created, regardless of what profile is active.
You can give any logical names to your profiles.
You can use this property to let Spring know which profiles should be active ( to be used while starting application). For example, if you give it in application.properties or via argument -Dspring.profiles.active=prod; you tell Spring, to run under prod profile. Which means - Spring will look for "application-prod.yml" or "application-prod.properties"file and will load all properties under it.
You can also annotate bean (method or class) by #Profile("PROFILE_NAME") - this ensures, the bean is mapped to certain profile.
You can pass multiple profiles to spring.profiles.active.
More information in docs - https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html

Springboot - Thymeleaf tries to resolve files it should not

Hi I am currently working on a web project that uses thymeleaf and also JSF (its a legacy system and we can only slowly migrate to thymeleaf thats why JSF is still there and cannot be removed from one day to another since this is a lot of work). Thymeleaf is configured to resolve the views in the webapp directory that lie under the directory "thymeleaf". This works perfectly if I deploy the application directly on a tomcat server. Also pages from other directories then the "thymeleaf" directory are also resolved by the JSF framework.
I added some integration tests in JUnit that are using SpringBoot. Inside these tests I got the problem that thymeleaf now is trying to resolve any page in any directory. JSF is completely ignored and I got a whole bunch of JUnit tests failing because of that. Is there any point why thymeleaf ignores its configuration and wants to resolve all files?
Here is my complete thymeleaf configuration, and as I said this works perfectly if I deploy it on a standalone tomcat.
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
String imagesPattern = "/images/**";
String imagesLocation = basePath() + "resources/images/";
registry.addResourceHandler(imagesPattern).addResourceLocations(imagesLocation);
log.info("added resourceHandler (pathPattern: '{}'), (resourceLocation: '{}')",
imagesPattern,
imagesLocation);
String cssPattern = "/css/**";
String cssLocation = basePath() + "resources/css/";
registry.addResourceHandler(cssPattern).addResourceLocations(cssLocation);
log.info("added resourceHandler (pathPattern: '{}'), (resourceLocation: '{}')", cssPattern, cssLocation);
}
#Bean(name = "basepath")
public String basePath()
{
String basepath = "";
File file = new File(Optional.ofNullable(System.getenv("THYMELEAF_APP_RESOURCES"))
.orElse("thymeleaf-resources/"));
if (file.exists())
{
basepath = "file:" + file.getAbsolutePath();
}
if (!basepath.endsWith("/"))
{
basepath += "/";
}
log.info("basepath: {}", basepath);
return basepath;
}
#Bean
#Description("Thymeleaf View Resolver")
public ThymeleafViewResolver viewResolver(String basePath)
{
log.info("setting up Thymeleaf view resolver");
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine(basePath));
viewResolver.setCharacterEncoding("UTF-8");
viewResolver.setCache(true);
return viewResolver;
}
public SpringTemplateEngine templateEngine(String basePath)
{
log.info("setting up Thymeleaf template engine.");
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver(basePath));
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
private ITemplateResolver templateResolver(String basePath)
{
log.info("setting up Thymeleaf template resolver");
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix(basePath + "thymeleaf/views/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCacheable(false);
return resolver;
}
#Bean
public IMessageResolver thymeleafMessageSource(MessageSource messageSource)
{
SpringMessageResolver springMessageResolver = new SpringMessageResolver();
springMessageResolver.setMessageSource(messageSource);
return springMessageResolver;
}
EDIT
I just found that the problem seems to lie much deeper. Having the dependencies of thymeleaf added into my pom.xml seems to be enough for spring boot to load it into the context... I just deleted my ThymeleafConfig class for testing purposes and still thymeleaf tries to resolve the JSF pages... (yes I did maven clean before executing the test)
EDIT 2
I read it now and tried to exclude the ThymeleafAutoConfiguration class but it does not help. My configurations are still overridden. Here is my configuration for this so far. (And yes this is the ONLY EnableAutoConfiguration annotation in the whole project)
#Configuration
#EnableAutoConfiguration(exclude = {ThymeleafAutoConfiguration.class})
#Import({WebAppConfig.class, ThymeleafConfig.class})
public class SpringBootInitializer extends SpringBootServletInitializer
and my ThymeleafConfig class is already added above.
Having the dependencies of thymeleaf added into my pom.xml seems to be enough for spring boot to load it into the context...
If this has surprised you then I would recommend spending some time to take a step back and read about how Spring Boot works and, in particular, it's auto-configuration feature. This section of the reference documentation is a good place to start.
In short, Spring Boot adopts a convention over configuration approach. If a dependency is on the classpath, Spring Boot assumes that you want to use it, and configures it with sensible defaults. This is what it's doing with Thymeleaf. You can disable this auto-configuration for a specific dependency using the excludes attribute on #SpringBootApplication:
#SpringBootApplication(exclude={ThymeleafAutoConfiguration.class})
public class ExampleApplication {
}
You can also use the spring.autoconfigure.exclude property to provide a comma-separated list of auto-configuration classes to exclude. Each entry in the list should be the fully-qualified name of an auto-configuration class. You could use this property with #TestPropertySource to disable auto-configuration on a test-by-test basis.
I have been struggling with a similar issue for hours and finally found out the root cause.
If you have a dependency to *-data-rest in your pom like this:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
you will have to add Thymeleaf to your pom as well even if you use a another template engine (Freemarker, JSP, ...) everywhere else.
Reason: to expose a JpaRepository as a rest service Spring Boot requires Thymeleaf. I do not understand why this is not defined as a dependency of spring-boot-starter-data-rest so that Maven resolves it automatically.
In my opinion it is a Spring Boot configuration bug.

Spring-boot: Configure FreeMarkerConfigurationFactoryBean in web application

I'm trying to use Freemarker for e-mail templating in a web application.
I have declared a FreeMarkerConfigurationFactoryBean as follow:
#Bean
public FreeMarkerConfigurationFactoryBean freeMarkerConfigurationFactoryBean(EmailTemplateService templateService) {
FreeMarkerConfigurationFactoryBean configurationFactoryBean = new FreeMarkerConfigurationFactoryBean();
configurationFactoryBean.setPreTemplateLoaders(templateService);
return configurationFactoryBean;
}
When running my JUnit everything is working well, but when running in my webapp my bean is "overriden" by the spring boot FreeMarkerAutoConfiguration.
I have tried to:
remove the spring-boot-starter-freemarker from my gradle file
#EnableAutoConfiguration(exclude = {FreeMarkerAutoConfigurationk.class})
spring.freemarker.enabled=false
But without success. Any idea?
Thanks guys.
As your application is a Web application, it's Spring Boot's FreeMarkerWebConfiguration that you're interested in. It doesn't use a FreeMarkerConfigurationFactoryBean but a FreeMarkerConfigurer. You should create a FreeMarkerConfigurer bean and configure it as required. For example:
#Bean
public FreeMarkerConfigurer freeMarkerConfigurer(EmailTemplateService templateService) {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setPreTemplateLoaders(templateService);
return configurer;
}

Resources