关键词:
系列目录
spi 05-dubbo adaptive extension 自适应拓展
实际应用
slf4j 版本冲突
slf4j 和较低版本的 lo4j 的日志接口冲突。
使用高版本,低版本的 log4j 接口和 高版本的 slf4j 如何统一呢?
取巧的方式,利用 spi 首先加载当前包的规则,写一个将二者融合起来的。
代码示例
- LocationAwareLogger.java
重新定义,同时支持 2 个不同版本的接口。
package org.slf4j.spi;
import org.slf4j.Logger;
import org.slf4j.Marker;
public interface LocationAwareLogger extends Logger {
int TRACE_INT = 00;
int DEBUG_INT = 10;
int INFO_INT = 20;
int WARN_INT = 30;
int ERROR_INT = 40;
/**
* Printing method with support for location information.
*
* @param marker
* @param fqcn The fully qualified class name of the <b>caller</b>
* @param level
* @param message
* @param t
*/
void log(Marker marker, String fqcn, int level, String message, Throwable t);
/**
* Printing method with support for location information.
*
* @param marker The marker to be used for this event, may be null.
* @param fqcn The fully qualified class name of the <b>logger instance</b>,
* typically the logger class, logger bridge or a logger wrapper.
* @param level One of the level integers defined in this interface
* @param message The message for the log event
* @param t Throwable associated with the log event, may be null.
*/
void log(Marker marker, String fqcn, int level, String message, Object[] argArray, Throwable t);
}
- Logger.java
实现
/**
* Logback: the reliable, generic, fast and flexible logging framework.
* Copyright (C) 1999-2015, QOS.ch. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee‘s choosing)
*
* under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation.
*/
package ch.qos.logback.classic;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.spi.LocationAwareLogger;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.classic.util.LoggerNameUtil;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.CoreConstants;
import ch.qos.logback.core.spi.AppenderAttachable;
import ch.qos.logback.core.spi.AppenderAttachableImpl;
import ch.qos.logback.core.spi.FilterReply;
@SuppressWarnings("AlibabaLowerCamelCaseVariableNaming")
public final class Logger implements org.slf4j.Logger, LocationAwareLogger, AppenderAttachable<ILoggingEvent>, Serializable {
private static final long serialVersionUID = 5454405123156820674L; // 8745934908040027998L;
/**
* The fully qualified name of this class. Used in gathering caller
* information.
*/
public static final String FQCN = Logger.class.getName();
/**
* The name of this logger
*/
private String name;
// The assigned levelInt of this logger. Can be null.
transient private Level level;
// The effective levelInt is the assigned levelInt and if null, a levelInt is
// inherited form a parent.
transient private int effectiveLevelInt;
/**
* The parent of this category. All categories have at least one ancestor
* which is the root category.
*/
transient private Logger parent;
/**
* The children of this logger. A logger may have zero or more children.
*/
transient private List<Logger> childrenList;
/**
* It is assumed that once the ‘aai‘ variable is set to a non-null value, it
* will never be reset to null. it is further assumed that only place where
* the ‘aai‘ariable is set is within the addAppender method. This method is
* synchronized on ‘this‘ (Logger) protecting against simultaneous
* re-configuration of this logger (a very unlikely scenario).
*
* <p>
* It is further assumed that the AppenderAttachableImpl is responsible for
* its internal synchronization and thread safety. Thus, we can get away with
* *not* synchronizing on the ‘aai‘ (check null/ read) because
* <p>
* 1) the ‘aai‘ variable is immutable once set to non-null
* <p>
* 2) ‘aai‘ is getAndSet only within addAppender which is synchronized
* <p>
* 3) all the other methods check whether ‘aai‘ is null
* <p>
* 4) AppenderAttachableImpl is thread safe
*/
transient private AppenderAttachableImpl<ILoggingEvent> aai;
/**
* Additivity is set to true by default, that is children inherit the
* appenders of their ancestors by default. If this variable is set to
* <code>false</code> then the appenders located in the ancestors of this
* logger will not be used. However, the children of this logger will inherit
* its appenders, unless the children have their additivity flag set to
* <code>false</code> too. See the user manual for more details.
*/
transient private boolean additive = true;
final transient LoggerContext loggerContext;
Logger(String name, Logger parent, LoggerContext loggerContext) {
this.name = name;
this.parent = parent;
this.loggerContext = loggerContext;
}
public Level getEffectiveLevel() {
return Level.toLevel(effectiveLevelInt);
}
int getEffectiveLevelInt() {
return effectiveLevelInt;
}
public Level getLevel() {
return level;
}
public String getName() {
return name;
}
public void log(Marker marker, String fqcn, int levelInt, String message, Throwable t) {
Level level = Level.fromLocationAwareLoggerInteger(levelInt);
filterAndLog_0_Or3Plus(fqcn, marker, level, message, new Object[]{}, t);
}
private boolean isRootLogger() {
// only the root logger has a null parent
return parent == null;
}
Logger getChildByName(final String childName) {
if (childrenList == null) {
return null;
} else {
int len = this.childrenList.size();
for (int i = 0; i < len; i++) {
final Logger childLogger_i = (Logger) childrenList.get(i);
final String childName_i = childLogger_i.getName();
if (childName.equals(childName_i)) {
return childLogger_i;
}
}
// no child found
return null;
}
}
public synchronized void setLevel(Level newLevel) {
if (level == newLevel) {
// nothing to do;
return;
}
if (newLevel == null && isRootLogger()) {
throw new IllegalArgumentException("The level of the root logger cannot be set to null");
}
level = newLevel;
if (newLevel == null) {
effectiveLevelInt = parent.effectiveLevelInt;
newLevel = parent.getEffectiveLevel();
} else {
effectiveLevelInt = newLevel.levelInt;
}
if (childrenList != null) {
int len = childrenList.size();
for (int i = 0; i < len; i++) {
Logger child = (Logger) childrenList.get(i);
// tell child to handle parent levelInt change
child.handleParentLevelChange(effectiveLevelInt);
}
}
// inform listeners
loggerContext.fireOnLevelChange(this, newLevel);
}
/**
* This method is invoked by parent logger to let this logger know that the
* prent‘s levelInt changed.
*
* @param newParentLevelInt
*/
private synchronized void handleParentLevelChange(int newParentLevelInt) {
// changes in the parent levelInt affect children only if their levelInt is
// null
if (level == null) {
effectiveLevelInt = newParentLevelInt;
// propagate the parent levelInt change to this logger‘s children
if (childrenList != null) {
int len = childrenList.size();
for (int i = 0; i < len; i++) {
Logger child = (Logger) childrenList.get(i);
child.handleParentLevelChange(newParentLevelInt);
}
}
}
}
/**
* Remove all previously added appenders from this logger instance.
* <p/>
* This is useful when re-reading configuration information.
*/
public void detachAndStopAllAppenders() {
if (aai != null) {
aai.detachAndStopAllAppenders();
}
}
public boolean detachAppender(String name) {
if (aai == null) {
return false;
}
return aai.detachAppender(name);
}
// this method MUST be synchronized. See comments on ‘aai‘ field for further
// details.
public synchronized void addAppender(Appender<ILoggingEvent> newAppender) {
if (aai == null) {
aai = new AppenderAttachableImpl<ILoggingEvent>();
}
aai.addAppender(newAppender);
}
public boolean isAttached(Appender<ILoggingEvent> appender) {
if (aai == null) {
return false;
}
return aai.isAttached(appender);
}
@SuppressWarnings("unchecked")
public Iterator<Appender<ILoggingEvent>> iteratorForAppenders() {
if (aai == null) {
return Collections.EMPTY_LIST.iterator();
}
return aai.iteratorForAppenders();
}
public Appender<ILoggingEvent> getAppender(String name) {
if (aai == null) {
return null;
}
return aai.getAppender(name);
}
/**
* Invoke all the appenders of this logger.
*
* @param event
* The event to log
*/
public void callAppenders(ILoggingEvent event) {
int writes = 0;
for (Logger l = this; l != null; l = l.parent) {
writes += l.appendLoopOnAppenders(event);
if (!l.additive) {
break;
}
}
// No appenders in hierarchy
if (writes == 0) {
loggerContext.noAppenderDefinedWarning(this);
}
}
private int appendLoopOnAppenders(ILoggingEvent event) {
if (aai != null) {
return aai.appendLoopOnAppenders(event);
} else {
return 0;
}
}
/**
* Remove the appender passed as parameter form the list of appenders.
*/
public boolean detachAppender(Appender<ILoggingEvent> appender) {
if (aai == null) {
return false;
}
return aai.detachAppender(appender);
}
/**
* Create a child of this logger by suffix, that is, the part of the name
* extending this logger. For example, if this logger is named "x.y" and the
* lastPart is "z", then the created child logger will be named "x.y.z".
*
* <p>
* IMPORTANT: Calls to this method must be within a synchronized block on this
* logger.
*
* @param lastPart
* the suffix (i.e. last part) of the child logger name. This
* parameter may not include dots, i.e. the logger separator
* character.
* @return
*/
Logger createChildByLastNamePart(final String lastPart) {
int i_index = LoggerNameUtil.getFirstSeparatorIndexOf(lastPart);
if (i_index != -1) {
throw new IllegalArgumentException("Child name [" + lastPart + " passed as parameter, may not include [" + CoreConstants.DOT + "]");
}
if (childrenList == null) {
childrenList = new CopyOnWriteArrayList<Logger>();
}
Logger childLogger;
if (this.isRootLogger()) {
childLogger = new Logger(lastPart, this, this.loggerContext);
} else {
childLogger = new Logger(name + CoreConstants.DOT + lastPart, this, this.loggerContext);
}
childrenList.add(childLogger);
childLogger.effectiveLevelInt = this.effectiveLevelInt;
return childLogger;
}
private void localLevelReset() {
effectiveLevelInt = Level.DEBUG_INT;
if (isRootLogger()) {
level = Level.DEBUG;
} else {
level = null;
}
}
void recursiveReset() {
detachAndStopAllAppenders();
localLevelReset();
additive = true;
if (childrenList == null) {
return;
}
for (Logger childLogger : childrenList) {
childLogger.recursiveReset();
}
}
/**
* The default size of child list arrays. The JDK 1.5 default is 10. We use a
* smaller value to save a little space.
*/
Logger createChildByName(final String childName) {
int i_index = LoggerNameUtil.getSeparatorIndexOf(childName, this.name.length() + 1);
if (i_index != -1) {
throw new IllegalArgumentException("For logger [" + this.name + "] child name [" + childName
+ " passed as parameter, may not include ‘.‘ after index" + (this.name.length() + 1));
}
if (childrenList == null) {
childrenList = new CopyOnWriteArrayList<Logger>();
}
Logger childLogger;
childLogger = new Logger(childName, this, this.loggerContext);
childrenList.add(childLogger);
childLogger.effectiveLevelInt = this.effectiveLevelInt;
return childLogger;
}
/**
* The next methods are not merged into one because of the time we gain by not
* creating a new Object[] with the params. This reduces the cost of not
* logging by about 20 nanoseconds.
*/
private void filterAndLog_0_Or3Plus(final String localFQCN, final Marker marker, final Level level, final String msg, final Object[] params,
final Throwable t) {
final FilterReply decision = loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this, level, msg, params, t);
if (decision == FilterReply.NEUTRAL) {
if (effectiveLevelInt > level.levelInt) {
return;
}
} else if (decision == FilterReply.DENY) {
return;
}
buildLoggingEventAndAppend(localFQCN, marker, level, msg, params, t);
}
private void filterAndLog_1(final String localFQCN, final Marker marker, final Level level, final String msg, final Object param, final Throwable t) {
final FilterReply decision = loggerContext.getTurboFilterChainDecision_1(marker, this, level, msg, param, t);
if (decision == FilterReply.NEUTRAL) {
if (effectiveLevelInt > level.levelInt) {
return;
}
} else if (decision == FilterReply.DENY) {
return;
}
buildLoggingEventAndAppend(localFQCN, marker, level, msg, new Object[] { param }, t);
}
private void filterAndLog_2(final String localFQCN, final Marker marker, final Level level, final String msg, final Object param1, final Object param2,
final Throwable t) {
final FilterReply decision = loggerContext.getTurboFilterChainDecision_2(marker, this, level, msg, param1, param2, t);
if (decision == FilterReply.NEUTRAL) {
if (effectiveLevelInt > level.levelInt) {
return;
}
} else if (decision == FilterReply.DENY) {
return;
}
buildLoggingEventAndAppend(localFQCN, marker, level, msg, new Object[] { param1, param2 }, t);
}
private void buildLoggingEventAndAppend(final String localFQCN, final Marker marker, final Level level, final String msg, final Object[] params,
final Throwable t) {
LoggingEvent le = new LoggingEvent(localFQCN, this, level, msg, t, params);
le.setMarker(marker);
callAppenders(le);
}
public void trace(String msg) {
filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, msg, null, null);
}
public void trace(String format, Object arg) {
filterAndLog_1(FQCN, null, Level.TRACE, format, arg, null);
}
public void trace(String format, Object arg1, Object arg2) {
filterAndLog_2(FQCN, null, Level.TRACE, format, arg1, arg2, null);
}
public void trace(String format, Object... argArray) {
filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, format, argArray, null);
}
public void trace(String msg, Throwable t) {
filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, msg, null, t);
}
public void trace(Marker marker, String msg) {
filterAndLog_0_Or3Plus(FQCN, marker, Level.TRACE, msg, null, null);
}
public void trace(Marker marker, String format, Object arg) {
filterAndLog_1(FQCN, marker, Level.TRACE, format, arg, null);
}
public void trace(Marker marker, String format, Object arg1, Object arg2) {
filterAndLog_2(FQCN, marker, Level.TRACE, format, arg1, arg2, null);
}
public void trace(Marker marker, String format, Object... argArray) {
filterAndLog_0_Or3Plus(FQCN, marker, Level.TRACE, format, argArray, null);
}
public void trace(Marker marker, String msg, Throwable t) {
filterAndLog_0_Or3Plus(FQCN, marker, Level.TRACE, msg, null, t);
}
public boolean isDebugEnabled() {
return isDebugEnabled(null);
}
public boolean isDebugEnabled(Marker marker) {
final FilterReply decision = callTurboFilters(marker, Level.DEBUG);
if (decision == FilterReply.NEUTRAL) {
return effectiveLevelInt <= Level.DEBUG_INT;
} else if (decision == FilterReply.DENY) {
return false;
} else if (decision == FilterReply.ACCEPT) {
return true;
} else {
throw new IllegalStateException("Unknown FilterReply value: " + decision);
}
}
public void debug(String msg) {
filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, msg, null, null);
}
public void debug(String format, Object arg) {
filterAndLog_1(FQCN, null, Level.DEBUG, format, arg, null);
}
public void debug(String format, Object arg1, Object arg2) {
filterAndLog_2(FQCN, null, Level.DEBUG, format, arg1, arg2, null);
}
public void debug(String format, Object... argArray) {
filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, format, argArray, null);
}
public void debug(String msg, Throwable t) {
filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, msg, null, t);
}
public void debug(Marker marker, String msg) {
filterAndLog_0_Or3Plus(FQCN, marker, Level.DEBUG, msg, null, null);
}
public void debug(Marker marker, String format, Object arg) {
filterAndLog_1(FQCN, marker, Level.DEBUG, format, arg, null);
}
public void debug(Marker marker, String format, Object arg1, Object arg2) {
filterAndLog_2(FQCN, marker, Level.DEBUG, format, arg1, arg2, null);
}
public void debug(Marker marker, String format, Object... argArray) {
filterAndLog_0_Or3Plus(FQCN, marker, Level.DEBUG, format, argArray, null);
}
public void debug(Marker marker, String msg, Throwable t) {
filterAndLog_0_Or3Plus(FQCN, marker, Level.DEBUG, msg, null, t);
}
public void error(String msg) {
filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, msg, null, null);
}
public void error(String format, Object arg) {
filterAndLog_1(FQCN, null, Level.ERROR, format, arg, null);
}
public void error(String format, Object arg1, Object arg2) {
filterAndLog_2(FQCN, null, Level.ERROR, format, arg1, arg2, null);
}
public void error(String format, Object... argArray) {
filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, format, argArray, null);
}
public void error(String msg, Throwable t) {
filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, msg, null, t);
}
public void error(Marker marker, String msg) {
filterAndLog_0_Or3Plus(FQCN, marker, Level.ERROR, msg, null, null);
}
public void error(Marker marker, String format, Object arg) {
filterAndLog_1(FQCN, marker, Level.ERROR, format, arg, null);
}
public void error(Marker marker, String format, Object arg1, Object arg2) {
filterAndLog_2(FQCN, marker, Level.ERROR, format, arg1, arg2, null);
}
public void error(Marker marker, String format, Object... argArray) {
filterAndLog_0_Or3Plus(FQCN, marker, Level.ERROR, format, argArray, null);
}
public void error(Marker marker, String msg, Throwable t) {
filterAndLog_0_Or3Plus(FQCN, marker, Level.ERROR, msg, null, t);
}
public boolean isInfoEnabled() {
return isInfoEnabled(null);
}
public boolean isInfoEnabled(Marker marker) {
FilterReply decision = callTurboFilters(marker, Level.INFO);
if (decision == FilterReply.NEUTRAL) {
return effectiveLevelInt <= Level.INFO_INT;
} else if (decision == FilterReply.DENY) {
return false;
} else if (decision == FilterReply.ACCEPT) {
return true;
} else {
throw new IllegalStateException("Unknown FilterReply value: " + decision);
}
}
public void info(String msg) {
filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, msg, null, null);
}
public void info(String format, Object arg) {
filterAndLog_1(FQCN, null, Level.INFO, format, arg, null);
}
public void info(String format, Object arg1, Object arg2) {
filterAndLog_2(FQCN, null, Level.INFO, format, arg1, arg2, null);
}
public void info(String format, Object... argArray) {
filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, format, argArray, null);
}
public void info(String msg, Throwable t) {
filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, msg, null, t);
}
public void info(Marker marker, String msg) {
filterAndLog_0_Or3Plus(FQCN, marker, Level.INFO, msg, null, null);
}
public void info(Marker marker, String format, Object arg) {
filterAndLog_1(FQCN, marker, Level.INFO, format, arg, null);
}
public void info(Marker marker, String format, Object arg1, Object arg2) {
filterAndLog_2(FQCN, marker, Level.INFO, format, arg1, arg2, null);
}
public void info(Marker marker, String format, Object... argArray) {
filterAndLog_0_Or3Plus(FQCN, marker, Level.INFO, format, argArray, null);
}
public void info(Marker marker, String msg, Throwable t) {
filterAndLog_0_Or3Plus(FQCN, marker, Level.INFO, msg, null, t);
}
public boolean isTraceEnabled() {
return isTraceEnabled(null);
}
public boolean isTraceEnabled(Marker marker) {
final FilterReply decision = callTurboFilters(marker, Level.TRACE);
if (decision == FilterReply.NEUTRAL) {
return effectiveLevelInt <= Level.TRACE_INT;
} else if (decision == FilterReply.DENY) {
return false;
} else if (decision == FilterReply.ACCEPT) {
return true;
} else {
throw new IllegalStateException("Unknown FilterReply value: " + decision);
}
}
public boolean isErrorEnabled() {
return isErrorEnabled(null);
}
public boolean isErrorEnabled(Marker marker) {
FilterReply decision = callTurboFilters(marker, Level.ERROR);
if (decision == FilterReply.NEUTRAL) {
return effectiveLevelInt <= Level.ERROR_INT;
} else if (decision == FilterReply.DENY) {
return false;
} else if (decision == FilterReply.ACCEPT) {
return true;
} else {
throw new IllegalStateException("Unknown FilterReply value: " + decision);
}
}
public boolean isWarnEnabled() {
return isWarnEnabled(null);
}
public boolean isWarnEnabled(Marker marker) {
FilterReply decision = callTurboFilters(marker, Level.WARN);
if (decision == FilterReply.NEUTRAL) {
return effectiveLevelInt <= Level.WARN_INT;
} else if (decision == FilterReply.DENY) {
return false;
} else if (decision == FilterReply.ACCEPT) {
return true;
} else {
throw new IllegalStateException("Unknown FilterReply value: " + decision);
}
}
public boolean isEnabledFor(Marker marker, Level level) {
FilterReply decision = callTurboFilters(marker, level);
if (decision == FilterReply.NEUTRAL) {
return effectiveLevelInt <= level.levelInt;
} else if (decision == FilterReply.DENY) {
return false;
} else if (decision == FilterReply.ACCEPT) {
return true;
} else {
throw new IllegalStateException("Unknown FilterReply value: " + decision);
}
}
public boolean isEnabledFor(Level level) {
return isEnabledFor(null, level);
}
public void warn(String msg) {
filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, msg, null, null);
}
public void warn(String msg, Throwable t) {
filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, msg, null, t);
}
public void warn(String format, Object arg) {
filterAndLog_1(FQCN, null, Level.WARN, format, arg, null);
}
public void warn(String format, Object arg1, Object arg2) {
filterAndLog_2(FQCN, null, Level.WARN, format, arg1, arg2, null);
}
public void warn(String format, Object... argArray) {
filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, format, argArray, null);
}
public void warn(Marker marker, String msg) {
filterAndLog_0_Or3Plus(FQCN, marker, Level.WARN, msg, null, null);
}
public void warn(Marker marker, String format, Object arg) {
filterAndLog_1(FQCN, marker, Level.WARN, format, arg, null);
}
public void warn(Marker marker, String format, Object... argArray) {
filterAndLog_0_Or3Plus(FQCN, marker, Level.WARN, format, argArray, null);
}
public void warn(Marker marker, String format, Object arg1, Object arg2) {
filterAndLog_2(FQCN, marker, Level.WARN, format, arg1, arg2, null);
}
public void warn(Marker marker, String msg, Throwable t) {
filterAndLog_0_Or3Plus(FQCN, marker, Level.WARN, msg, null, t);
}
public boolean isAdditive() {
return additive;
}
public void setAdditive(boolean additive) {
this.additive = additive;
}
@Override
public String toString() {
return "Logger[" + name + "]";
}
/**
* Method that calls the attached TurboFilter objects based on the logger and
* the level.
*
* It is used by isYYYEnabled() methods.
*
* It returns the typical FilterReply values: ACCEPT, NEUTRAL or DENY.
*
* @param level
* @return the reply given by the TurboFilters
*/
private FilterReply callTurboFilters(Marker marker, Level level) {
return loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this, level, null, null, null);
}
/**
* Return the context for this logger.
*
* @return the context
*/
public LoggerContext getLoggerContext() {
return loggerContext;
}
@Override
public void log(Marker marker, String fqcn, int levelInt, String message, Object[] argArray, Throwable t) {
Level level = Level.fromLocationAwareLoggerInteger(levelInt);
filterAndLog_0_Or3Plus(fqcn, marker, level, message, argArray, t);
}
/**
* Support SLF4J interception during initialization as introduced in SLF4J version 1.7.15
* @since 1.1.4
* @param slf4jEvent
*/
public void log(org.slf4j.event.LoggingEvent slf4jEvent) {
Level level = Level.fromLocationAwareLoggerInteger(slf4jEvent.getLevel().toInt());
filterAndLog_0_Or3Plus(FQCN, slf4jEvent.getMarker(), level, slf4jEvent.getMessage(), slf4jEvent.getArgumentArray(), slf4jEvent.getThrowable());
}
/**
* After serialization, the logger instance does not know its LoggerContext.
* The best we can do here, is to return a logger with the same name
* returned by org.slf4j.LoggerFactory.
*
* @return Logger instance with the same name
* @throws ObjectStreamException
*/
protected Object readResolve() throws ObjectStreamException {
return LoggerFactory.getLogger(getName());
}
}
参考资料
javaspi07-自动生成spi配置文件实现方式
系列目录spi01-spi是什么?入门使用spi02-spi的实战解决slf4j包冲突问题spi03-spijdk实现源码解析spi04-spidubbo实现源码解析spi05-dubboadaptiveextension自适应拓展spi06-自己从零手写实现SPI框架spi07-自动生成SPI配置文件实现方式回顾上一节我们... 查看详情
javaspi03-serviceloaderjdk源码解析
...己从零手写实现SPI框架spi07-自动生成SPI配置文件实现方式javaSPI加载流程1应用程序调用ServiceLoader.load方法Servic 查看详情
javaspi04-spidubbo实现源码解析
系列目录spi01-spi是什么?入门使用spi02-spi的实战解决slf4j包冲突问题spi03-spijdk实现源码解析spi04-spidubbo实现源码解析spi05-dubboadaptiveextension自适应拓展spi06-自己从零手写实现SPI框架spi07-自动生成SPI配置文件实现方式dubbospi而Dubbo中最... 查看详情
javaspi06-自己从零手写实现spi框架
系列目录spi01-spi是什么?入门使用spi02-spi的实战解决slf4j包冲突问题spi03-spijdk实现源码解析spi04-spidubbo实现源码解析spi05-dubboadaptiveextension自适应拓展spi06-自己从零手写实现SPI框架spi07-自动生成SPI配置文件实现方式回顾学习了java的... 查看详情
javaspi01-spi是什么?spi使用入门教程serviceloader使用简介
系列目录spi01-spi是什么?入门使用spi02-spi的实战解决slf4j包冲突问题spi03-spijdk实现源码解析spi04-spidubbo实现源码解析spi05-dubboadaptiveextension自适应拓展spi06-自己从零手写实现SPI框架spi07-自动生成SPI配置文件实现方式问题引入以前一... 查看详情
javaspi机制和使用示例
JAVASPI简介SPI是Java提供的一种服务加载方式,全名为ServiceProviderInterface。根据Java的SPI规范,我们可以定义一个服务接口,具体的实现由对应的实现者去提供,即服务提供者。然后在使用的时候再根据SPI的规范去获取对应的服务提... 查看详情
javaspi机制和使用示例
JAVASPI简介SPI是Java提供的一种服务加载方式,全名为ServiceProviderInterface。根据Java的SPI规范,我们可以定义一个服务接口,具体的实现由对应的实现者去提供,即服务提供者。然后在使用的时候再根据SPI的规范去获取对应的服务提... 查看详情
springmvc引入slf4j报错,org.slf4j.spi.locationawarelogger.log如何解决?
在线急等参考技术A你可以重下 参考技术B错误要贴出来啊追问Exceptioninthread"main"java.lang.NoSuchMethodError:org.slf4j.spi.LocationAwareLogger.log(Lorg/slf4j/Marker;Ljava/lang/String;ILjava/lang/String;[Ljava/lang/Object;Ljava/lang... 查看详情
javaspi机制简介
SPI简介SPI全称为(ServiceProviderInterface),是JDK内置的一种服务提供发现机制。目前有不少框架用它来做服务的扩展发现,简单来说,它就是一种动态替换发现的机制,举个例子来说,有个接口,想运行时动态的给它添加实现,你只需... 查看详情
javaspi使用与注意
JavaSPI示例前面简单介绍了SPI机制的原理,本节通过一个示例演示JavaSPI的使用方法。首先,我们定义一个接口,名称为Robot。publicinterfaceRobot{voidsayHello();}接下来定义两个实现类,分别为OptimusPrime和Bumblebee。publicclassOptimusPrimeimplemen... 查看详情
javaspi及demo(代码片段)
首先交代下背景,何为JavaSPI?SPI全称为(ServiceProviderInterface),是JDK内置的一种服务提供发现机制。为什么需要SPI?我们的现代系统越来越庞大,如果设计架构有问题,就可能牵一发而动全身,在面向对象中我们推荐基于接口编程... 查看详情
杂谈javaspi机制
@TOCJava常用机制-SPI机制详解什么是SPI机制SPI(ServiceProviderInterface),是JDK内置的一种服务提供发现机制,可以用来启用框架扩展和替换组件,主要是被框架的开发人员使用,比如java.sql.Driver接口,其他不同厂商可以针对同一接口... 查看详情
javaspi机制详解(代码片段)
JavaSPI机制详解SPI介绍何谓SPI?SPI和API有什么区别?实战演示ServiceProviderInterfaceServiceProvider效果展示ServiceLoaderServiceLoader具体实现自己实现一个ServiceLoader总结在面向对象的设计原则中,一般推荐模块之间基于接口编程,... 查看详情
利用jdk自带的spi实现一个javaspi程序例子
SPI全称ServiceProviderInterface,面向接口编程,是Java提供的一套用来被第三方实现或者扩展的接口,它可以用来启用框架扩展和替换组件。关于spi思想的的介绍详情请百度。以下是利用spi思想的一个小例子。步骤一:新建一个java项... 查看详情
javaspi机制源码级深度理解(代码片段)
...bbo、SpringBoot等框架。本文从源码入手分析,深入探讨JavaSPI的特性、原理,以及在一些比较经典领域的应用。 一、SPI简介SPI全称ServiceProviderInte 查看详情
javaspi
whatSPI?SPI全称ServiceProviderInterface,是Java提供的一套用来被第三方实现或者扩展的接口,它可以用来启用框架扩展和替换组件。SPI的作用就是为这些被扩展的API寻找服务实现。如何使用定义如下类:publicinterfaceSPITestInter... 查看详情
javaspi实例
SPI全称为ServiceProviderInterface,是一种服务发现机制。SPI的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。这里简单写一个例子示意创建Dem... 查看详情
javaspi机制简述
...根据依赖自动切换具体实现方案(实现类)的效果。使用JavaSPI使用了策略模式,一个接口多种实现,这一点从概 查看详情