Spring源码解读:引言、第一个Spring程序、使用日志框架Logback

参考自B站UP主视频《孙哥说Spring5》

什么是Spring Framework?

在这里插入图片描述

EJB存在的问题

  • 运行环境苛刻
  • 代码可移植性差(只要运行的服务器改变了,代码就要随之而改变,且服务器因为是闭源收费的,对服务器就无法进行深度定制)

所以也就称为重量级框架

什么是Spring?

Spring是一个轻量级的JavaEE解决方案,整合众多优秀的设计模式

  • 轻量级:对于运行环境是没有额外的要求

  • 代码移植性高:不需要实现额外的接口(EJB代码需要专门实现服务器的接口)

  • JavaEE解决方案:有众多产品可以整合进入(SpringMVC、Mybatis等)
    在这里插入图片描述

  • 合理运用了优秀的设计模式

1. 工厂模式(核心)
2. 代理模式
3. 模板模式
4. 策略模式

设计模式简介

  1. 广义概念:面向对象设计中,解决特定问题的经典代码
  2. 狭义概念:GOF4人帮定义的23种设计模式:工厂、适配器、装饰器、外观、代理、单例等

Spring的核心:工厂模式

关于工厂模式,可以查看之前写的一篇更加详细的笔记:让代码来告诉你什么叫工厂模式

#---------------- applicationContext.properties 文件 --------------------
# 在读取配置文件的时候,是使用 一个 Properties  集合来存储 Properties文件内容
# Properties是一种特殊Map:key要是String类型的 value也是String类型的
# 例如下面这两行配置,我们可以在代码中使用key获得value Properties.getProperties("userService"); 
# 当有一个新的类要使用的话,只需要改配置文件中的内容即可,也就是实现了解耦

userService = com.rick.serviceImpl.UserServiceImpl
userDao = com.rick.daoImpl.UserDaoImple

通过Bean工厂来获得一个类

----------------------------------BeanFactory.java-------------------------------------
package com.rick.factory;

import com.rick.dao.UserDao;
import com.rick.daoImpl.UserDaoImpl;
import com.rick.service.UserService;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import static java.lang.Class.*;

/**
 * 工厂类
 * @author Rick
 */
public class BeanFactory {
    private static Properties env = new Properties();
    static{
    	// 静态代码块,在系统启动的时候就加载配置文件
        try {
            //获得IO输入流,读取文件
            InputStream inputStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
            //文件中的内容封装进 Properties集合
            env.load(inputStream);
            // 关闭输入流
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /*
        对象的创建方式:
            1、直接通过调用构造方法 UserService userService = new UserService();
            2、通过反射的形式,创建对象,解耦合 getInstance()
     */
    public static UserService getUserService(){
        //return new UserServiceImpl();
        UserService userService = null;
        try {
        	// 获得Class模板
            Class clazz = Class.forName(env.getProperty("userService"));
            // 通过模板创建
            userService = (UserService) clazz.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return userService;
    }

    public static UserDaoImpl getUserDao(){
        UserDaoImpl userDaoImpl = null;
        try {
            Class clazz  = Class.forName(env.getProperty("userDao"));
            userDaoImpl = (UserDaoImpl)clazz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return userDaoImpl;
    }

}
-------------------------------UserService.java--------------------------
package com.rick.service;

import com.rick.domain.User;

/**
 * 接口
 * @author Rick
 */
public interface UserService {
    public void saveUser(User user);
    public void querryUserByNameAndPassword(User user);
}
------------------------------UserServiceImpl.java--------------------------------------
package com.rick.serviceImpl;

import com.rick.dao.UserDao;
import com.rick.factory.BeanFactory;
import com.rick.service.UserService;
import com.rick.domain.User;

/**
 * 实现类
 * @author Rick
 */
public class UserServiceImpl implements UserService {

//    UserDao userDao = new UserDaoImpl(); // 这样对于两个类的耦合性很高,不利于代码的维护
    UserDao userDao = BeanFactory.getUserDao(); // 使用 Bean工厂 来获得 UserDao,能够降低类之间的耦合性

    @Override
    public void saveUser(User user) {
        userDao.saveUser(user);
    }

    @Override
    public void querryUserByNameAndPassword(User user) {
        userDao.querryUserByNameAndPassword(user);
    }
}
------------------------------------------------UserDao.java-------------------------------
package com.rick.dao;

import com.rick.domain.User;

/**
 * 接口
 * @author Rick
 */
public interface UserDao {
    public void saveUser(User user);
    public void querryUserByNameAndPassword(User user);
}
-----------------------------------------UserDaoImpl.java------------------------------
package com.rick.daoImpl;

import com.rick.dao.UserDao;
import com.rick.domain.User;

/**
 * 实现类
 * @author Rick
 */
public class UserDaoImpl implements UserDao {

    @Override
    public void saveUser(User user) {
        System.out.println("saving" + user.toString());
    }

    @Override
    public void querryUserByNameAndPassword(User user) {
        System.out.println(user.toString());
    }
}
---------------------------------AppTest.java------------------------------------------
package com.ric

import static org.junit.Assert.assertTrue;

import com.rick.service.UserService;
import com.rick.factory.BeanFactory;
import org.junit.Test;

// 测试类
public class AppTest 
{
    @Test
    public void test1() throws Exception{
        // 如果有一个新的实现类 UserServiceImplNew 就需要改动代码来使用新的类
        //UserService userService = new UserServiceImplNew();
        //UserService userService = new UserServiceImpl();
        // 通过配置文件来集中管理
        UserService userService = BeanFactory.getUserService(); // 通过工厂类获得类
        User user = new User();
        userService.querryUserByNameAndPassword(user);
    }
}

将上面的 BeanFactory 中的代码优化一下,使其能够适合更多的类去使用

package com.rick.factory;

import com.rick.dao.UserDao;
import com.rick.daoImpl.UserDaoImpl;
import com.rick.service.UserService;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import static java.lang.Class.*;

/**
 * 通用的工厂类
 * @author Rick
 */
public class BeanFactory {
    private static Properties env = new Properties();
    static{
        try {
            //获得IO输入流
            InputStream inputStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
            //文件内容分装
            env.load(inputStream);
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    /*
     * key : 配置文件中的 key
     * 通过传入 key 来获得指定的全限定类名,从而获得类
     * 这样就可以实现,通过 BeanFactory 获得任意自己想要的类名
     */
    public static Object getBean(String key){
        Object obj = null;
        Class clazz = null;
        try {
            clazz = Class.forName(env.getProperty("key"));
            obj = clazz.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return obj;
    }
}

第一个 Spring 程序

软件版本

  • JDK: 8
  • Maven: 3.6.3
  • IDEA: 2020.1.1/
  • SpringFranework: 5.1.15.RELEASE
  • 官方网站:www.spring.io

环境搭建

<!-- 添加 Spring 的依赖 -->
<dependency>
    <groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
    <version>5.1.15.RELEASE</version>
</dependency>
  1. 配置文件的放置位置:任意位置 没有硬性要求
  2. 配置文件命名:没有硬性要求 建议:applicationContext.xml
  3. 注意:日后应用Spring框架时,需要进行配置文件路径的设置。(IDEA中配置即可)

Spring 的核心API

ApplicationContext

  • 作用:Spring提供的ApplicationContext工厂,用于对象的创建
  • 好处:解耦合
  • 特性:
ApplicationContext 为 【接口类型】
	接口:可屏蔽实现的差异
	提供了两种接口的实现
		非web环境:ClassPathXmlApplicationContext
		web环境:XmlWebApplicationContext

ApplicationContext 为 【重量级资源】--> ApplicationContext工厂的对象会【占用大量内存】
	不会频繁的创建对象:(单例)
		一个应用只会创建一个工厂对象
	ApplicationContext工厂:
		一定是【线程安全】的(多线程并发访问)

在这里插入图片描述

程序开发应用

  1. 创建类型
  2. 配置文件的配置:applicationContext.xml
  3. 通过工厂类,获得对象:ApplicationContextClassPathXmlApplication

实体类

//-----------------------------------Person.java
package com.rick.domain;
/**
 * @author Rick
 * 通过工厂创建
 */
public class Person {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                ", dog=" + dog +
                '}';
    }
}

创建配置文件

<!--applicationContext.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<!-- 这里的 id 就是之前说的传入的 key,class 就是 value 全限定名-->
	<!-- id 名字 全局唯一 -->	
    <bean id="person" class="com.rick.domain.Person"/>

</beans>

测试获得类

//--------------------------------Test.java
package com.rick;

import com.rick.domain.Person;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Unit test for simple App.
 */
public class AppTest 
    @Test
    public void test1(){
        //获得Spring的工厂,并传入配置文件的路径
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");	
    	/**
		 *需要强制转换类型
         *Person user = (Person) ctx.getBean("person");
    	 *不需要强制转换类型 但是要求只能由一个Bean标签是Person类型
    	 *Person person = ctx.getBean(Person.class);
 		 */
    	// 通过传入 Class 模板来获得,可以避免强制类型转换
    	Person user = ctx.getBean("person",Person.class);
        System.out.println(person.toString());

		//获取 Spring工厂配置文件 中所有 bean标签 的 id值,但 不能判断 name值
		String[] beanDefinitionNames = ctx.getBeanDefinitionNames(Person.class);
		//根据 类型 获得 Spring配置文件 中对应的 id值,也 能判断 name值
		String[] beanNamesForType = ctx.getBeanNamesFOrType(Person.class);
		//判断是否存在指定的 id值 的 bean
		boolean isExist = ctx.containBeanDefinition("a");
		//判断是否存在指定的 id值 的 bean
		boolean isExist = ctx.containBean("a");
    }
}

配置文件中需要注意的细节

只配置class属性:<bean class="com.rick.domain.Person"/>

  • 那上述这种配置,有无id值?其实是有的,会自动生成:com.rick.domain.Person#0
  • 应用场景:如果这个bean只用一次则可以省略id值,反之若需要多次使用则必须设置id值

name属性

  • 作用:用于在Spring的配置文件中,为 bean对象 定义别名(小名)【id属性是大名
  • 区别:
    • 别名可以定义多个name="p,p1,p2",但 id属性只能有一个值id="person"
    • XML的 id属性值 有命名要求:必须以字母开头,由字母、数字、连字符、下划线组成,不能以特殊字符,如:/person或者2person
    • XML的 name属性值 无命名要求,name属性一般应用在特殊的场景下
  • XML发展到今天,id属性的限制已不存在
// 引入 name 属性之后,这两者就有一定的区别的
// 不能识别 name
boolean isExist = ctx.containBeanDefinition("a");
// 可以识别 name
boolean isExist = ctx.containBean("a");

对Spring工厂底层实现原理的简单分析

1. 通过 ClassPathXmlApplicationContext() 或 XmlWebApplicationContext() 工厂读取配置文件 applicationContext.xml
2. 获得bean标签的相关信息(id的值,class的值),通过反射创建对于的对象
		Classs<?> clazz = Class.forName(Person.class);
		Person person = clazz.newInstance();
3. 反射创建对象,底层也是会调用对象自己的构造方法
	    Classs<?> clazz = Class.forName(Person.class);
		Person person = clazz.newInstance();
	等效于
		Person person = new Person();
  • 未来在开发过程中,是不是所有的对象,都会交给Spring工厂来创建?
    • 理论上,是的,但也有特例
    • 实体对象(entity)是不会交给Spring创建,实体对象是由持久层框架进行创建的

Spring5.x 整合 logback框架

整合日志框架后,日志框架就可以在控制台中,输出执行过程中的一些重要的信息,可以便于我们了解运行过程,也可以利于程序的调试

Spring 1、2、3早期都是使用 commin-logging.jar,Spring 5.x 默认整合的日志框架logback log4j2

logback简介

logback是由log4j创始人设计的又一个开源日志组件

logback当前分成三个模块:

  • logback-core:是其它两个模块的基础模块。
  • logback- classic:是log4j的一个 改良版本,且完整实现Slf4j API,使你可以很方便地更换成其它日志系统如log4jJDK14 Logging
  • logback-access:与Servlet容器集成提供通过Http来访问日志的功能

logback-corelogback-classic:此外logback-classic完整实现Slf4J API使你可以很方便地更换成其它日志系统如log4jJDK14 Logging

与log4j的区别

1. 更快的实现 Logback的内核重写了,在一些关键执行路径上性能提升10倍以上。而且logback不仅性能提升了,初始化内存加载也更小了。

2. 非常充分的测试 Logback经过了几年,数不清小时的测试。Logback的测试完全不同级别的。这是简单重要的原因选择logback而不是log4j。

3. Logback-classic非常自然实现了SLF4j Logback-classic实现了 SLF4j。在使用SLF4j中,你都感觉不到logback-classic。而且因为logback-classic非常自然地实现了SLF4J, 所 以切换到log4j或者其他,非常容易,只需要提供成另一个jar包就OK,根本不需要去动那些通过SLF4JAPI实现的代码。

4. 非常充分的文档 官方网站有两百多页的文档。

5. 自动重新加载配置文件 当配置文件修改了,Logback-classic能自动重新加载配置文件。扫描过程快且安全,它并不需要另外创建一个扫描线程。这个技术充分保证了应用程序能跑得很欢在JEE环境里面。

6. Lilith Lilith是log事件的观察者,和log4j的chainsaw类似。而lilith还能处理大数量的log数据 。

7. 谨慎的模式和非常友好的恢复 在谨慎模式下,多个FileAppender实例跑在多个JVM下,能 够安全地写道同一个日志文件。RollingFileAppender会有些限制。Logback的FileAppender和它的子类包括 RollingFileAppender能够非常友好地从I/O异常中恢复。

8. 配置文件可以处理不同的情况 开发人员经常需要判断不同的Logback配置文件在不同的环境下(开发,测试,生产)。而这些配置文件仅仅只有一些很小的不同,可以通过,和来实现,这样一个配置文件就可以适应多个环境。

9. Filters(过滤器) 有些时候,需要诊断一个问题,需要打出日志。在log4j,只有降低日志级别,不过这样会打出大量的日志,会影响应用性能。在Logback,你可以继续 保持那个日志级别而除掉某种特殊情况,如alice这个用户登录,她的日志将打在DEBUG级别而其他用户可以继续打在WARN级别。要实现这个功能只需 加4行XML配置。可以参考MDCFIlter 。

10. SiftingAppender(一个非常多功能的Appender) 它可以用来分割日志文件根据任何一个给定的运行参数。如,SiftingAppender能够区别日志事件跟进用户的Session,然后每个用户会有一个日志文件。

11. 自动压缩已经打出来的log RollingFileAppender在产生新文件的时候,会自动压缩已经打出来的日志文件。压缩是个异步过程,所以甚至对于大的日志文件,在压缩过程中应用不会受任何影响。

12. 堆栈树带有包版本 Logback在打出堆栈树日志时,会带上包的数据。

13. 自动去除旧的日志文件 通过设置TimeBasedRollingPolicy或者SizeAndTimeBasedFNATP的maxHistory属性,你可以控制已经产生日志文件的最大数量。如果设置maxHistory 12,那那些log文件超过12个月的都会被自动移除。

总结:logback 比 log4j 优秀,可以取代之。

导入依赖

<!--  logback start  -->
<dependency>
	<groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.3</version>
 </dependency>
 <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
     <groupId>ch.qos.logback</groupId>
     <artifactId>logback-access</artifactId>
     <version>1.2.3</version>
</dependency>
<!--   logback end   -->

配置文件

放在 resources 文件夹根目录下

<?xml version="1.0" encoding="UTF-8"?>
<!--
	说明:【logback.xml】
	1、日志级别及文件
		日志记录采用分级记录,级别与日志文件名相对应,不同级别的日志信息记录到不同的日志文件中
		例如:error级别记录到log.error.xxx.log或log.error.log(该文件为当前记录的日志文件),而log.error.xxx.log为归档日志,
		日志文件按日期记录,同一天内,若日志文件大小等于或大于10M,则按0、1、2...顺序分别命名
		例如log-level-2013-12-21.0.log
		其它级别的日志也是如此。

	2、文件路径
		若开发、测试用,在Eclipse中运行项目,则到Eclipse的安装路径查找logs文件夹.
		若部署到Tomcat下,则在Tomcat下的logs文件中.
		${catalina.base}能够取到项目部署时候的tomcat目录。

	3、Appender
		FILE-ERROR对应error级别,文件名以log.error.xxx.log形式命名
		FILE-WARN对应warn级别,文件名以log.warn.xxx.log形式命名
		FILE-INFO对应info级别,文件名以log.info.xxx.log形式命名
		FILE-DEBUG对应debug级别,文件名以log.debug.xxx.log形式命名
		STDOUT将日志信息输出到控制台上,为方便开发测试使用
 -->

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true.
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒.当scan为true时,此属性生效。默认的时间间隔为1分钟.
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <!-- 在Eclipse中运行,请到Eclipse的安装目录中找log文件,Tomcat下,请到Tomcat目录下找 -->
    <property name="LOG_PATH" value="${catalina.base}/logs"/>
    <!-- 项目名称 -->
    <property name="PROJECT_NAME" value="spring-starter"/>

    <!-- 控制台打印日志的配置 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} %level ${PROJECT_NAME} [%thread] [%logger{50}:%line] %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
    </appender>

    <!-- 配置DEBUG, INFO, WARN, ERROR 日志的Appender -->
    <appender name="FILE-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${LOG_PATH}/${PROJECT_NAME}/${PROJECT_NAME}.log.error.log</file>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,
                 可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
                 而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
            <fileNamePattern>${LOG_PATH}/${PROJECT_NAME}/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 除按日志记录之外,还配置了日志文件不能超过10M,若超过10M,日志文件会以索引0开始,
                 命名日志文件,例如log-error-2013-12-21.0.log -->
            <maxFileSize>10MB</maxFileSize>
            <!-- 日志文件保留天数 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!-- 追加方式记录日志 -->
        <append>true</append>
        <!-- 日志打印的格式 -->
        <encoder>
            <pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} %level ${PROJECT_NAME} [%thread] [%logger{50}:%line] %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <!-- 此日志文件只记录error级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="FILE-WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${LOG_PATH}/${PROJECT_NAME}/${PROJECT_NAME}.log.warn.log</file>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,
                 可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
                 而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
            <fileNamePattern>${LOG_PATH}/${PROJECT_NAME}/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 除按日志记录之外,还配置了日志文件不能超过10M,若超过10M,日志文件会以索引0开始,
                 命名日志文件,例如log-warn-2013-12-21.0.log -->
            <maxFileSize>10MB</maxFileSize>
            <!-- 日志文件保留天数 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!-- 追加方式记录日志 -->
        <append>true</append>
        <!-- 日志打印的格式 -->
        <encoder>
            <pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} %level ${PROJECT_NAME} [%thread] [%logger{50}:%line] %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <!-- 此日志文件只记录warn级别,不记录大于warn级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="FILE-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${LOG_PATH}/${PROJECT_NAME}/${PROJECT_NAME}.log.info.log</file>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,
                 可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
                 而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
            <fileNamePattern>${LOG_PATH}/${PROJECT_NAME}/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 除按日志记录之外,还配置了日志文件不能超过10M,若超过10M,日志文件会以索引0开始,
                 命名日志文件,例如log-info-2013-12-21.0.log -->
            <maxFileSize>10MB</maxFileSize>
            <!-- 日志文件保留天数 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!-- 追加方式记录日志 -->
        <append>true</append>
        <!-- 日志打印的格式 -->
        <encoder>
            <pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} %level ${PROJECT_NAME} [%thread] [%logger{50}:%line] %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <!-- 此日志文件只记录info级别,不记录大于info级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="FILE-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${LOG_PATH}/${PROJECT_NAME}/${PROJECT_NAME}.log.debug.log</file>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,
                 可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
                 而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
            <fileNamePattern>${LOG_PATH}/${PROJECT_NAME}/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 除按日志记录之外,还配置了日志文件不能超过10M,若超过10M,日志文件会以索引0开始,
                 命名日志文件,例如log-debug-2013-12-21.0.log -->
            <maxFileSize>10MB</maxFileSize>
            <!-- 日志文件保留天数 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!-- 追加方式记录日志 -->
        <append>true</append>
        <!-- 日志打印的格式 -->
        <encoder>
            <pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} %level ${PROJECT_NAME} [%thread] [%logger{50}:%line] %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <!-- 此日志文件只记录debug级别,不记录大于debug级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- SPRING等框架类代码日志打印, 输出到OTHER文件中, 出厂默认WARN以上 -->
    <appender name="OTHER" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 此日志文件只记录warn级别及其以上的 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>WARN</level>
        </filter>
        <!-- 正在记录的日志文件的路径及文件名 -->
        <File>${LOG_PATH}/${PROJECT_NAME}/${PROJECT_NAME}.log.other.log</File>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,
                 可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
                 而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
            <fileNamePattern>${LOG_PATH}/${PROJECT_NAME}/log-other-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 除按日志记录之外,还配置了日志文件不能超过10M,若超过10M,日志文件会以索引0开始,
                 命名日志文件,例如log-debug-2013-12-21.0.log -->
            <maxFileSize>35MB</maxFileSize>
            <!-- 日志文件保留天数 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!-- 追加方式记录日志 -->
        <append>true</append>
        <!-- 日志打印的格式 -->
        <encoder>
            <pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} %level ${PROJECT_NAME} [%thread] [%logger{50}:%line] %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
    </appender>

    <!--
        出厂默认输出level级别INFO, 排查问题时, 可以通过工具切换为TRACE.
        自定义模块日志打印 添加在后面.
        name需要修改为自己项目中的合适的package
     -->
    <logger name="com.tao" level="INFO" additivity="false">
        <appender-ref ref="FILE-ERROR" />
        <appender-ref ref="FILE-WARN" />
        <appender-ref ref="FILE-INFO" />
        <appender-ref ref="FILE-DEBUG" />
        <!-- 生产环境请将STDOUT去掉!!! -->
        <appender-ref ref="STDOUT" />
    </logger>

    <!-- 其他的warn级别及其以上的日志,通过OTHER来记录 -->
    <root level="WARN">
        <appender-ref ref="OTHER" />
    </root>
</configuration>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值