前言：spring系列第二篇文章，前面懒病犯了。（笑）本篇主要讲解context.refresh()方法0. 准备工作Test.Javapublic class Test { public static void main(String[] args) throws IOException { // 把spring所有的前提环境准备好(比如：bean容器、bean工厂等) AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); // 像容器注入配置类，后面来讲。 context.register(AppConfig.class); // 本篇主要讲解的内容 context.refresh(); AppConfig bean = context.getBean(AppConfig.class); System.out.println(bean); } }1. 源码阅读Refresh()方法方法处于AbstractApplicationContext类，方法里面做了很多的事情，首先我们点开这个方法:public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. // 准备工作包括：设置启动时间、是否激活标识位、初始化属性源（property source）配置 // 和主流程关系不太大 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. // 得到beanFactory，然后对beanFactory进行设置 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. // 重点方法，准备beanFactory prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. // 空方法，当前版本没有代码 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. /* * 在spring的环境中执行已经被注册的 factory processors * 设置执行自定义和spring内部的beanFactoryPostProcessor * 这里执行了了spring内部最关键的一个BeanFactoryPostProcessor：ConfigurationClassPostProcessor */ invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. // 注册bean的处理器来拦截bean的创建 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. // 这个方法不太重要。国际化 initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. // 空壳方法 onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. // 实例化所有剩余的不是懒加载的单例bean，又一个重点方法。 // 何谓剩余？单例bean有两种：spring内置的、自己添加的（这就是代表剩余的） finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. // 最后一步：发布相应的事件 finishRefresh(); // ... 省略后面的 } }里面有很多调用的方法，我们先一个一个的分析：1.1 prepareRefresh()正如其命名一样，该方法做的工作主要是：设置启动时间、是否激活标识位、初始化属性源（property source）配置等，与主流程关系不大。有兴趣的可以自己专研下。1.2 obtainFreshBeanFactory()取出得到beanFactory，然后对beanFactory进行设置。关于什么是beanFactory，简单来说就是一个工厂，里面有储存着所有要用的东西，等后面再来详细说明。1.3 prepareBeanFactory()// Prepare the bean factory for use in this context. // 重点方法，准备beanFactory prepareBeanFactory(beanFactory);这是一个比较重要的方法，里面完成了很多工作： protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. // 设置一个类加载器 beanFactory.setBeanClassLoader(getClassLoader()); // bean的表达式解析，能够获取bean当中的属性，在前台页面 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // 对象与字符串之间的转换 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // Configure the bean factory with context callbacks. 配置工厂的回调 // 增加一个后置管理器。 ApplicationContextAwareProcessor 实现了BeanPostProcessor // ApplicationContextAwareProcessor 这个类也会在后面介绍的 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); //最核心的 // 以下接口，忽略自动装配 beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); // ...省略部分 // BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean. // 依赖的替换 //以下接口，允许自动装配,第一个参数是自动装配的类型，，第二个字段是自动装配的值 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); // ...省略部分 // Register early post-processor for detecting inner beans as ApplicationListeners. beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // Detect a LoadTimeWeaver and prepare for weaving, if found. if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } /* * 意思是如果自定义的Bean中没有名为"systemProperties"和"systemEnvironment"的Bean. * 则注册两个Bean，Key为"systemProperties"和"systemEnvironment"，Value为Map， * 这两个Bean就是一些系统配置和系统环境信息 */ // Register default environment beans. 注册默认的环境bean if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } // ...省略部分 }主要做了如下工作：设置一个类加载器bean的表达式解析，能够获取bean当中的属性，在前台页面设置对象与字符串之间的转换的类添加了一个后置处理器：ApplicationContextAwareProcessor，其实现了接口BeanPostProcessor（其作为spring扩展点之一，这个接口会在后面详细讲解的）设置忽略自动装配的接口相关依赖的替换设置一些系统配置和系统环境信息1.4 postProcessBeanFactory()// 空方法，当前版本没有代码 postProcessBeanFactory(beanFactory);这个方法是在标准初始化完成后，用于修改内部beanFactory的方法，当前版本没有实现，可能在后续的版本中增加相关的实现。1.5 invokeBeanFactoryPostProcessors()// Invoke factory processors registered as beans in the context. /* * 在spring的环境中执行已经被注册的 factory processors * 设置执行自定义和spring内部的beanFactoryPostProcessor * 这里执行了了spring内部最关键的一个BeanFactoryPostProcessor：ConfigurationClassPostProcessor */ invokeBeanFactoryPostProcessors(beanFactory);这个方法是非常重要的一个方法，完成了非常重要的工作，这篇就讲个开始， 下一篇将重点讲解此方法里面内容。protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { // getBeanFactoryPostProcessors()方法是获取手动（这个是没有交给spring容器管理的，也就是没加@Component） /** * getBeanFactoryPostProcessors()返回的是AnnotationConfigApplicationContext继承的父类中被定义的 * 一个List，是一个空的。 * 是需要自己调用AnnotationConfigApplicationContext的addBeanFactoryPostProcessors()方法添加进去 */ PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // ...省略部分内容 } }1.5.1 getBeanFactoryPostProcessors()先看这个方法：getBeanFactoryPostProcessors()返回的是AnnotationConfigApplicationContext继承的父类中被定义的一个List，是一个空的。是需要自己调用AnnotationConfigApplicationContext的addBeanFactoryPostProcessors()方法添加进去。addBeanFactoryPostProcessor()方法public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) { // .... this.beanFactoryPostProcessors.add(postProcessor); }当没有手动调用add方法时，从截图可以清楚看到里面并没有内容当我们在Test类中的main方法中调用addBeanFactoryPostProcessor()方法时：可以从下图看出结果：本篇文章到这就完结，后面的内容，下篇文章再写。希望我能更新更快一点（逃2. 参考链接剑指Spring源码（二）
前言：一入spring深似海，呃，后面不知道怎么写了，那就开干吧。这篇是spring系列的第一篇文章，希望自己能坚持下去，愿阅读源码的各位都一同坚持下去。与君共勉！0. 准备工作首先应该准备相关的环境，我的环境是：IntelliJ IDEA 2020.2 (Ultimate Edition)JDK 1.8.*gradle-5.6.4spring版本：spring-framework-5.1.17.RELEASE可以使用我的环境，然后参考后面的步骤时，只需要修改对应的版本，当然你也可以使用这篇的文章的环境对应的版本。如果有不对的地方，欢迎留言，我会尽量提供帮助的。具体的步骤可以参考这篇文章 gradle+idea配置阅读Spring源码开发环境（解决jar包下载缓慢问题）,强烈推荐，良心博主，不做重复工作（不，其实是懒！）。但是好像有一个错误，就是设置gradle环境的地方，具体操作，参看下图。1. 源码阅读源码分析的部分主要是用JavaConfig技术启动spring环境，这也是spring官网推荐的方式。本系列文章是假设读者已经掌握了spring基本入门的应用。如未掌握，可以点击链接Java-based Container Configuration，前往官网学习入门，或者百度相关知识入门1.1 编写基本代码AppConfig.Java首先写一个配置类@Configuration @ComponentScan("com.example") public class AppConfig { }Test.Java编写一个测试类public class Test { public static void main(String[] args) throws IOException { // 把spring所有的前提环境准备好(比如：bean容器、bean工厂等) AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(AppConfig.class); context.refresh(); AppConfig bean = context.getBean(AppConfig.class); System.out.println(bean); } }如果成功打印出来，说明spring环境已经搭建成功，现在可以开心阅读源码了。1.2 AnnotationConfigApplicationContext类// 继承了GenericApplicationContext类 public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry首先在上面的main方法中，调用了AnnotationConfigApplicationContext类的无参构造方法，在其实例化之前，会调用父类 GenericApplicationContext类的无参构造，其构造方法如下：public GenericApplicationContext() { // 实例化了一个spring默认提供的BeanFactory ==> DefaultListableBeanFactory类 // 保存到了成员变量 beanFactory中 this.beanFactory = new DefaultListableBeanFactory(); }然后再调用本类的构造方法，如下：public AnnotationConfigApplicationContext() { // 创建一个读取注解的Bean定义读取器。Bean定义：BeanDefinition // 这个中完成了 this.reader = new AnnotatedBeanDefinitionReader(this); /* * 可以用来扫描包或类，然后转换成bd * 但是实际上我们扫描包工作不是scanner对象 */ // 扫描器，这是仅仅是为了程序员能够在外部地调用AnnotationConfigApplicationContext对象的scan方法 this.scanner = new ClassPathBeanDefinitionScanner(this); }下面主要介绍实例化 AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner两个类所做的事情1.2.1 AnnotatedBeanDefinitionReader类在上面实例化AnnotatedBeanDefinitionReader类public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) { this(registry, getOrCreateEnvironment(registry)); }调用到，下面这个构造方法：public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { // .....省略 // 梦开始的地方，嘿嘿 // 非常重要的方法 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); }registerAnnotationConfigProcessors()方法首先调用这个方法，一个空壳方法：public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) { registerAnnotationConfigProcessors(registry, null); }真正的内容方法：这里首先介绍一下BeanDefinition：BeanDefinition是什么，顾名思义，它是用来描述Bean的，里面存放着关于Bean的一系列信息，比如Bean的作用域，Bean所对应的Class，是否懒加载，是否Primary等等，这个BeanDefinition也相当重要，我们以后会常常和它打交道。如需详细的了解，可以点击spring官网的链接查看。（后面可能用bd来代表BeanDefinition）这个方法注册了6个关键的bd（也是6个后置处理器）到beanDefinitionMap中，在后面会被使用，这个方法中的RootBeanDefinition是实现了 BeanDefinition的，其代表spring内部的BeanDefinition。这里注册了一个在初始化 beanFactory环境重要的一个类：ConfigurationClassPostProcessor，这个类后在后面着重讲解。public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, @Nullable Object source) { // 这里返回的是 在GenericApplicationContext类中的构造方法创建的一个 beanFactory DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry); if (beanFactory != null) { if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) { // AnnotationAwareOrderComparator主要能解析@Order注解和@Priority。设置实例 beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); } if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) { // ContextAnnotationAutowireCandidateResolver提供处理延迟加载的功能 beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); } } Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8); // BeanDefinition的注册。这里注册了6个关键的bd // 这个是最核心的类 ConfigurationClassPostProcessor，这个类将会在后面重点介绍 if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { /* * ConfigurationClassPostProcessor 的类型是BeanDefinitionRegistryPostProcessor * 而BeanDefinitionRegistryPostProcessor 最终实现BeanFactoryPostProcessor * 可以把RootBeanDefinition理解成spring内部的bean定义，通过BeanDefinition实现，可以将一个类变成bean定义 * * 为什么在这里注册这个ConfigurationClassPostProcessor？ * 因为在spring的beanFactory初始化需要做一些事情，在执行invokeBeanFactoryPostProcessors()时 * 委托调用其内部实现 * 以此来实现解耦合。 * */ RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); // 注册成一个bean定义 beanDefinitionMap // registerPostProcessor()方法，最终会把这个类放到beanFactory的 beanDefinitionMap中 beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); } //.....后面的省略 } registerPostProcessor()方法private static BeanDefinitionHolder registerPostProcessor( BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) { definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // 注册成一个bean定义。这里的registry 是 我们开始实例的 DefaultListableBeanFactory registry.registerBeanDefinition(beanName, definition); return new BeanDefinitionHolder(definition, beanName); }registerBeanDefinition()方法主要是将beanDefinition、beanName分别放入到Map、List中，这两个容器也是beanFactory工厂中非常重要的两个属性，将在后面逐步展示其所起的作用。// ....省略 else { // Still in startup registration phase // Map this.beanDefinitionMap.put(beanName, beanDefinition); // List this.beanDefinitionNames.add(beanName); removeManualSingletonName(beanName); } // ... 省略/** Map of bean definition objects, keyed by bean name. */ // bean的定义 private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); /** List of bean definition names, in registration order. */ // beanName private volatile List<String> beanDefinitionNames = new ArrayList<>(256);1.2.2 ClassPathBeanDefinitionScanner类这里并不介绍其内部结构，主要介绍其用途，因为一般很少被使用。正如上图注释所说那样，这里的scanner主要是作为调用者在外部调用，例如：public class Test { public static void main(String[] args) throws IOException { // 把spring所有的前提环境准备好(比如：bean容器、bean工厂等) AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(AppConfig.class); // 自己想要额外的扫描一些包，并不想要spring来扫描，可以调用该方法 context.scan("com.example"); context.refresh(); }主要的使用地方// AnnotationConfigApplicationContext类内部 public void scan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); this.scanner.scan(basePackages); }到这里就介绍完了实例化AnnotationConfigApplicationContext类所做的事情了，Test类中剩下的方法将放在后面逐步更新，希望自己能当个秒男一样更新吧（雾2 参考链接gradle+idea配置阅读Spring源码开发环境（解决jar包下载缓慢问题剑指Spring源码（一）
前言本文主要介绍的是spring5、spring4、mybatis日志源码中是具体如何加载具体的日志类，看完后你可以根据源码的加载顺序使用自己需要使用的日志。如有错误，欢迎指出spring当中的日志log4jlogbacklog4j2julslf4jjcl各种日志技术的关系和作用通过源码来分析spring的日志技术分别分析spring5和spring4的使用日志的区别通过源码分析mybaits的日志技术spring和mybatis整合通过注解设置自定义的日志主流的log技术名词log4j log4j log4j 1.2.17 可以不需要依赖第三方的技术，直接记录日志jcljakartaCommonsLoggingImpl commons-logging commons-logging 1.1.1 jcl他不直接记录日志,他是通过第三方记录日志(jul)，它是jdk自带的如果使用jcl来记录日志,在没有log4j的依赖情况下,是用jul如果有了log4j则使用log4jjcl=Jakarta commons-logging ,是apache公司开发的一个抽象日志通用框架,本身不实现日志记录,但是提供了记录日志的抽象方法即接口(info,debug,error.......),底层通过一个数组存放具体的日志框架的类名,然后循环数组依次去匹配这些类名是否在app中被依赖了,如果找到被依赖的则直接使用,所以他有先后顺序。上图为jcl中存放日志技术类名的数组，默认有四个，后面两个可以忽略，因为都是jdk1.3以前的。上图81行就是通过一个类名去load一个class，如果load成功则直接new出来并且返回使用。如果没有load到class这循环第二个，直到找到为止。可以看到这里的循环条件必须满足result不为空，也就是如果没有找到具体的日志依赖则继续循环，如果找到则条件不成立，不进行循环了。总结：顺序log4j>juljuljava自带的一个日志记录的技术,直接使用log4j2slf4jslf4j他也不记录日志,通过绑定器绑定一个具体的日志记录来完成日志记录绑定器、桥接器问题slf4j -->通过绑定器-->jcl -->通过桥接器--> jcl ====> 会导致内存溢出logbacksimple-log各种日志技术的关系和作用spring日志技术分析spring5.*日志技术实现spring5使用的spring的jcl(spring改了jcl的代码)来记录日志的,但是jcl不能直接记录日志,默认是使用JUL记录，但是只要引入了log4j2、slf4j等，就会被重新赋值改变（在static静态块中）源代码展示org.apache.commons.logging.LogFactory类里面被调用的最多的方法：// 这个方法，调用本类的getLog()方法 public static Log getLog(Class<?> clazz) { return getLog(clazz.getName()); } public static Log getLog(String name) { return LogAdapter.createLog(name); }org.apache.commons.logging.LogAdapter类静态变量和静态代码块会在类的实例化之前被加载，具体是在类加载过程的初始化阶段，会在编译器生成的clinit方法中被调用，执行的顺序有源文件中出现的顺序一致/** * Create an actual {@link Log} instance for the selected API. * 这个方法就是返回具体的实例 */ public static Log createLog(String name) { // 通过静态变量logApi具体的值来加载日志 switch (logApi) { case LOG4J: return Log4jAdapter.createLog(name); case SLF4J_LAL: return Slf4jAdapter.createLocationAwareLog(name); case SLF4J: return Slf4jAdapter.createLog(name); default: return JavaUtilAdapter.createLog(name); } } // 核心代码 private static final String LOG4J_SPI = "org.apache.logging.log4j.spi.ExtendedLogger"; private static final String LOG4J_SLF4J_PROVIDER = "org.apache.logging.slf4j.SLF4JProvider"; private static final String SLF4J_SPI = "org.slf4j.spi.LocationAwareLogger"; private static final String SLF4J_API = "org.slf4j.Logger"; private static final LogApi logApi; // 枚举类 private enum LogApi {LOG4J, SLF4J_LAL, SLF4J, JUL} static { // isPresent()方法，是判断这个类是否能够被加载到 if (isPresent(LOG4J_SPI)) { if (isPresent(LOG4J_SLF4J_PROVIDER) && isPresent(SLF4J_SPI)) { // log4j-to-slf4j bridge -> we'll rather go with the SLF4J SPI; // however, we still prefer Log4j over the plain SLF4J API since // the latter does not have location awareness support. logApi = LogApi.SLF4J_LAL; } else { // Use Log4j 2.x directly, including location awareness support // 使用Log4j 2.x的版本 logApi = LogApi.LOG4J; } } else if (isPresent(SLF4J_SPI)) { // Full SLF4J SPI including location awareness support logApi = LogApi.SLF4J_LAL; } else if (isPresent(SLF4J_API)) { // Minimal SLF4J API without location awareness support logApi = LogApi.SLF4J; } else { // java.util.logging as default // 默认使用JUL logApi = LogApi.JUL; } }spring4.*日志技术实现spring4当中依赖的是原生的jcl，采用循环优先的原则。mybatis的日志技术实现你提供哪个，就使用你提供的。如果没有提供，就会使用JCL，然后JCL会去找到实现类初始化静态代码块会在类的加载过程中的初始化阶段执行org.apache.ibatis.logging.LogFactory常被调用的方法public static Log getLog(Class<?> aClass) { return getLog(aClass.getName()); } public static Log getLog(String logger) { try { // 通过静态变量logConstructor来获得具体的 return logConstructor.newInstance(logger); } catch (Throwable t) { throw new LogException("Error creating logger for logger " + logger + ". Cause: " + t, t); } }// 静态变量 private static Constructor<? extends Log> logConstructor; static { // 在初始化阶段执行，一旦logConstructor不为空，后面的就不会被执行 tryImplementation(LogFactory::useSlf4jLogging); tryImplementation(LogFactory::useCommonsLogging); tryImplementation(LogFactory::useLog4J2Logging); tryImplementation(LogFactory::useLog4JLogging); tryImplementation(LogFactory::useJdkLogging); tryImplementation(LogFactory::useNoLogging); }关键代码 if (logConstructor == null),没有找到实现则继续找private static void tryImplementation(Runnable runnable) { // 当为空时，才执行方法 if (logConstructor == null) { try { runnable.run(); } catch (Throwable t) { // ignore } } } public static synchronized void useSlf4jLogging() { setImplementation(org.apache.ibatis.logging.slf4j.Slf4jImpl.class); } private static void setImplementation(Class<? extends Log> implClass) { try { Constructor<? extends Log> candidate = implClass.getConstructor(String.class); // 为什么不直接返回这里的Log对象？ // 这里主要的目的是看能不能得到，用户还需要自定义一些东西，所以不能返回这个，应该使用getLog()方法返回的对象 Log log = candidate.newInstance(LogFactory.class.getName()); if (log.isDebugEnabled()) { log.debug("Logging initialized using '" + implClass + "' adapter."); } // 赋值，只要前面没有抛异常 logConstructor = candidate; } catch (Throwable t) { throw new LogException("Error setting Log implementation. Cause: " + t, t); } } // getLog方法 public static Log getLog(String logger) { try { return logConstructor.newInstance(logger); } catch (Throwable t) { throw new LogException("Error creating logger for logger " + logger + ". Cause: " + t, t); } }具体实现类mybatis提供很多日志的实现类,用来记录日志,取决于初始化的时候load到的class上图红色箭头可以看到JakartaCommonsLoggingImpl中引用了jcl 的类,如果在初始化的时候load到类为JakartaCommonsLoggingImpl那么则使用jcl 去实现日志记录,但是也是顺序的,顺序参考源码Spring和Mybatis整合设置自定义的的日志// spring的Appconfig中 @Bean public SqlSessionFactory sqlSessionFactory() throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); // 所以可以通过这样设置自己想要使用的日志 org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); // 这个方法里面调用的是org.apache.ibatis.logging.LogFactory的useCustomLogging() configuration.setLogImpl(Log4jImpl.class); factoryBean.setConfiguration(configuration); factoryBean.setDataSource(dataSource()); return factoryBean.getObject(); } // useCustomLogging方法 public static synchronized void useCustomLogging(Class<? extends Log> clazz) { setImplementation(clazz); }