Java read source code design mode: Adapter

Source: Internet
Author: User

Source Code related to the adapter mode:Slf4j-1.6.1, hibernate-3.6.7


As we all know, log4j is a widely used log tool. In addition, sun also has its own log tool in JDK, namely java. util. logging. Logger. Of course, there are other log tools.

The functions and usage of multiple log tools are similar. They generally contain log-level methods such as debug, info, warn, and error, but do not implement common interfaces. This is not like JDBC. Although there are many types of relational databases, such as MySQL and Oracle, there is a set of unified interfaces, that is, JDBC.

Of course, if you write a project by yourself, you just need to find a log tool. However, the authors of some open-source frameworks are quite entangled. They don't know which log tool your system uses, and they don't know which log tool he uses in the open-source framework.

Slf4j provides a common interface and implements adapters for different log tools. Therefore, in the open-source framework, logs only need to call the interfaces provided by slf4j, without worrying about which implementation class is used. For example, the log of the ORM framework Hibernate depends on slf4j.

Similar to slf4j, there are commons-logging and so on.


Source code (due to the huge length of the source code, the irrelevant code is omitted below ):

Slf4j provides a unified interface org. slf4j. Logger, which is provided to clients (such as Hibernate) for calling:

package org.slf4j;public interface Logger {  public boolean isTraceEnabled();  public void trace(String msg);  public void trace(String format, Object arg);  public void trace(String format, Object arg1, Object arg2);  public void trace(String format, Object[] argArray);  public void trace(String msg, Throwable t);  public boolean isDebugEnabled();  public void debug(String msg);  public void debug(String format, Object arg);  public void debug(String format, Object arg1, Object arg2);  public void debug(String format, Object[] argArray);  public void debug(String msg, Throwable t);  public boolean isInfoEnabled();  public void info(String msg);  public void info(String format, Object arg);  public void info(String format, Object arg1, Object arg2);  public void info(String format, Object[] argArray);  public void info(String msg, Throwable t);  public boolean isWarnEnabled();  public void warn(String msg);  public void warn(String format, Object arg);  public void warn(String format, Object[] argArray);  public void warn(String format, Object arg1, Object arg2);  public void warn(String msg, Throwable t);  public boolean isErrorEnabled();  public void error(String msg);  public void error(String format, Object arg);  public void error(String format, Object arg1, Object arg2);  public void error(String format, Object[] argArray);  public void error(String msg, Throwable t);}

In client hibernate, instead of directly calling log4j or JDK logger, The org. slf4j. Logger interface is used. Any piece of code with logs in hibernate:

(Note: you do not need to pay attention to how LoggerFactory. getLogger implements this article)

package org.hibernate.impl;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public final class SessionFactoryImpl implements SessionFactory, SessionFactoryImplementor {private static final Logger log = LoggerFactory.getLogger(SessionFactoryImpl.class);private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {log.trace("deserializing");in.defaultReadObject();log.debug("deserialized: " + uuid);}private void writeObject(ObjectOutputStream out) throws IOException {log.debug("serializing: " + uuid);out.defaultWriteObject();log.trace("serialized");}}

Log4j and JDK logger do not implement the org of slf4j. slf4j. logger interface, so slf4j must provide an adapter to implement org. slf4j. the Logger interface, which is used by the adapter to call log4j or JDK logger to implement log, so as to realize compatibility with log tools. (Note: from the source code, we can see that the LocationAwareLogger interface inherits from org. slf4j. Logger, so implementing LocationAwareLogger is equivalent to implementing org. slf4j. Logger)

Log4j adapter org. slf4j. impl. Log4jLoggerAdapter:

package org.slf4j.impl;import java.io.Serializable;import org.apache.log4j.Level;import org.slf4j.Logger;import org.slf4j.Marker;import org.slf4j.helpers.FormattingTuple;import org.slf4j.helpers.MessageFormatter;import org.slf4j.spi.LocationAwareLogger;public final class Log4jLoggerAdapter extends MarkerIgnoringBase implements    LocationAwareLogger, Serializable {  final transient org.apache.log4j.Logger logger;  public boolean isDebugEnabled() {    return logger.isDebugEnabled();  }  public void debug(String msg) {    logger.log(FQCN, Level.DEBUG, msg, null);  }  public void debug(String format, Object arg) {    if (logger.isDebugEnabled()) {      FormattingTuple ft = MessageFormatter.format(format, arg);      logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());    }  }  public void debug(String format, Object arg1, Object arg2) {    if (logger.isDebugEnabled()) {      FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);      logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());    }  }  public void debug(String format, Object[] argArray) {    if (logger.isDebugEnabled()) {      FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);      logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());    }  }  public void debug(String msg, Throwable t) {    logger.log(FQCN, Level.DEBUG, msg, t);  }}

Jdk logger adapter org. slf4j. impl. JDK14LoggerAdapter:

package org.slf4j.impl;import java.util.logging.Level;import org.slf4j.Marker;import org.slf4j.helpers.FormattingTuple;import org.slf4j.helpers.MarkerIgnoringBase;import org.slf4j.helpers.MessageFormatter;import org.slf4j.spi.LocationAwareLogger;public final class JDK14LoggerAdapter extends MarkerIgnoringBase implements    LocationAwareLogger {  final java.util.logging.Logger logger;  public boolean isDebugEnabled() {    return logger.isLoggable(Level.FINE);  }  public void debug(String msg) {    if (logger.isLoggable(Level.FINE)) {      log(SELF, Level.FINE, msg, null);    }  }  public void debug(String format, Object arg) {    if (logger.isLoggable(Level.FINE)) {      FormattingTuple ft = MessageFormatter.format(format, arg);      log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());    }  }  public void debug(String format, Object arg1, Object arg2) {    if (logger.isLoggable(Level.FINE)) {      FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);      log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());    }  }  public void debug(String format, Object[] argArray) {    if (logger.isLoggable(Level.FINE)) {      FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);      log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());    }  }  public void debug(String msg, Throwable t) {    if (logger.isLoggable(Level.FINE)) {      log(SELF, Level.FINE, msg, t);    }  }}

In adapter mode, it generally includes the following parts:

Adaptee:The implementation class that actually implements the function, but is not compatible with the client. That is, java. util. logging. Logger and org. apache. log4j. Logger in the above Code.

Target:The interface called by the client. The adapter implements this interface. Org. slf4j. Logger in the above Code.

Adapter:Adapter. The adapter implements the Target interface. The specific function is implemented by calling Adaptee. The above org. slf4j. impl. Log4jLoggerAdapter and org. slf4j. impl. JDK14LoggerAdapter.

Client:Call the Target interface. Is the above Hibernate.


Summary:

There are multiple similar classes (such as java. util. logging. Logger, org. apache. log4j. Logger), there is no unified interface, but the client wants to be compatible. In this case, the best way is to refactor, that is, let them implement the same interface. However, if the reconstruction cost is too large or the same interface cannot be implemented at all (for example, in the above example, log4j and JDK logger are not one of them), You must create a unified interface (org. slf4j. logger), and write an adapter (org. slf4j. impl. log4jLoggerAdapter, org. slf4j. impl. JDK14LoggerAdapter), allows the adapter to implement a unified interface, and calls a specific implementation class for implementation, has achieved the purpose of compatibility.


Author: Cross brother reprint please indicate the source: http://blog.csdn.net/xiao__gui/article/details/32695647



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.