Log4j works for one class and doesn't work for the other class - spring

I am developing a Spring MVC 3.0.4 webapp and Logger factroy doesn't work for the Controller classes other than HomeController.java. I initilize the Logger factory like:
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
private static final Logger logger = LoggerFactory.getLogger(RequestDataController.class);
and
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
is added for both classes
What configuration is missing?

It seems SLF4J is missconfigured. You use it for you own logging and that's a right choice! But Spring has JCL logging framework hardcoded. It's an abstarction layer that is typically configured with Log4J implementation. Please, visit this link where some JCL-to-SLF4J drop-in replacements described. If you want to leave both Log4J and SLF4j in your project than add proper logging preferences into log4j.properties or log4j.xml for core spring packages.

Related

Loading application.properties file in a non SpringBoot application

I've a set of microservices built with spring boot and using feign as client. All is working perfectly, but I have a problem with a non SpringBoot application.
In this case I would like to use configuration properties file (application.properties) to configure different client (like Ribbon).
In my configuration bean I've included #ImportAutoConfiguration for all the components, but configuration is not loaded from properties file.
Is there a way to perform this?
Thanks!
import org.springframework.context.annotation.PropertySource;
#RequestMapping("/url")
#Controller
#PropertySource("classpath:config.properties")
public class StudentController{
#Autowired
private Environment env;
//get properties using keys
//env.getProperty("key");
}
and put config.properties file inside src/main/resources

Logback separation by Spring Boot child() contexts

I am creating child() contexts dynamically in Spring Boot and I would like to log each context to a separated file. Is this possible?
The reason to do that is because I have a dynamic spring-integration configuration for different adapters. This is quite useful for working with different connections with the same adapter configuration but there is much information for just one log file.
I saw a Thread separation even a JNDI context separation but I do not know what is the best way to do this. Is this possible just configuring the logback.xml file?
Update:
Maybe the option is MDC and I am not understanding the concept. For instance, could you explain how to apply MDC for a Spring #MessageEndpoint element with multiple Spring Integration elements such as #Transformer, #ServiceActivator and #Router like the following one:
#MessageEndpoint
public class TestComponents {
private static final Logger LOGGER = LoggerFactory.getLogger(Test.class);
#Router(inputChannel = "inputRouter")
public MessageChannel router(Message<String> demo) {
..
LOGGER.trace(“TEST”);
…
LOGGER.error(“TEST”);
…
}
#ServiceActivator(inputChannel="inputService")
public void service(Message< String > demo) {
..
LOGGER.trace(“TEST”);
..
}
#Transformer(inputChannel="inputTransformer", outputChannel="outputTransformer")
public byte[] transformerToByte(Message<String> demo) {
..
LOGGER.debug(“TEST”);
..
}
}
The example could be also applicable to a #Component with different methods.
I am worry about performance due to the paragraph described in the documentation:
Please note that MDC as implemented by logback-classic assumes that
values are placed into the MDC with moderate frequency
I don't think this can be done easily. I don't have a lot of experience with Logback, but I'm quite familiar with Log4J, Spring, Tomcat and classloading.
Logback, like log4J uses a static factory method to produce a singleton logger, this means that static state is stored in the class loader.
In spring you can specify which class load is used to load the context, but a class loader will only load a class/resource that can't be loaded by the parent class loader (you will discover this if you override URLClassLoader.getResource). This is a problem because when Spring Boot start, logging is initialised and loaded by the 'root' class loader.
The only way I can see you preventing this is to remove the logback jar from your classpath, and create a new URL class loader (containing only the logback jar and configuration) for loading the root Spring context and another class load for loading the child contexts (same jar different configuration). Since the logback jar is not part of the system classpath, you should be able to have two separate logback configuration, because static is scoped by class loaders.
EDIT
Diving a little deeper I noticed that it is not enough to have a class loader that loads logback-core and logback-classic jars, due to the way the LoggingSystem class is initialised (LogSystem line 126, version 1.4.1), the entire spring-boot jar (and potentially every thing else) needs to be loaded by the same class loader. Which means you will not be able to use the jar bundling typically used to run spring boot applications.
You can use MDC (Mapped Diagnostic Context) from logback in combination with SiftingAppender.
Below I'll explain how it should work:
MDC allows you to have a discriminator which can be used to separate log files based on its value. At this stage you need to do MDC.put('child-context-key', 'childContextId') before any top stack method from child context is executed, and MDC.remove('child-context-key') after execution.
After that you can configure ch.qos.logback.classic.sift.SiftingAppender which will use 'child-context-key' value as discriminator to separate your log files.
example:
<appender name="CHILD-CONTEXT-SIFT-APPENDER" class="ch.qos.logback.classic.sift.SiftingAppender">
<discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator">
<key>child-context-key</key>
<defaultValue>defaultChildContextId</defaultValue>
</discriminator>
<sift>
<appender name="CHILD-CONTEXT-SIFT-FILE-APPENDER"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/path/to/your/log/file/${child-context-key}.log
</file>
</sift>
</appender>
Also you can follow this example form logback which shows how to configure separate log files for web application modules based on JNDI discriminator.

Plugin System in Spring Boot for modular applications

I looking for dynamically loading jar in spring boot after compiling, for example I will put jars in some folder and when spring boot is started, all jars from this folder will be injected into spring boot app. I don't know how can I do this with spring boot, and if You know can help me with this, with some example.
I need this jars to have #Service, #Controller as this will be module (plugin), with adding capabilities to my spring boot app.
Is possible to do this with spring boot, and if it is possible, please provide me with some sample code.
Thanks in advance.
UPDATE:
I found something https://www.youtube.com/watch?v=F-sw2pFdcDw https://code.google.com/p/jspf/
UPDATE 2: I can't get #Controller bean from plugin jar registered in Spring Boot
Have a look at FlexiCore, an open-source framework that brings modularity to spring boot utilizing plugins(jars) loaded at runtime See wizzdi and FlexiCore.
for example FlexiCore allows you to create a project ( compiled into a seperate jar from your main application) that contains a spring bean as follows:
#Component
#Extension
public class HelloWorldService implements ServicePlugin{
public String hello() {
return "Hello World!";
}
}
it will be automatically be loaded once placed inside the designated plugins folder, it basically allows a full support for most(all) of spring boot features , so for example you can add a RestController bean to your jar as well , FlexiCore will automatically load that bean allowing you to call the controller as if it was in your main application jar:
#RestController
#Extension
public class TestEntityController implements Plugin {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
#Autowired
private TestEntityService testEntityService;
#PostMapping("/createTestEntity")
public TestEntity createTestEntity(#RequestParam(name="name", required=false, defaultValue="Stranger") String name) {
return testEntityService.createTestEntity(name);
}
#GetMapping("{id}")
public TestEntity getTestEntity(#PathVariable("id")String id) {
return testEntityService.getTestEntity(id);
}
}
Disclaimer: I am the CTO of wizzdi, the company powering FlexiCore.
One option is definitely to just use broad #ComponentScan. If you add new jar to classpath the annotated classes from that jar will get discovered via #ComponentScan, #Controllers will get mapped etc.
The XML equivalent here would be placing xml configuration files somewhere to your classpath (META-INF folder being obvious choice) and import them all using wildcard. The idea is the same. If the plugin jar file is on classpath you will get the xml file imported and the beans (controllers, ...) will get loaded.
There are drawbacks to this approach like the modules not being isolated but its definitely option for simpler applications.
You can find a sample spring boot web project here.
By dynamically loading jars I assume you want to add dependencies to your project. For this you can update pom.xml of the sample project and put your dependencies here.

#Provider AND Registration in Application(ResourceConfig) requirement for custom MessageBodyWriter/Reader?

Is there a requirement that a custom MessageBodyWriter and MessageBodyReader must not only be annotated by #Provider annotation AND also be included in the Application configuration through Application or ResourceConfig. If yes, why?
My train of thought was that, if classes are annotated with #Provider then the JAX-RS runtime by default loads such classes as it's runtime component. Declaring the same class inside the Application makes is a redundant exercise. It appears my train of thought is wrong, but I am looking for some kind of explanation on how and why this has been designed this way(ie both annotation and Application configuration).
I can understand that some form of Application configuration would be required on the Jersey Client side, but am not very confident about that either.
For instance, the JavaMarshaller class below has been annotated with #Provider
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.ext.Provider;
#Provider
#Produces("application/example-java")
#Consumes("application/example-java")
public class JavaMarshaller implements MessageBodyReader, MessageBodyWriter {
.......
Now in the Application class is it required to do as below?
#ApplicationPath("services")
public class ShoppingApplication extends Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> classes = new HashSet<Class<?>>();
public ShoppingApplication() {
classes.add(JavaMarshaller.class);
}
.........
Typically, the registration of classes dynamically is a feature of application servers. Since your'e deploying to tomcat, Jersey will likely expect that you're listing your providers and resources in your Application class.
If you were deploying to a full app server, like WildFly or GlassFish, you wouldn't need to do this.

Avoid applicationContext.xml in my Action and Service Classes

I am writing a web application using Struts, Spring framework.
In the Struts Action I am Injecting Service Classes as follows
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
loginService = (LoginService)context.getBean("loginService");
How can I avoid mentioning applicationContext.xml in my Action classes I just have to use
loginService = (LoginService)context.getBean("loginService"); without specifying the .xml file in my class.
I came across to use below while googling
private LoginService loginService = (LoginService)ApplicationContextProvider.getContext().getBean("loginService");
But I do not want to use static method getContext().
Spring support Struts integration in the package org.springframework.web.struts.
Take a look at this article for an example.

Resources