参考自B站UP主视频《孙哥说Spring5》
文章目录
什么是Spring Framework?
EJB存在的问题
- 运行环境苛刻
- 代码可移植性差(只要运行的服务器改变了,代码就要随之而改变,且服务器因为是闭源收费的,对服务器就无法进行深度定制)
所以也就称为重量级框架
什么是Spring?
Spring是一个轻量级的JavaEE解决方案,整合众多优秀的设计模式
-
轻量级:对于运行环境是没有额外的要求
-
代码移植性高:不需要实现额外的接口(EJB代码需要专门实现服务器的接口)
-
JavaEE解决方案:有众多产品可以整合进入(SpringMVC、Mybatis等)
-
合理运用了优秀的设计模式
1. 工厂模式(核心)
2. 代理模式
3. 模板模式
4. 策略模式
设计模式简介
- 广义概念:面向对象设计中,解决特定问题的经典代码
- 狭义概念: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>
- 配置文件的放置位置:任意位置 没有硬性要求
- 配置文件命名:没有硬性要求 建议:
applicationContext.xml
- 注意:日后应用Spring框架时,需要进行配置文件路径的设置。(IDEA中配置即可)
Spring 的核心API
ApplicationContext
- 作用:Spring提供的ApplicationContext工厂,用于对象的创建
- 好处:解耦合
- 特性:
ApplicationContext 为 【接口类型】
接口:可屏蔽实现的差异
提供了两种接口的实现
非web环境:ClassPathXmlApplicationContext
web环境:XmlWebApplicationContext
ApplicationContext 为 【重量级资源】--> ApplicationContext工厂的对象会【占用大量内存】
不会频繁的创建对象:(单例)
一个应用只会创建一个工厂对象
ApplicationContext工厂:
一定是【线程安全】的(多线程并发访问)
程序开发应用
- 创建类型
- 配置文件的配置:
applicationContext.xml
- 通过工厂类,获得对象:
ApplicationContext
或ClassPathXmlApplication
实体类
//-----------------------------------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
,使你可以很方便地更换成其它日志系统如log4j
或JDK14 Logging
logback-access
:与Servlet容器
集成提供通过Http
来访问日志的功能
logback-corelogback-classic
:此外logback-classic
完整实现Slf4J API
使你可以很方便地更换成其它日志系统如log4j
或JDK14 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>