Spring

spring框架概述

  • spring是一个轻量级的开源框架

  • spring解决企业开发的复杂性

  • spring有两个核心部分IOCAop

    • IOC:控制反转,把创建对象的过程交给spring进行管理

    • Aop:面向切面编程,不修改源代码的情况下进行功能增强


spring下载地址image-20220130164829123

spring基本5个jar包image-20220130165213984

使用步骤:

  • 导入jar包
  • 在src目录下创建spring使用的xml配置文件(spring config文件)
  • 配置相关对象
  • 启动程序

IOC容器

通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中

使用IOC的目的:为了降低耦合度


IOC底层原理

xml解析、工厂模式、反射

image-20220130173046282




IOC接口(BeanFactory)

IOC思想基于IOC容器完成,IOC容器底层就是对象工厂

spring提供IOC容器实现的两种方式

  • BeanFactory:IOC容器基本实现方式,是spring内部使用的接口,不建议使用

    • BeanFactory是懒加载,一开始只读取配置文件,获取对象时才创建对象
  • ApplicationContext:是BeanFactory的子接口,提供更多更强大的功能

    • 加载配置文件时就创建对象

    • 有两个实现类FileSystemXmlApplicationContext(盘符路径)和ClassPathXmlApplicationContext(类路径)


1
2
3
4
5
//使用配置好的对象
//1、加载spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("配置文件名.xml")
//2、获取配置创建的对象
User user = context.getBean("对象配置的id值", User.class/*要创建的类型*/);



IOC操作Bean管理(基于xml)

Bean管理

Bean管理指的是两个操作

  • spring创建对象
  • spring注入属性
1
2
3
4
5
6
7
8
9
<!--spring创建对象-->
<!--使用bean标签可以实现对象创建-->
<!--创建对象的时候,默认执行无参构造方法-->
<bean id="user" class="com.springDemo.User"></bean>

<!--在bean标签中有很多属性(常见)-->
id属性:给对象取一个别名(唯一标识)
class属性:类全路径(包全路径)
name属性:与id属性效果一致,但是name中可以添加特殊符号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!--spring注入属性
DI:依赖注入,就是注入属性,是IOC的具体实现方式-->

<!--set注入-->
<!--1、先创建类,定义属性和对应的set方法-->
<!--2、在spring配置文件中创建对象并注入属性-->
<bean id="user" class="com.springDemo.User">
<property name="userName" value="jjw"></property>
<!--name属性就是类中属性名称 value就是要注入的值-->

<property name="address">
<null></null>
</property>
<!--属性可以是null值-->
</bean>

<!--构造注入-->
<!--1、先创建类,定义属性和有参构造方法-->
<!--2、在spring配置文件中创建对象并注入属性-->
<bean id="user" class="com.springDemo.User">
<constructor-arg name="userName" value="jjw"></constructor-arg>
<!--name属性就是类中属性名称 value就是要注入的值-->
</bean>

<!--p名称空间注入,可简化基于xml配置方式-->
<!--1、添加配置xmlns:p="http://www.springframework.org/schema/p"-->
<!--2、在spring配置文件中创建对象并注入属性-->
<bean id="user" class="com.test.User" p:userName="jjw"></bean>

注入外部bean

1
2
3
4
5
6
7
8
9
<bean id="user" class="com.springDemo.User">
<property name="userName" value="jjw"></property>
<!--注入外部bean使用ref属性-->
<property name="address" ref="address"></property>
</bean>

<bean id="address" class="com.springDemo.Address">
<property name="add" value="heibeishifandaxue"></property>
</bean>

级联赋值

1
2
3
4
5
6
7
8
9
<bean id="emp" class="com.Emp">
<property name="name" value="jjw"></property>
<property name="dept" ref="dept"></property>
<!--需要有这个属性的get方法-->
<property name="dept.name" value="技术部"></property>
</bean>
<bean id="dept" class="com.Dept">
<property name="dname" value="后勤部"></property>
</bean>

注入集合属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<bean id="user" class="com.springDemo.User">
<!--数组类型属性注入-->
<property name="courses">
<array>
<value>123</value>
<value>234</value>
<value>345</value>
</array>
</property>

<!--List类型属性注入-->
<property name="list">
<list>
<value>123</value>
<value>234</value>
<value>345</value>
<!--注入引用类型
<ref bean=""></ref>
<ref bean=""></ref>
<ref bean=""></ref>-->
</list>
</property>

<!--Map类型属性注入-->
<property name="map">
<map>
<entry key="" value=""></entry>
<entry key="" value=""></entry>
<entry key="" value=""></entry>
</map>
</property>

<!--Set类型属性注入-->
<property name="set">
<set>
<value>123</value>
<value>234</value>
<value>345</value>
</set>
</property>
</bean>

提取集合类型

1、添加util配置

image-20220131135613821

2、提取集合,并注入

1
2
3
4
5
6
7
8
9
<util:list id="users">
<value>123</value>
<value>234</value>
<value>345</value>
</util:list>

<bean id="user" class="com.User">
<property name="users" ref="users"></property>
</bean>


spring有两种类型bean,一种普通bean,另一种工厂bean(FactoryBean)

1、普通bean:在配置文件中定义bean类型就是返回类型

2、工厂bean:在配置文件定义bean类型可以和返回类型不一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import org.springframework.beans.factory.FactoryBean;

public class MyBean implements FactoryBean<User> {

//定义返回的bean
@Override
public User getObject() throws Exception {
User user = new User();
user.setUserName("jjw");
return user;
}

@Override
public Class<?> getObjectType() {
return null;
}

//是否为单例
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
1
2
<bean id="mybean" class="com.test.MyBean"></bean>
<!--当使用getbean方法获得bean时,返回User-->

Bean的作用域

作用域就是单实例、多实例、request、session

在spring里面,可以设置bean实例是单实例或者多实例

在spring里面,默认情况是单实例


单例:

当bean为单例模式时,加载spring配置文件时就会创建单例对象

1
<bean ... scope="singleton"> <!--单例-->

多例:

当bean为多例时,执行getBean方法时才创建对象

1
<bean ... scope="prototype"> <!--多例-->

Bean的生命周期

1、通过构造器创建bean实例(无参构造)

2、为bean的属性设置值和对其他bean的引用(调用set方法)

(可以添加后置处理器,添加后在第3步之前将bean实例传递给后置处理器的postProcessBeforeInitialization方法)

3、调用bean的初始化方法(需要自己配置)

(可以添加后置处理器,添加后在第3步之后将bean实例传递给后置处理器的postProcessAfterInitialization方法)

4、bean可以使用

5、当容器关闭时,调用bean的销毁方法(需要自己配置)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.test;

public class Orders {
private String oname;

public Orders() {
System.out.println("第一步,执行无参构造方法");
}

public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步,调用set方法设置属性值");
}

public void init(){
System.out.println("第三步,执行初始化方法");
}

public void destroy(){
System.out.println("第五步,执行销毁方法");
}
}
1
2
3
<bean id="orders" class="com.test.Orders" init-method="init" destroy-method="destroy">
<property name="oname" value="jjw"></property>
</bean>

Bean自动装配

根据指定的装配规则(属性名称属性类型),spring自动将匹配的属性值进行注入

1
2
3
4
5
6
7
8
9
10
11
12
<!--bean标签的autowire属性可以实现自动装配
autowire属性常用的两个值为
byName:根据属性名注入,采用的时set注入,所以需要有set方法
byType:根据属性类型注入,采用的时set注入,所以需要有set方法-->

<bean id="user" class="com.test.User" autowire="byName"></bean>
<!--类中的属性名要与xml中id值一致-->
<bean id="orders" class="com.test.Orders"></bean>

<bean id="user" class="com.test.User" autowire="byType"></bean>
<!--类中的属性名要与xml中id值一致-->
<bean id="orders" class="com.test.Orders"></bean>

引入外部属性文件

1、创建外部属性文件,properties格式的文件

1
2
3
4
5
6
<!--以阿里的德鲁伊数据库连接池配置为例-->
建议加上***.***否则容易命名冲突
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/userDb
prop.userName=root
prop.password=root

2、添加context上下文配置

image-20220131195517342

3、将外部properties文件引入到spring配置文件中

1
2
3
4
5
6
7
8
<context:property-placeholder location="classpath:***.properties"/>

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.password}"></property>
</bean>



IOC操作Bean管理(基于注解)

  • @Component:普通的组件
  • @Service:用于业务逻辑层
  • @Controller:用于控制层
  • @Repository:用于dao层

功能是一样的,都可以用来创建bean实例


基于注解创建对象

1、引入spring.aop.x.x.x.RELEASE.jar

2、开启组件扫描,添加context上下文配置(多个包之间逗号隔开)

image-20220131195517342

1
2
<!--开启组件扫描-->
<context:component-scan base-package="要扫描的包(包名),包名,..."></context:component-scan>

3、创建类,添加注解

1
2
3
4
@Component(value = "user") //默认value为类名首字母小写的驼峰命名法
public class User{
...
}

开启包扫描的细节

自定义扫描的包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--
use-default-filters="false":表示现在不使用默认filter,自己配置filter
context:include-filter:设置要扫描的内容
context:exclude-filter:设置不扫描的内容
type="annotation" 表示根据注解来扫描
expression="org.springframework.stereotype.Controller":表示只扫描双引号里的注解-->

<context:component-scan base-package="com" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

<context:component-scan base-package="com">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>
</context:component-scan>

基于注解实现属性注入

@AutoWired:根据属性类型自动注入

@Qualifier:根据属性名称自动注入

@Resource:根据类型或者名称自动注入

@Value:注入普通类型属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class User {
@Autowired
private Orders orders;
}

//@Qualifier需要和@AutoWired搭配使用
public class User {
@Autowired
@Qualifier(value = "orders"/*id值*/)
private Orders orders;
}

public class User {
@Resource //@Resource(name="orders"/*id值*/)
private Orders orders;
}

public class User {
@Value(value = "jjw")
private String name;
}

基于注解注入多例

1、在需要多例调用的类上加 @Scope(“prototype”)

2、在进行注入时不能直接使用 @Autowired ,最简单的方法是使用工厂方式注入

1
2
3
4
//自动注入一个工厂,使用工厂实例化需要多例的类
@Autowired
private ObjectFactory<T> objectFactory;
T t = objectFactory.getObject();

完全注解开发

1、创建配置类,替代xml配置文件

1
2
3
4
@Configuration //作为配置类,替代配置文件
@ComponentScan(basePackages = "com.test") //开启包扫描
public class SpringConfig {
}

2、加载配置类,通过配置类获取bean

1
2
3
4
5
6
7
8
public class Test {
public static void main(String[] args) {
//加载配置类
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
Orders orders = context.getBean("orders",Orders.class);
orders.setOname("jjw");
}
}



AOP


AOP概念

什么是Aop

  • 面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低提高程序的可重用性,同时提高了开发的效率

  • 主要目的是将日志记录、性能统计、事物管理、异常处理等代码从业务逻辑代码中划分出来,从而可以在不修改源代码的情况下添加新的功能

image-20220201165200537


AOP底层原理

AOP底层使用了动态代理的方式,增强类中某个方法的功能

有两种情况的动态代理

1、有接口的情况,使用JDK动态代理

image-20220201201233960

创建接口实现类代理对象,增强类的方法


实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
*使用反射包下的Proxy类的newProxyInstance方法
*第一个参数:类加载器
*第二个参数:增强方法所在的类。这个类实现的接口,支持多个接口
*第三个参数:实现这个InvocationHandler,创建代理对象,写增强的方法
*/
public class JDKProxy {
public static void main(String[] args) {
Class[] interfaces = {UserDao.class};
UserDaoImpl userDaoImpl = new UserDaoImpl();
UserDao userDao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {

//增强的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

//方法之前
System.out.println("方法之前执行...."+method.getName());

//要增强的方法
Object result = method.invoke(userDaoImpl,args);

//方法之后执行
System.out.println("方法之后执行...."+method.getName());

return result;
}
});
}
}

2、没有接口的情况,使用CGLIB动态代理

image-20220201203010743

创建子类的代理对象,增强子类的方法




AOP术语

1、连接点

类里面哪些方法可以被增强,这些方法称为连接点


2、切入点

实际被真正增强的方法,称为切入点


3、通知

  • 实际增强的逻辑部分称为通知

  • 通知有多种类型

    • 前置通知
    • 后置通知
    • 环绕通知
    • 异常通知
    • 最终通知

4、切面

把通知应用到切入点的过程,称为切面


AOP操作

参考:https://www.cnblogs.com/joy99/p/10941543.html

spring框架一般都是基于AspectJ实现AOP操作 *AspectJ不是spring的组成部分,它是一个独立的AOP框架


引入AspectJ依赖image-20220202201934490

语法结构image-20220202202149656


注解方式

1、创建User类,在类中定义方法

2、创建UserProxy增强类

3、进行通知的配置

  • 在spring配置文件中开启配置扫描
  • 使用注解创建UserUserProxy
  • 在增强类上添加注解**@Aspect**
  • 在spring配置文件中开启生成代理对象

4、配置不同类型的通知

  • 在增强类里面,在作为通知方法上添加通知类型注解,使用切入点表达式配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启注解扫描-->
<context:component-scan base-package="com"></context:component-scan>

<!--开启Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

1
2
3
4
5
6
@Component
public class User {
public void add(){
System.out.println("add......");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Component
@Aspect
public class UserProxy {
//前置通知
//@Before注解表示作为前置通知
@Before("execution(* com.test.User.add(..))")
public void before(){
System.out.println("before.....");
}

//后置通知
@After("execution(* com.test.User.add(..))")
public void after(){
System.out.println("after.....");
}

//异常通知
@AfterThrowing("execution(* com.test.User.add(..))")
public void afterThrowing(){
System.out.println("afterThrowing.....");
}

//环绕通知
@Around("execution(* com.test.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
System.out.println("around1.....");

//被增强的方法执行
proceedingJoinPoint.proceed();

System.out.println("around2.....");

}
}
1
2
3
4
5
6
7
8
public class Test {
public static void main(String[] args) {
//加载配置类
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
User user = context.getBean("user",User.class);
user.add();
}
}

image-20220203142803295


抽取相同的切入点

1
2
3
4
5
6
7
8
9
@Pointcut("execution(* com.test.User.add(..))")
public void pointCut(){}

//前置通知
//@Before注解表示作为前置通知
@Before("pointCut()")
public void before(){
System.out.println("before.....");
}

有多个增强类,对同一个方法进行增强,可以设置增强类优先级,使其按顺序增强

1
2
3
4
@Component
@Aspect
@Order(3) //数值越小,优先级越高
public class UserProxy {

配置文件方式

1、创建两个类,增强类和被增强类,创建方法

2、在spring配置文件中创建两个类对象

3、在spring配置文件中配置切入点

image-20220203150952815




JdbcTemplate

JdbcTemplate是spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库进行操作


引入jar包

image-20220203161721997

image-20220203161738736


数据库连接池配置

image-20220203162110508


配置JdbcTemplate对象,注入DataSource

image-20220203162731323


在dao层的dao实现类中注入JdbcTemplate对象

image-20220203164024760




JdbcTemplate操作数据库

添加

1、对应数据库表创建类

2、在dao进行数据库添加操作

1
2
3
4
5
6
7
8
public void add(Book book){
//创建sql语句
String sql = "insert into t_book value(?,?)";

//调用方法实现
//第一个参数为sql语句,第二个参数为对应?中的数值
int update = jdbcTemplate.update(sql, book.getName() , book.getPrice());
}

修改

1
2
3
4
5
6
7
public void updateBook(Book book){
//创建sql语句
String sql = "update t_book set book_naem=?,book_price=?, where book_id=?";

//调用方法实现
int update = jdbcTemplate.update(sql, book.getName() , book.getPrice() , book.getId());
}

删除

1
2
3
4
5
6
public void deleteBook(Book book){
//创建sql语句
String sql = "delete from t_book where user_id=?";
//调用方法实现
int update = jdbcTemplate.update(sql, book.getId());
}

查询

返回有多少条记录

1
2
3
4
5
public Integer selectCount(){
String sql = "select count(*) from t_book";
Integer count = jdbcTemplate.queryForObject(sql,Integer.class);
return count;
}

返回一个对象

1
2
3
4
5
6
7
public Book selectById(String id){
String sql = "select * from t_book where user_id = ?";

//BeanPropertyRowMapper会将返回的数据进行封装成对应的类,属性名需要一样
Book book = jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<Book>(Book.class),id);

}

返回一个集合

1
2
3
4
5
6
7
8
public List<Book> findAllBook(){
String sql = "select * from t_book";

//BeanPropertyRowMapper会将返回的数据进行封装成对应的类
List<Book> bookList = jdbcTemplate.query(sql,new BeanPropertyRowMapper<Book>(Book.class));

return bookList;
}xxxxxxxxxx8 1public List<Book> findAllBook(){2    String sql = "select * from t_book";3    4    //BeanPropertyRowMapper会将返回的数据进行封装成对应的类5    List<Book> bookList = jdbcTemplate.query(sql,new BeanPropertyRowMapper<Book>(Book.class));6    7    return bookList;8}public List<Book> findAllBook(){    String sql = "select * from t_book";        //BeanPropertyRowMapper会将返回的数据进行封装成对应的类   List<Book> bookList = jdbcTemplate.query(sql,new BeanPropertyRowMapper<Book>(Book.class));       return bookList;}

批量操作

批量添加

1
2
3
4
5
public void batchAdd(List<Object[]> batchArgs){
String sql = "insert into t_book value(?,?)";

int[] count = jdbcTemplate.batchUpdate(sql,batchArgs);
}

批量修改

1
2
3
4
5
public void batchUpdate(List<Object[]> batchArgs){
String sql = "update t_book set book_naem=?,book_price=?, where book_id=?";

int[] count = jdbcTemplate.batchUpdate(sql,batchArgs);
}

批量删除

1
2
3
4
5
public void batchDelete(List<Object[]> batchArgs){
String sql = "delete from t_book where user_id=?";

int[] count = jdbcTemplate.batchUpdate(sql,batchArgs);
}



事务

事务概念

事务时数据库操作最基本单元,逻辑上一组操作,要么都成功,要么都失败

在spring中进行事务操作有两种方式

1、编程式事务管理

2、声明式事务管理(底层使用AOP原理)


四大特性

  • 原子性
  • 一致性
  • 隔离性
  • 持久性

示例(银行转账为例)

image-20220204194207653

步骤

1、在spring配置文件中配置事务管理器

2、在spring配置文件中引入名称空间tx

image-20220204201052249

3、开启事务注解

4、在service层上添加事务注解(也可以添加到方法上面)

  • 如果把注解添加到类上面,这个类里面所有的方法都添加事务
  • 如果把这个注解添加到方法上面,就只给某一个方法添加事务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.password}"></property>
</bean>

<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>

<!--开启事务注解-->
<!--指定开启哪个事务管理器-->
<tx:annotation-driver transaction-manager="transactionManager"></tx:annotation-driver>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Repository
public class UserDaoImpl{
@Autowired
private JdbcTemplate jdbcTemplate;

public void reduceMoney(){
//创建sql语句
String sql = "update t_bank set money = money-? where username=?";
jdbcTemplate.update(sql,100,"jjw1");
}

public void addMoney(){
//创建sql语句
String sql = "update t_bank set money = money+? where username=?";
jdbcTemplate.update(sql,100,"jjw2");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
@Service
@Transactional
public class UserService{
@Autowired
private UserDao userDao;

public void accountMoney(){
//执行事务操作
userDao.reduceMoney();
userDao.addMoney;
}
}

声明式事务管理参数配置

@Transaction(参数)


propagation:事务的传播行为

  • 多事务方法直接进行调用,这个过程中事务是如何进行管理的(一个有无事务的方法调用另外一个有无事务的方法,事务如何进行处理)

spring定义了七种事务传播行为

image-20220204204012987


ioslation:事务隔离级别

  • 多事务操作之间不会产生影响,不会产生脏读,不可重复读、虚读

timeout:超时时间

  • 事务需要在一定的时间内进行提交,否则进行回滚
  • 默认为-1(不超时),设置时间已秒为单位

readOnly:是否只读

  • 只能查询操作
  • 默认为false(不只读)

rollbackFor:回滚

  • 设置出现哪些异常进行事务回滚

noRollbackFor:不回滚

  • 设置出现哪些异常进行不事务回滚


完全注解方式

创建配置类,使用配置类替代xml配置文件

image-20220204205657762

image-20220204205933089




spring5框架新功能

整个spring5框架是基于Java8的,运行时兼容JDK9


支持整合日志框架

spring5框架自带了通用的日志封装,官方建议使用Log4j2


整合Log4j2

1、引入jar包image-20220205124649342

2、创建log4j2.xml(名称固定)配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8" ?>
<!--日志级别以及优先级排序:oFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Confiquration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到1og4j2内部各种详细输出-->

<configuration status="INFO">
<!--先定义所有的appender-->
<appenders>
<!--输出日.志信息到控制台-->
<console name="Console" target="SYSTEM_OUT">
<!--控制日志输出的格式-->
<PatternLayout pattern="%d{yyyY-MM-dd HH:mm : ss .sss} [t] %-5level %logger{36} - %msg%n"/>
</console>
</appenders>
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
<!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
<loggers>
<root level="info">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>

3、自定义日志内容

1
2
3
4
5
private static final Logger log = LoggerFactory.getLogger(Test.class);
public static void main(String[] args) {
//加载配置类
log.info("info............");
}

Nullable注解和函数式注册对象

@Nullable

@Nullable注解可以使用在方法上面,属性上面,参数上面

方法:表示方法返回值可以为空,不会报空指针异常

属性值:表示属性值可以为空

参数:表示参数值可以为空


函数式注册对象

1
2
3
4
5
6
7
//创建GenericApplicationContext对象
GenericApplicationContext context = new GenericApplicationContext();
//调用context的方法对象注册
context.refresh();
context.registerBean("user",User.class,()-> new User());
//获取对象
User user = (User) context.getBean("user");



单元测试框架(JUnit5)

整合JUnit4

1、引入依赖

image-20220205145509132

image-20220205151659537


2、创建测试类,使用注解方式完成

1
2
3
4
5
6
7
8
9
10
11
@RunWith(SpringJUnit4ClassRunner.class) //单元测试框架
@ContextConfiguration("classpath:bean.xml") //加载配置文件
public class Jtest {
@Autowired
User user;

@Test //JUnit4下的@Test注解
public void test(){
user.add();
}
}

若不使用JUnit4框架的话test方法中需要加载配置文件后才能使用ioc容器中的bean,使用了@RunWith注解将会自动开启ioc容器,不需要再通过getBean()方法获得bean


整合JUnit5

1、引入依赖

image-20220205152322878


2、创建测试类,使用注解方式完成

1
2
3
4
5
6
7
8
9
10
11
12
13
//@ExtendWith(SpringExtension.class)
//@ContextConfiguration("classpath:bean.xml")

@SpringJUnitConfig(locations = "classpath:bean.xml") //复合注解
public class Jtest {
@Autowired
User user;

@Test
public void test(){
user.add();
}
}