Spring6全面详解

Spring6全面详解

  自2022年11月,Spring6正式发布。在Spring6中,对于JDK的要求最低为 17+。(17 - 19)

部分文本摘抄于尚硅谷视频(bilibili)做了一定的排版和个人的理解。如果不是很熟悉,可以去看
Spring5全面详解 内容大约十万字左右, 对于Spring5的使用整理的较为全面,也都有解释部分,Spring6只是看以下是否具有一些特性上的更换。所以可能并没有Spring5的内容详细。但本篇大约在8-10万字左右。持续进行编写。


1. Spring6概述

1.1 Spring核心模块

在spring6中,Core的核心模块有以下内容

  1. IOC
  2. Container
  3. Events
  4. Resources
  5. i18n
  6. Validation
  7. Data Binding
  8. Type Conversion
  9. SpEL
  10. 10.AOP
  11. AOT(静态编译)

Spring6全面详解_第1张图片


1.1.1 Spring Core

SpringCore提供了IOC,DI,Bean配置装载创建的核心实现。核心概念:Beans,BeanFactory,BeanDefinitons,ApplicationContext。

  • Spring-Core(IOC和DI的基本实现)
  • Spring-Beans (BeanFactory和Bean的装配管理(BeanFactory))
  • Spring-Context(SpringContext上下文,即IOC容器(ApplicationContext)
  • Spring-Expression (Spring表达式语言)

1.1.2 Spring Aop

  • Spring-Aop 面向切面编程的应用模块,整合ASM,CGLib,JDK Proxy。
  • Spring-Aspect 集成AspectJ,Aop应用框架。
  • Spring-Instrument 动态Class Loading模块。

1.1.3 Spring Data Access

  • Spring-JDBC 属于是Spring对Jdbc的封装,用于简化JDBC的使用方法。
  • Spring-Orm 是Java对象与数据库数据映射的框架。
  • Spring-Oxm 是对象与Xml文件的映射框架。
  • Spring-Jms 是Spring对 Java Message Service(Java消息服务)的封装,用于服务间的相互通信。
  • Spring-Tx 是Spring的事务管理。

1.1.4 Spring Web

  • Spring-Web 是最基础的Web支持,建立于Spring-Context之上,通过Servlet和Listener来初始化Ioc容器。
  • Spring-WebMvc 实现了Web Mvc。
  • Spring-WebSocket 与前端的双工通信协议。
  • Spring-WebFlux 是Spring5.0+提供的,用于取代传统是Java Servlet,非阻塞式Reactive Web框架,异步,非阻塞,事件驱动服务。

1.1.5 Spring Message

  • Spring-Messaging 是Spring4.0+提供的,用于为Spring集成一些基础的报文传送服务。

1.1.6 Spring Test

  • Spring-Test 对于测试的支持,主要是针对于Junit的封装。



2. Spring6体验

2.1 引入Spring相关的依赖需求

    <dependencies>

        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>6.0.3version>
        dependency>

        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.13.2version>
            <scope>testscope>
        dependency>
        
		
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <version>1.18.26version>
        dependency>

    dependencies>

2.2 创建实体类和对应的XML配置文件

新建一个包,里面包含一个User实体类。 pojo -> User.java。然后User内含有以下代码。

package org.example.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@AllArgsConstructor
@NoArgsConstructor
@Data
@ToString
public class User {

    private String username;

    private String password;

    private Integer age;

    private String phoneNumber;

}

然后去创建对应的Spring配置文件。可以在Idea中快捷去创建对应的配置文件。右键resources的包,然后new —>
XML Configuration File。即可。创建完成后, 使Spring对我们的User类进行托管。


<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">

    <bean id="user" class="org.example.pojo.User">
        <property name="username" value="张三" />
        <property name="password" value="123456" />
        <property name="age" value="18" />
        <property name="phoneNumber" value="12368965432" />
    bean>

beans>

在完成上述步骤后,在一个具有Main方法的类中,去进行测试。

package org.example;

import org.example.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {

		// 通过Xml加载获取Ioc容器对象。
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

		// 通过Ioc容器获取Bean对象
        User user = applicationContext.getBean("user", User.class);

		// 打印对象内容,查看内容是否对的上。[User(username=张三, password=123456, age=18, phoneNumber=12368965432)]
        System.out.println(user);

    }
}

2.3 根据全包类名通过反射创建对象

Class<?> aClass = Class.forName("org.example.pojo.User");

User userClass = (User) aClass.getDeclaredConstructor().newInstance();

2.4 Spring创建好的对象放在哪里?

会放在一个Map集合里,该属性存在于 DefaultListableBeanFactory 类中。属性名称为:

 private final Map<String, BeanDefinition> beanDefinitionMap;

在该Map 中。

  • Key 代表唯一标识
  • Value 代表该类的定义(描述)



3. Log4j2日志整合

3.1 Log4j2重要组件

3.1.1 日志信息的优先级

日志日志的优先级从高到低有 TRACE < DEBUG < INFO < WARN < ERROR < FATAL

  • TRACE:追踪,是日志的最低级别,相当于追踪程序的执行。
  • DEBUG:调试,一般在开发中,都将其设置为最低的级别。
  • INFO:信息,输出重要的信息,使用较多。
  • WARN:警告,输出警告的信息。
  • ERROR:错误,输出错误的信息。
  • FALTAL:重大错误。

上面这些内容主要用于指定程序日志的重要程度,优先级高的日志信息会覆盖掉优先级低的日志信息,如果你在程序中使用一条INFO级别的日志信息,则DEBUG和TRACE不会显示。


3.1.2 日志信息输出的目的地

一般来说指的是,把日志输出到控制台,或者把日志输出到文件内进行本地存储。


3.1.3 日志信息输出的格式

就是决定了你输出日志的时候,日志以什么样的形式进行输出。


3.2 引入log4j2的依赖


<dependency>
        <groupId>org.apache.logging.log4jgroupId>
        <artifactId>log4j-coreartifactId>
        <version>2.20.0version>
dependency>


<dependency>
    <groupId>org.apache.logging.log4jgroupId>
    <artifactId>log4j-slf4j2-implartifactId>
    <version>2.20.0version>
dependency>

3.3引入log4j2配置文件

首先固定名称为:log4j2.xml 文件必须放到类根路径下。


<configuration>
    <loggers>
        
        <root level="DEBUG">
            <appender-ref ref="spring6log"/>
            <appender-ref ref="RollingFile"/>
            <appender-ref ref="log"/>
        root>
    loggers>

    <appenders>
        
        <console name="spring6log" target="SYSTEM_OUT">
            
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/>
        console>

        
        <File name="log" fileName="d:/spring6_log/test.log" append="false">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
        File>

        
        <RollingFile name="RollingFile" fileName="d:/spring6_log/app.log"
                     filePattern="log/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
            <SizeBasedTriggeringPolicy size="50MB"/>
            
            <DefaultRolloverStrategy max="20"/>
        RollingFile>
    appenders>
configuration>

在配置完成后,他是自动实现的。你在重新去执行Main方法的时候,就会看到对应的日志信息。同时目录下还会生成两个.log文件。

2023-03-02 10:41:18 889 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@2b72cb8a
2023-03-02 10:41:18 997 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 1 bean definitions from class path resource [applicationContext.xml]
2023-03-02 10:41:19 024 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'user'
User(username=张三, password=123456, age=18, phoneNumber=12368965432)

3.4 手动使用log日志

我们可以在我们的代码中,加入Log日志的使用。需要我们定义一个成员变量。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

private final Logger logger = LoggerFactory.getLogger(Main.class);

完整代码

package org.example;

import org.example.pojo.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class Main {

    private static final Logger logger = LoggerFactory.getLogger(Main.class);

    public static void main(String[] args) throws Exception {

        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        User user = applicationContext.getBean("user", User.class);

        System.out.println(user);
        
        logger.info("我们执行了Main方法");

    }
}

得到的日志结果为:

2023-03-02 10:46:07 133 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@490caf5f
2023-03-02 10:46:07 209 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 1 bean definitions from class path resource [applicationContext.xml]
2023-03-02 10:46:07 225 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'user'
User(username=张三, password=123456, age=18, phoneNumber=12368965432)
2023-03-02 10:46:07 263 [main] INFO org.example.Main - 我们执行了Main方法

在方法内,不止可以使用info方法,其他级别的都可以使用,有DEBUG,有ERROR等各种级别的方法供来调用。




4. IOC容器

IOC是 Inversion of Control 的简写,译为 “控制反转”,他不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则,能够指导我们设计出低耦合,优良的程序。

Spring通过Ioc来控制对象之间的创建和初始化,控制对象与对象之间的依赖关系,我们从IOC容器中获取到的Java对象称为Spring Bean对象。它与使用 new 关键字创建的Java对象没有任何区别。


4.1 控制反转

  • 控制反转是一种设计思想。
  • 是为了减少程序的耦合度,提高扩展能力。
  • 控制反转的内容将对象的创建权交给Spring Ioc来进行管理。将对象与对象之间的关系交给Ioc管理。
  • 通过DI(Dependency Injection) 依赖注入实现控制反转。

4.2 依赖注入

DI(Dependency Injection) 依赖注入实现控制反转。
常见的DI注入方式主要是以下两种:

  • 构造器注入
  • Set方法注入
    所以结论是,IOC是一种控制反转的思想,DI是对于控制反转思想的实现。

4.3 IOC容器在Spring的实现

Spring 的Ioc 容器就是IOC思想的一个落地实现。IOC内管理的内容组件称为Bean,在创建Bean之前,需要先创建IOC容器。对于IOC容器的实现,Spring提供了两种实现方式。


4.3.1 BeanFactory

该接口是针对于IOC的基本实现,但是该接口不面向开发人员,用于Spring内部开发使用。

4.3.2 ApplicationContext

BeanFactory的子接口,拥有比BeanFactory更多的特性,做了很多增强,面向开发人员,在绝大部分场景下,我们选择使用ApplicationContext,而不是使用底层的BeanFactory。


4.4 手写IOC容器(通过反射)

4.4.1 获取Class对象的三种方式

  • 通过对象名称 + .class : User.class
  • 通过全类名来加载类 : Class.forName(“全包类名”)
  • 通过对象来获取class对象 : new User().getClass()
// 获取Class对象的多种方式
@Test
public void test01() throws ClassNotFoundException {

    // 第一种方式 通过对象 .class
    Class<User> userClass = User.class;

    // 第二种方式 通过forName来获取class对象
    Class<?> aClass = Class.forName("org.example.pojo.User");

    // 第三种方式,通过new对象来获取class
    Class<? extends User> aClass1 = new User().getClass();
    
	// 通过反射创建对象
	User user = userClass.getDeclaredConstructor().newInstance();
	
	System.out.println(user);
    
}

4.4.2 通过反射获取对象的构造方法

有两种获取全部构造器的方式,分别是

  • getConstructors()
    • 获取该类中的所有的有参构造无参构造,但是只能获取public修饰的构造方法,private修饰的则无法访问
  • getDeclaredConstructors()
    • 与第一个不同且增强,可以获取到private修饰的构造方法,也可以获取到public修饰的构造方法。

代码示例

// 通过反射获取构造方法。
@Test
public void test02() throws Exception {

    Class<User> userClass = User.class;

    // 第一种获取方式(针对public修饰过的构造方法)
    Constructor<?>[] constructors = userClass.getConstructors();

    for (Constructor<?> constructor : constructors) {
        System.out.println("构造器名称: " + constructor.getName() + "\n参数个数: " + constructor.getParameterCount());
    }

    // 第二种获取方式(可以获取到private修饰的构造方法)
    Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();

    for (Constructor<?> declaredConstructor : declaredConstructors) {
        System.out.println("构造器名称: " + declaredConstructor.getName() + "\n参数个数: " + declaredConstructor.getParameterCount());
    }

}

你可能感兴趣的:(Spring,spring,java,后端)