Spring's optimized Commons Logging bridge with automatic detection of Log4J 2, SLF4J, and java.util.logging
npx @tessl/cli install tessl/maven-org-springframework--spring-jcl@6.2.0Spring JCL (Java Commons Logging) is Spring's variant of the Apache Commons Logging API that provides a minimized and optimized logging bridge specifically designed for Spring Framework's internal logging needs. It offers special support for Log4J 2, SLF4J, and java.util.logging with automatic detection of available logging frameworks in the classpath.
Package Name: org.springframework:spring-jcl
Package Type: Maven
Language: Java
Installation:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jcl</artifactId>
<version>6.2.8</version>
</dependency>Gradle:
implementation 'org.springframework:spring-jcl:6.2.8'import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;For implementation classes (optional):
import org.apache.commons.logging.LogFactoryService;
import org.apache.commons.logging.impl.NoOpLog;
import org.apache.commons.logging.impl.SimpleLog;Internal classes (not typically imported directly):
import org.apache.commons.logging.LogAdapter;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class MyService {
private static final Log logger = LogFactory.getLog(MyService.class);
public void doSomething() {
logger.info("Starting operation");
try {
// Your code here
logger.debug("Operation in progress");
} catch (Exception e) {
logger.error("Operation failed", e);
throw e;
}
logger.info("Operation completed");
}
}Spring JCL is built around several key components:
Creates logger instances with automatic framework detection and optimization.
/**
* Main factory class for obtaining Log instances with automatic adapter detection
*/
public abstract class LogFactory {
/**
* Convenience method to return a named logger
* @param clazz containing Class from which a log name will be derived
* @return Log instance for the class
*/
public static Log getLog(Class<?> clazz);
/**
* Convenience method to return a named logger
* @param name logical name of the Log instance to be returned
* @return Log instance for the name
*/
public static Log getLog(String name);
}Deprecated Methods (for compatibility):
/**
* @deprecated in favor of getLog(Class)/getLog(String)
*/
@Deprecated
public static LogFactory getFactory();
/**
* @deprecated in favor of getLog(Class)
*/
@Deprecated
public Log getInstance(Class<?> clazz);
/**
* @deprecated in favor of getLog(String)
*/
@Deprecated
public Log getInstance(String name);
/**
* @deprecated no-op method for compatibility
*/
@Deprecated
public static void release(ClassLoader classLoader);
/**
* @deprecated no-op method for compatibility
*/
@Deprecated
public static void releaseAll();
/**
* @deprecated utility method for object identification
* Returns string representation with class name and identity hash code
*/
@Deprecated
public static String objectId(Object o);
// Abstract methods (for subclass implementation)
/**
* @deprecated abstract method for attribute access
*/
@Deprecated
public abstract Object getAttribute(String name);
/**
* @deprecated abstract method for attribute name retrieval
*/
@Deprecated
public abstract String[] getAttributeNames();
/**
* @deprecated abstract method for attribute removal
*/
@Deprecated
public abstract void removeAttribute(String name);
/**
* @deprecated abstract method for attribute setting
*/
@Deprecated
public abstract void setAttribute(String name, Object value);
/**
* @deprecated abstract method for factory release
*/
@Deprecated
public abstract void release();Core logging interface providing six logging levels with conditional checks for performance.
/**
* A simple logging interface abstracting logging APIs
*/
public interface Log {
// Level check methods (for performance optimization)
boolean isFatalEnabled();
boolean isErrorEnabled();
boolean isWarnEnabled();
boolean isInfoEnabled();
boolean isDebugEnabled();
boolean isTraceEnabled();
// Fatal level logging
void fatal(Object message);
void fatal(Object message, Throwable t);
// Error level logging
void error(Object message);
void error(Object message, Throwable t);
// Warn level logging
void warn(Object message);
void warn(Object message, Throwable t);
// Info level logging
void info(Object message);
void info(Object message, Throwable t);
// Debug level logging
void debug(Object message);
void debug(Object message, Throwable t);
// Trace level logging
void trace(Object message);
void trace(Object message, Throwable t);
}Usage Examples:
// Performance-optimized logging
if (logger.isDebugEnabled()) {
logger.debug("Processing user: " + user.getName() + " with ID: " + user.getId());
}
// Exception logging
try {
processData();
} catch (DataProcessingException e) {
logger.error("Failed to process data for user: " + userId, e);
throw e;
}
// Different logging levels
logger.trace("Entering method with params: " + params);
logger.debug("Intermediate calculation result: " + result);
logger.info("User " + username + " logged in successfully");
logger.warn("Deprecated API usage detected in class: " + className);
logger.error("Database connection failed", connectionException);
logger.fatal("System is shutting down due to critical error", criticalError);Fallback service implementation for META-INF service discovery compatibility when commons-logging.jar is accidentally on classpath.
/**
* @deprecated since it is only meant to be used in fallback scenario when commons-logging.jar is accidentally on classpath
*/
@Deprecated
public class LogFactoryService extends LogFactory {
/**
* Constructor that prints compatibility warning about commons-logging.jar conflicts
* Prints message: "Standard Commons Logging discovery in action with spring-jcl: please remove commons-logging.jar from classpath in order to avoid potential conflicts"
*/
public LogFactoryService();
/**
* Get logger instance for class - delegates to LogAdapter.createLog()
* @param clazz containing Class from which a log name will be derived
* @return Log instance for the class
*/
public Log getInstance(Class<?> clazz);
/**
* Get logger instance by name - delegates to LogAdapter.createLog()
* @param name logical name of the Log instance to be returned
* @return Log instance for the name
*/
public Log getInstance(String name);
// Attribute management methods (for compatibility) - uses ConcurrentHashMap
/**
* Set attribute value (null values remove the attribute)
*/
public void setAttribute(String name, Object value);
/**
* Remove attribute by name
*/
public void removeAttribute(String name);
/**
* Get attribute value
* @return attribute value or null if not found
*/
public Object getAttribute(String name);
/**
* Get all attribute names
* @return array of attribute names
*/
public String[] getAttributeNames();
/**
* Release resources - no-op method for compatibility
*/
public void release();
}Basic logger implementations for specific use cases.
/**
* Trivial implementation of Log that throws away all messages
*/
public class NoOpLog implements Log, Serializable {
public NoOpLog();
public NoOpLog(String name);
// All methods return false for level checks and are no-op for logging methods
}
/**
* @deprecated in spring-jcl (effectively equivalent to NoOpLog)
*/
@Deprecated
public class SimpleLog extends NoOpLog {
/**
* Constructor that prints deprecation warning
* Prints message: "SimpleLog is deprecated and equivalent to NoOpLog in spring-jcl. Use a standard LogFactory.getLog(Class/String) call instead."
* @param name logger name
*/
public SimpleLog(String name);
}/**
* Main logging interface with six levels: trace, debug, info, warn, error, fatal
*/
public interface Log {
// See Logging Interface section above for complete method signatures
}
/**
* Abstract factory class for obtaining Log instances
*/
public abstract class LogFactory {
// See Logger Factory section above for complete method signatures
}
/**
* Service implementation extending LogFactory for compatibility
* @deprecated only for fallback compatibility scenarios
*/
@Deprecated
public class LogFactoryService extends LogFactory {
// See Service Implementation section above for complete method signatures
}
/**
* No-operation logger implementation
*/
public class NoOpLog implements Log, java.io.Serializable {
// See Implementation Classes section above for complete method signatures
}
/**
* @deprecated Simple logger implementation (equivalent to NoOpLog)
*/
@Deprecated
public class SimpleLog extends NoOpLog {
// See Implementation Classes section above for complete method signatures
}Internal adapter class that handles automatic logging framework detection and logger creation.
/**
* Internal adapter class for framework detection and logger creation
* This class is not part of the public API but is referenced by LogFactory
*/
final class LogAdapter {
/**
* Create Log instance using detected logging framework
* @param name the logger name
* @return Log instance using the best available logging framework
*/
public static Log createLog(String name);
}Internal Implementation Classes:
// Log4J 2 implementation (when Log4J 2 is available)
private static class Log4jLog implements Log, Serializable {
public Log4jLog(String name);
// Implements all Log interface methods with Log4J 2 ExtendedLogger
}
// SLF4J implementation (when SLF4J is available)
private static class Slf4jLog<T extends Logger> implements Log, Serializable {
public Slf4jLog(T logger);
// Implements all Log interface methods with SLF4J Logger
}
// SLF4J with location awareness (when LocationAwareLogger is available)
private static class Slf4jLocationAwareLog extends Slf4jLog<LocationAwareLogger> {
public Slf4jLocationAwareLog(LocationAwareLogger logger);
// Implements all Log interface methods with location-aware SLF4J logging
}
// Java Util Logging implementation (fallback)
private static class JavaUtilLog implements Log, Serializable {
public JavaUtilLog(String name);
// Implements all Log interface methods with java.util.logging.Logger
}Note: These internal classes are implementation details and should not be used directly. Use LogFactory.getLog() methods instead.
Spring JCL automatically detects and prioritizes logging frameworks through the LogAdapter class in this order:
org.apache.logging.log4j.spi.ExtendedLogger and org.apache.logging.slf4j.SLF4JProvider are detected along with org.slf4j.spi.LocationAwareLogger, it uses SLF4J with location awareness to avoid the log4j-to-slf4j bridge conflictorg.apache.logging.log4j.spi.ExtendedLogger directly when available (and no SLF4J bridge detected)org.slf4j.spi.LocationAwareLogger when availableorg.slf4j.Logger when availablejava.util.logging.Logger as defaultThe detection is automatic and requires no configuration. The LogAdapter uses Class.forName() to detect available logging frameworks on the classpath.
Spring JCL handles logging framework detection failures gracefully:
No exceptions are thrown during logger creation - the system always provides a working logger instance, falling back to java.util.logging if all other frameworks fail.
isDebugEnabled(), etc.) before expensive string operationsLogFactory.getLog(Class.class) over string names for better IDE supportLogFactory.getLog() instead of deprecated getInstance() methods