Spring Boot: Using Tomcat context parameters in logback configuration - spring-boot

I have several instances of a Spring Boot app deployed in a unique Tomcat.
Each app is configured with a context.xml file which contains a customer code
<Context path="/myApp1" reloadable="false">
<Parameter name="CUSTOMER_CODE" value="CUSTOMER1" />
</Context>
I wish that each customer has a separate log based on code defined in context.xml.
Unfortunately this config doesn't work in my logback-config.xml:
<property name="LOG_FILE" value="${ROOT_LOG}/${CUSTOMER_CODE}/myApp.log}"/>
A folder CUSTOMER_CODE_IS_UNDEFINED is created in "ROOT_LOG" directory. "ROOT_LOG" is provided by a system property.
Is there any way to make this logback configuration working?
The use of properties defined in application.properties works well (I renamed my logback.xml to logback-spring.xml). It seems to me that Spring boot does not set Tomcat context parameters in Environnement before initialize logging. Any idea for a workaround? Thanks.

I finally found a solution to get my customer code available in Spring Environment bean before logging initialization. Not very pretty but it's working:
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application extends SpringBootServletInitializer {
public static String APP_CUSTOMER_CODE;
/**
* Initialization of Spring Boot App with context param customer code
*/
#Override
protected SpringApplicationBuilder configure(final SpringApplicationBuilder builder) {
final Map<String, Object> initProps = new HashMap<>();
initProps.put("CUSTOMER_CODE", APP_CUSTOMER_CODE);
return builder.properties(initProps).sources(Application.class);
}
/**
* Method called before Spring Initialization
*/
#Override
public void onStartup(final ServletContext servletContext) throws ServletException {
APP_CUSTOMER_CODE = servletContext.getInitParameter("CUSTOMER_CODE");
super.onStartup(servletContext);
}
}
In addidtion, i must declare a springProperty tag in logback-spring.xml to use the variable:
<springProperty name="CUSTOMER_CODE" source="CUSTOMER_CODE"/>

Related

A bean with that name has already been defined in class path resource [path] and overriding is disabled

I have the java configuration for the Spring Data Elaticsearch(using Transport Client) and ESTemplate.
Here some except:
#Configuration
#EnableElasticsearchRepositories(basePackages = "subpackage-in-this-project")
#PropertySource("file:path-to-file")
public class ESConfig {
#Bean
ElasticsearchTemplate elasticsearchTemplate(Client client) {
return new ElasticsearchTemplate(client);
}
#Bean
Client client() {
// configuration of the ES client
}
}
And I have a config that extends the one above in the different project.
#Configuration
#ComponentScan("package-prefix-that-matches-packages-in-both-projects")
#EnableElasticsearchRepositories(basePackages = "subpackage-in-this-project")
#PropertySource("file:same-path-to-file-as-in-the-config-above")
public class ExtendedESConfig extends ESConfig {
#Value("index-name")
private String indexName;
#Bean
public String indexName() {
return indexName;
}
}
Upon executing a third Spring Boot application, which uses the dependency on the project with ExtendedESConfig, I get this and I can't quite understand why does it happen, started to happen after upgrading to 2.2.9.RELEASE from 2.0.5.RELEASE Spring Boot version.
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'elasticsearchTemplate', defined in class path resource [my/package/ESConfig.class], could not be registered. A bean with that name has already been defined in class path resource [my/other/package/ExtendedESConfig.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
2020-08-30 16:49:46 ERROR [main] org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter:40 -
Important remark from my comment:
... sadly, I am not the one who wrote this ES config and built the whole infrastructure around it. ...
At the time of this question, I don't own ExtendedESConfig nor can change it.
Or you can add the next property to your application.properties :
spring.main.allow-bean-definition-overriding=true
The default behaviour of overriding bean has been disabled in Spring Boot 2.1. Spring Boot 2.1 Release Notes
Since you don't own / or don't want to modify both configuration classes. You can exclude parent configuration form your SpringBootApplication class using #ComponentScan
#SpringBootApplication
#ComponentScan(excludeFilters =
{#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ESConfig.class)})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
I had a similar problem with my custom springSecurityFilterChain method, in my #Configuration class. The application told me it couldn't create a Bean named springSecurityFilterChain since it was defined elsewhere (in my case, in a Spring Security package, which, as is your case, I couldn't modify).
I found the solution here and it amounted to simply changing my custom method's name; I chose customFilterChain. So it went from
#Bean
public SecurityFilterChain springSecurityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf().disable()
// etc
}
to:
#Bean
public SecurityFilterChain customFilterChain(HttpSecurity http) throws Exception {
return http
.csrf().disable()
// etc
}
Amazingly it worked. Like the article says, Spring builds the bean using the method's name by default. Hope it helps.
find in your modul: resources/application.properties and write:
spring.main.allow-bean-definition-overriding=true
it help you, you need to enable the beans override mechanism.

Spring Boot + Mybatis #MapperScan and SqlSessionFactory

Im developing a new app using Spring Boot. I use Mybatis for persistance. Im using Java Config for everything I can.
I'm getting this exception when the app starts regarding creating my Mybatis mapper interface
exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
My Sring Boot application class is set up like this
#SpringBootApplication
#MapperScan("com.mydomain.admin.service.dao")
public class AdminApplication {
public static void main(String[] args) {
SpringApplication.run(AdminApplication.class, args);
}
}
The Mybatis mapper interface class is set up like this
package com.mydomain.admin.service.dao;
public interface AdminClientDAO {
#Select("SELECT clientId, name, enabledFlag as enabled, dateAdded, dateUpdated as updateDate FROM client")
public List<Client> findAll();
}
my datasource is configured with spring boot. I've named the properties
spring.datasource.* so spring boot with auto-configure the data source
Now, Im wondering if Im assuming too much spring boot magic. I assumed that spring boot would configure the sqlSessionFactory because mybatis was in the classpath..
Many examples I see show configuring the sqlSessionFactory as a #Bean in the Java Config.. Is this the way it should be done is should spring boot be doing some magic and auto-config it?
I found my issue. I was missing mybatis-spring-boot-starter
I have
#Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
return sessionFactory.getObject();
}
In class called Application.java which extends
org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
And my Application.java is initialized in class which extends
org.springframework.boot.context.web.SpringBootServletInitializer
And the datasource works fine in my Spring-Boot Application.
Hope this helps somebody searching for Spring Boot, Mybatis and SQLSessionFactory with datasource in spring.datasource.*

How to enable async supported for a spring MVC application in java configuration file (Not XML)

I know how to enable async support in a XML configuration, I have done so for filters and servlets by adding tag
async-supported>true/async-supported
How to do it in a Java config file. I create a WebInit class which implements WebApplicationInitializer and overrides onStartUp -what should I do next?
public class WebInit implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
//What to do here, to move from XML to java config
}
}
Along the following lines -
ServletRegistration.Dynamic registration = container.addServlet(servletName, myServlet);
registration.setAsyncSupported(true);
EDIT:
Sorry, did not realize that you were looking for a Spring specific solution. With Spring MVC you would just extend a AbstractAnnotationConfigDispatcherServletInitializer assuming that your root and web contexts are #Configuration based. This initializer in-turn extends from AbstractDispatcherServletInitializer, this class has asyncSupported flag set by default.

Ldap Query - Configuration using Spring Boot

I have a Spring boot application that needs to perform LDAP queries. I'm trying to take the following recommendation from the Spring boot documentation:
"Many Spring configuration examples have been published on the
Internet that use XML configuration. Always try to use the equivalent
Java-base configuration if possible."
In a Spring XML configuration file, I would have used:
<ldap:context-source
url="ldap://localhost:389"
base="cn=Users,dc=test,dc=local"
username="cn=testUser"
password="testPass" />
<ldap:ldap-template id="ldapTemplate" />
<bean id="personRepo" class="com.llpf.ldap.PersonRepoImpl">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>
How would I configure this using a Java-based configuration? I need to be able to change URL, base, username, and password attributes of ldap:context-source without a code rebuild.
The <ldap:context-source> XML tag produces an LdapContextSource bean and the <ldap:ldap-template> XML tag produces an LdapTemplate bean so that's what you need to do in your Java configuration:
#Configuration
#EnableAutoConfiguration
#EnableConfigurationProperties
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
#ConfigurationProperties(prefix="ldap.contextSource")
public LdapContextSource contextSource() {
LdapContextSource contextSource = new LdapContextSource();
return contextSource;
}
#Bean
public LdapTemplate ldapTemplate(ContextSource contextSource) {
return new LdapTemplate(contextSource);
}
#Bean
public PersonRepoImpl personRepo(LdapTemplate ldapTemplate) {
PersonRepoImpl personRepo = new PersonRepoImpl();
personRepo.setLdapTemplate(ldapTemplate);
return personRepo;
}
}
To allow you to change the configuration without a rebuild of your code, I've used Spring Boot's #ConfigurationProperties. This will look in your application's environment for properties prefixed with ldap.contextSource and then apply them to the LdapContextSource bean by calling the matching setter methods. To apply the configuration in the question, you can use an application.properties file with four properties:
ldap.contextSource.url=ldap://localhost:389
ldap.contextSource.base=cn=Users,dc=test,dc=local
ldap.contextSource.userDn=cn=testUser
ldap.contextSource.password=testPass

spring boot with sitemesh

I'm using spring boot, and I would like to use sitemesh3 to my project.
I need to add the sitemesh filter, I create this class :
#Configuration
public class Initializer implements ServletContextInitializer{
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
//Sitemesh
FilterRegistration.Dynamic sitemesh = servletContext.addFilter("sitemesh", new ConfigurableSiteMeshFilter());
EnumSet<DispatcherType> sitemeshDispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD);
sitemesh.addMappingForUrlPatterns(sitemeshDispatcherTypes, true, "*.jsp");
}
}
I created the file sitemesh3.xml in WEB-INF directory but nothing happened, have I missed some configuration?
ServletContextInitializers aren't picked up with Spring Boot. Add the filter to your application configuration and wrap it in a FilterRegistrationBean.
See the Spring Boot reference guide.

Resources