Spring6框架学习

5c23d52f880511ebb6edd017c2d2eca2

学习笔记:尚硅谷Spring6基础篇_尚硅谷spring6资料-CSDN博客

尚硅谷Spring零基础入门到进阶,一套搞定spring6全套视频教程(源码级讲解)_哔哩哔哩_bilibili

Spring | Guides

Spring Framework Documentation :: Spring Framework

概述

Spring 是一款主流的 Java EE 轻量级开源框架 ,由于其轻便、易用和高效,被广泛应用于企业级Java应用开发中。

Spring包含了很多子框架和扩展,如Spring MVC、Spring Boot、Spring Cloud等。

Spring的主要特点是IOC容器和AOP技术,它们使得Java应用的开发和管理更加简单和高效。

Spring 目的是用于简化 Java 企业级应用的开发难度和开发周期。Spring 框架除了自己提供功能外,还提供整合其他技术和框架的能力

Spring Framework

狭义和广义

  • 广义的 Spring:Spring 技术栈

广义上的 Spring 泛指以 Spring Framework 为核心的 Spring 技术栈。

经过十多年的发展,Spring 已经不再是一个单纯的应用框架,而是逐渐发展成为一个由多个不同子项目(模块)组成的成熟技术,例如 Spring Framework、Spring MVC、SpringBoot、Spring Cloud、Spring Data、Spring Security 等,其中 Spring Framework 是其他子项目的基础。

这些子项目涵盖了从企业级应用开发到云计算等各方面的内容,能够帮助开发人员解决软件发展过程中不断产生的各种实际问题,给开发人员带来了更好的开发体验。

  • 狭义的 Spring:Spring Framework

狭义的 Spring 特指 Spring Framework,通常我们将它称为 Spring 框架。

Spring 框架是一个分层的、面向切面的 Java 应用程序的一站式轻量级解决方案,它是 Spring 技术栈的核心和基础,是为了解决企业级应用开发的复杂性而创建的。

Spring 有两个最核心模块: IoC 和 AOP。

  • IoC:Inverse of Control 的简写,译为“控制反转”,指把创建对象过程交给 Spring 进行管理。
  • AOP:Aspect Oriented Programming 的简写,译为“面向切面编程”。AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。

模块组成

v2-a6a4035fbafad6f43e9034931f8057ce_720w

Spring Core(核心容器)

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

  • spring-core :IOC和DI的基本实现
  • spring-beans:BeanFactory和Bean的装配管理(BeanFactory)
  • spring-context:Spring context上下文,即IOC容器(AppliactionContext)
  • spring-expression:spring表达式语言

Spring AOP(面向切面编程)

  • spring-aop:面向切面编程的应用模块,整合ASM,CGLib,JDK Proxy
  • spring-aspects:集成AspectJ,AOP应用框架
  • spring-instrument:动态Class Loading模块

Spring Data Access(数据访问)

  • spring-jdbc:spring对JDBC的封装,用于简化jdbc操作
  • spring-orm:java对象与数据库数据的映射框架
  • spring-oxm:对象与xml文件的映射框架
  • spring-jms: Spring对Java Message Service(java消息服务)的封装,用于服务之间相互通信
  • spring-tx:spring jdbc事务管理

Spring Web(应用程序)

  • spring-web:最基础的web支持,建立于spring-context之上,通过servlet或listener来初始化IOC容器
  • spring-webmvc:实现web mvc
  • spring-websocket:与前端的全双工通信协议
  • spring-webflux:Spring 5.0提供的,用于取代传统java servlet,非阻塞式Reactive Web框架,异步,非阻塞,事件驱动的服务

Spring Message(消息传递)

  • Spring-messaging:spring 4.0提供的,为Spring集成一些基础的报文传送服务

Spring test(测试)

  • spring-test:集成测试支持,主要是对junit的封装

Spring6特性

Spring6要求最低的JDK版本是Java17

GETTING STARTED

创建maven聚合工程

父工程spring6

子模块spring-first

步骤

  1. 引入spring相关依赖
  2. 创建类,定义属性和方法
  3. 按照spring要求创建配置文件(xml格式)
  4. 在spring配置文件配置相关信息
  5. final test

添加依赖

spring框架

1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.2</version>
</dependency>

以及junit

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.6.2</version>
</dependency>

用于后面那个@Test注释来进行运行代码

创建类,定义属性和方法

新建包com.atlant1c.spring6

新建两个类

User.java

1
2
3
4
5
6
7
8
9
10
11
12
package com.atlant1c.spring6;

public class User {
public void add() {
System.out.println("add……");
}

public static void main(String[] args){
User user = new User();
user.add();
}
}

TestUser.java

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

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUser {
@Test
public void testUserObject() {
// Load the Spring configuration file
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");

// Get the User object from the Spring container
User user = (User) applicationContext.getBean("user");

// Use the object to call the add() method
System.out.println("1"+user);

System.out.print("2");
user.add();
}
}

在rseources目录下新建配置文件bean.xml

1
2
3
4
5
6
7
8
9
<?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">
<!--bean标签
id属性:唯一标识
class属性:要创建对象所在类的全路径(包名称+类名称)-->
<bean id="user" class="com.atlant1c.spring6.User">
</bean></beans>

image-20240229110300787

运行

第一行输出的是user方法的地址值

第二行是调用user方法输出字符串

image-20240229105355639

踩坑记录

【idea中URI is not registered错误】_uri未注册-CSDN博客

xml注释要用形如<!---->

思考

之前创建对象,无参数构造执行?

在User.java添加无参构造

1
2
3
public User(){
System.out.println("0无参构造");
}

image-20240229111140274

可以看到执行了。

不用new怎么样创建对象?

利用反射

如何使用反射创建的对象

  1. 加载bean.xml配置文件

  2. 对xml文件进行解析

  3. 获取xml文件bean标签属性值(id和class)

  4. 使用反射根据类全路径创建对象

    1
    2
    Class clazz = Class.forName("com.atlant1c.spring6.User");
    User usr =(User)clazz.getDeclaredConstructor().newInstance();

创建对象放到哪里?

image-20240229112757676

添加Log4j2框架

概述:Log4j2是一个开源的Java日志框架,帮助Java开发人员在应用程序中实现灵活和可配置的日志记录

组成:日志信息的优先级,日志信息的优先级从高到低有TRACE < DEBUG < INFO < WARN < ERROR < FATAL

说明:

  1. TRACE:追踪,是最低的日志级别,相当于追踪程序的执行
  2. DEBUG:调试,一般在开发中,都将其设置为最低的日志级别
  3. INFO:信息,输出重要的信息,使用较多
  4. WARN:警告,输出警告的信息
  5. ERROR:错误,输出错误信息
  6. FATAL:严重错误
  1. 日志信息的输出目的地,日志信息的输出目的地指定了日志将打印到控制台还是文件中
  2. 日志信息的输出格式,而输出格式则控制了日志信息的显示内容。

引入框架依赖

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.19.0</version>
</dependency>

加入配置文件

同样在resourse添加log4j2.xml配置文件

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
42
43
44
45
<?xml version="1.0" encoding="UTF-8"?>

<configuration>
<loggers>
<!--level指定日志级别,从低到高的优先级:
TRACE < DEBUG < INFO < WARN < ERROR < FATAL
trace:追踪,是最低的日志级别,相当于追踪程序的执行
debug:调试,一般在开发中,都将其设置为最低的日志级别
info:信息,输出重要的信息,使用较多
warn:警告,输出警告的信息
error:错误,输出错误信息
fatal:严重错误-->
<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>

<!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用-->
<File name="log" fileName="D:/语言学习/java学习/学习源代码/spring/spring6_log/test.log" append="false">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
</File>

<!-- 这个会打印出所有的信息,
每次大小超过size,
则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,
作为存档-->
<RollingFile name="RollingFile" fileName="D:/语言学习/java学习/学习源代码/spring/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属性如不设置,
则默认为最多同一文件夹下7个文件,这里设置了20 -->
<DefaultRolloverStrategy max="20"/>
</RollingFile>
</appenders>
</configuration>

使用日志

image-20240229150924848

自定义日志

image-20240229152330168

容器Ioc

概述

容器放bean对象,存在map里面。

定义

IoC (Inversion of Control),即控制反转,是一种设计模式或者说设计思想,它是面向对象编程中的一种概念,用来描述对象之间的依赖关系,指导我们如何设计出松耦合、更优良的程序。

简介

Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化,控制对象与对象之间的依赖关系。我们将由 IoC 容器管理的 Java 对象称为 Spring Bean,它与使用关键字 new 创建的 Java 对象没有任何区别。

作用

在 IoC 模式中,控制权从程序代码中转移到了容器中,即通过容器来管理对象的创建、销毁、依赖注入等操作,而应用程序本身只需要使用这些对象即可。这样,应用程序就不需要自己管理对象之间的依赖关系,而是由容器来管理,从而实现了代码的解耦和更好的可维护性,提高程序扩展力。

说明:

  • 将对象的创建权利交出去,交给第三方容器负责
  • 将对象和对象之间关系的维护权交出去,交给第三方容器负责

实现过程

xml配置文件:

Bean定义信息BeanDefinition。

抽象(接口):

BeanDefinitionReader

image-20240229154304727

Ioc容器:

  1. Bean定义信息
  2. 实例化(BeanFactory工厂+反射)
  3. 初始化
  4. 最终对象context.getBean("");

依赖注入

控制反转思想的实践。

定义

依赖注入(Dependency Injection,DI)是一种设计模式,其主要思想是在程序运行的过程中,通过外部容器(如Spring容器)动态地将依赖对象注入到程序中,以解耦对象之间的依赖关系,从而提高程序的灵活性、可维护性和可测试性。

作用

Spring通过依赖注入的方式来完成Bean管理的。换句话说,依赖注入,依赖注入实现了控制反转的思想。依赖指的是对象和对象之间的关联关系。注入指的是一种数据传递行为,通过注入行为来让对象和对象产生关系。

补充:

Bean管理说的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)。

实现方式

  • 第一种:set注入
  • 第二种:构造注入

实现

Spring 的框架中,IoC 容器是通过 BeanFactoryApplicationContext 接口实现的。BeanFactory 接口是 Spring 框架最底层的接口,提供了基本的 IoC 功能;ApplicationContext 接口是 BeanFactory 接口的子接口,提供了更高级的特性和功能,如 AOP、国际化、事件驱动等。其中BeanFactory 接口,最重要的方法是getBean()方法,用于从容器中获取对象。

Spring 的 IoC 容器就是 IoC思想的一个落地的产品实现。IoC容器中管理的组件也叫做 bean。在创建 bean 之前,首先需要创建IoC 容器。Spring 提供了IoC 容器的两种实现方式:

  • BeanFactory:这是 IoC 容器的基本实现,是 Spring 内部使用的接口。面向 Spring 本身,不提供给开发人员使用。
  • ApplicationContext:BeanFactory 的子接口,提供了更多高级特性。面向 Spring 的使用者,几乎所有场合都使用 ApplicationContext 而不是底层的 BeanFactory

ApplicationContext的主要实现类:

类型名 简介
ClassPathXmlApplicationContext 通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象
FileSystemXmlApplicationContext 通过文件系统路径读取 XML 格式的配置文件创建 IOC 容器对象
ConfigurableApplicationContext ApplicationContext 的子接口,包含一些扩展方法 refresh() 和 close() ,让 ApplicationContext 具有启动、关闭和刷新上下文的能力。
WebApplicationContext 专门为 Web 应用准备,基于 Web 环境创建 IOC 容器对象,并将对象引入存入 ServletContext 域中。

image-20240229155610626

基于xml管理bean

获取bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.atlant1c.spring6.iocxml;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUser {
public static void main(String []args){
ApplicationContext context =new ClassPathXmlApplicationContext("bean.xml");
//1
User user1 = (User)context.getBean("user");
System.out.println("根据id获取bean"+user1);
//2
User user2 = context.getBean(User.class);
System.out.println("根据类型获取bean"+user2);
//3
User user3 = context.getBean("user",User.class);
System.out.println("根据id和类型获取bean"+user3);
}
}

image-20240229164535682

基于set方法完成

创建类,定义属性,生成属性set方法

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
package com.atlant1c.spring6.iocxml.di;

public class Book {
private String bname;
private String author;

public Book (){

}


public Book(String bname,String author){
this.bname = bname;
this.author = author;
}


//生成set方法
public String getAuthor() {
return author;
}

public String getBname() {
return bname;
}

public void setAuthor(String author) {
this.author = author;
}

public void setBname(String bname) {
this.bname = bname;
}
public static void main(String[] args){
Book book = new Book();
book.setBname("java");
book.setAuthor("Atlant1c");

Book book1 = new Book("python","Atlant1c");
}
}

在spring配置文件中配置

1
2
3
4
5
6
7
8
9
10
11
12
<?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">
<!--set方法完成注入-->
<bean id="book" class="com.atlant1c.spring6.iocxml.di.Book">
<property name="bname" value="前端开发">
</property>
<property name="author" value="Atlant1c">
</property>
</bean>
</beans>

新建TestBook类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.atlant1c.spring6.iocxml.di;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestBook {
@Test
public void testtSettter(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
Book book = (Book) context.getBean("book","Book.class");
System.out.println(book);
}
}

image-20240301154142759

基于构造器完成

创建类,定义属性,生成有参数构造方法

和上面一样

TestBook类中加入

1
2
3
4
5
6
@Test
public void testtConstructor(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
Book book = (Book) context.getBean("bookCon","Book.class");
System.out.println(book);
}

配置文件添加

1
2
3
4
5
6
<!--构造器方法完成注入-->
<bean id="bookCon" class="com.atlant1c.spring6.iocxml.di.Book">
<constructor-arg name="bname" value="java开发">
</constructor-arg>
<constructor-arg name="author" value="Atlant1c"></constructor-arg>
</bean>

image-20240301155734884

特殊值处理

字面量赋值

1
2
3
<!-- 使用value属性给bean的属性赋值时,Spring会把value属性的值看做字面量 -->
<property name="name" value="张三"/>
12

null值

1
2
3
4
<property name="name">
<null />
</property>
123

细节:

1
2
<property name="name" value="null"></property>
1

以上写法,为name所赋值为字符串null

5.2.3.3xml实体

1
2
3
<!-- 解决方案一:使用XML实体来代替 -->
<property name="expression" value="a &lt; b"/>
12

说明:

小于号在XML文档中用来定义标签的开始,不能随便使用

CDATA节

1
2
3
4
<property name="expression">
<!-- 解决方案二:使用CDATA节 -->
<value><![CDATA[a < b]]></value>
</property>

注入对象类型属性值

有三种注入方式,第三种用得少就没去try

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//TestEmp.java
package com.atlant1c.spring6.iocxml.ditest;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestEmp {
public static void main(String[] args){
ApplicationContext context =new ClassPathXmlApplicationContext("bean-ditest.xml");
Emp emp = context.getBean("emp1",Emp.class);
emp.work();

}
}


//Dept.java
package com.atlant1c.spring6.iocxml.ditest;

public class Dept {
private String Dname;

public void setDname(String dname) {
Dname = dname;
}

public void info(){
System.out.println("部门名称"+Dname);
}
}

//Emp.java
package com.atlant1c.spring6.iocxml.ditest;

public class Emp {
private Dept dept;

public void setDept(Dept dept) {
this.dept = dept;
}

private String ename;

public void setEname(String ename) {
this.ename = ename;
}

private Integer age;

public void setAge(Integer age) {
this.age = age;
}

public void work(){
System.out.println(ename+"emp work....."+age);
dept.info();
}
}

配置文件

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
<!--bean-ditest.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">
<!--外部bean-->
<bean id="dept1" class="com.atlant1c.spring6.iocxml.ditest.Dept">
<property name="dname" value="技术研发部"></property>
</bean>
<bean id="emp1" class="com.atlant1c.spring6.iocxml.ditest.Emp">
<property name="ename" value="jack"></property>
<property name="age" value="25"></property>
<property name="dept" ref="dept1"></property>
</bean>


<!--内部bean-->
<bean id="emp2" class="com.atlant1c.spring6.iocxml.ditest.Emp">
<property name="ename" value="mary"></property>
<property name="age" value="20"></property>
<property name="dept">
<bean id="dept2" class="com.atlant1c.spring6.iocxml.ditest.Dept">
<property name="dname" value="财务部"></property>
</bean>
</property>
</bean>
</beans>

注入集合类型属性值

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<?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">
<bean id="teacher" class="com.atlant1c.spring6.iocxml.dimap.Teacher">

</bean>


<bean id="student" class="com.atlant1c.spring6.iocxml.dimap.Teacher">

</bean>


<bean id="teacherOne" class="com.atlant1c.spring6.iocxml.dimap.Teacher">
<property name="tId" value="10010"></property>
<property name="tName" value="大宝"></property>
</bean>

<bean id="teacherTwo" class="com.atlant1c.spring6.iocxml.dimap.Teacher">
<property name="tId" value="10086"></property>
<property name="tName" value="二宝"></property>
</bean>
<bean id="stu1" class="com.atlant1c.spring6.iocxml.dimap.Student">
<property name="sId" value="01"></property>
<property name="sName" value="zs"></property>
<property name="teacherMap">
<map>
<entry>
<key>
<value>10010</value>
</key>
<ref bean="teacherOne"></ref>
</entry>
</map>
</property>
</bean>

<bean id="stu2" class="com.atlant1c.spring6.iocxml.dimap.Student">
<property name="sId" value="02"></property>
<property name="sName" value="ls"></property>
<property name="teacherMap">
<map>
<entry>
<key>
<value>10011</value>
</key>
<ref bean="teacherTwo"></ref>
</entry>
</map>
</property>
</bean>


</beans>

注入引用集合类型属性值

配置对应的命名空间

1
2
3
4
5
6
7
8
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

配置Bean

注:

  • 使用标签,可以将List集合或者Map集合的属性注入变为引用的方式
  • 在使用util标签时,需要引入相应的命名空间

引入外部属性文件

  1. 引入数据库相关依赖。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     <!-- MySQL驱动 -->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.30</version>
    </dependency>

    <!-- 数据源 -->
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.15</version>
    </dependency>
  2. 创建外部属性文件,properties格式。

  3. 创建spring配置文件,引入context命名空间进入属性文件,使用表达式完成注入。

Bean的生命周期

流程

  1. bean对象创建(调用无参构造器)

  2. bean对象设置属性

  3. bean的后置处理器(初始化之前)

  4. bean对象初始化(需在配置bean时指定初始化方法)

  5. bean的后置处理器(初始化之后)

  6. bean对象就绪可以使用

  7. bean对象销毁(需在配置bean时指定销毁方法)

  8. IOC容器关闭

引入FactoryBean属性值

用来整合其他框架

引入xml自动装配

自动装配就是让应用程序上下文为你找出依赖项的过程。service层给control层,control层给dao层。

在xml中通过byName进行自动装配

使用byName进行自动装配时候的注意事项

  1. bean的id必须与被装配的实体类中的setXXX()中的参数名相同
  2. 在beans中的bean的id必须具有唯一性。

在xml中通过byType进行自动装配

使用byType进行自动装配时候的注意事项:

  1. bean的class必须与被装配的实体类中的setXXX()中的参数类型相同
  2. 在beans中的bean的class必须具有唯一性。

基于注解管理Bean

从 Java 5 开始,Java 增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译、类加载和运行时被读取,执行相应的处理。开发人员可以通过注解在不改变原有代码和逻辑的情况下,在源代码中嵌入补充信息。

Spring 从 2.5 版本开始提供了对注解技术的全面支持,我们可以使用注解来实现自动装配,简化 Spring 的 XML 配置。

步骤

  1. 引入依赖
  2. 开启组件扫描
  3. 使用注解定义 Bean
  4. 依赖注入

使用注解
Spring 提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean

注解 说明
@Component 该注解用于描述 Spring 中的 Bean,它是一个泛化的概念,仅仅表示容器中的一个组件(Bean),并且可以作用在应用的任何层次,例如 Service 层、Dao 层等。 使用时只需将该注解标注在相应类上即可。
@Repository 该注解用于将数据访问层(Dao 层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
@Service 该注解通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
@Controller 该注解通常作用在控制层(如SpringMVC 的 Controller),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

开启组件扫描

实现组件扫描

步骤一:添加约束

1
2
3
4
5
6
7
8
9
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
</beans>

说明:

在 XML 配置的一级标签 中添加 context 相关的约束

步骤二:开启扫描方式

1
2
<context:component-scan base-package="com.atguigu.spring6">
</context:component-scan>

说明:

在Beans.xml文件中,设置开启扫描方式即可

指定要排除的组件

1
2
3
4
5
6
7
8
9
10
11
<context:component-scan base-package="com.atguigu.spring6">
<!-- context:exclude-filter标签:指定排除规则 -->
<!--
type:设置排除或包含的依据
type="annotation",根据注解排除,expression中设置要排除的注解的全类名
type="assignable",根据类型排除,expression中设置要排除的类型的全类名
-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<!--<context:exclude-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>-->
</context:component-scan>
说明:

context:exclude-filter标签,指定排除规则
type属性:设置排除或包含的依据
属性值:annotation,根据注解排除
属性值:assignable,根据类型排除
expression属性:设置要排除的注解或类型的全类名

仅扫描指定组件

1
2
3
4
5
6
7
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<!-- context:include-filter标签:指定在原有扫描规则的基础上追加的规则 -->
<!-- use-default-filters属性:取值false表示关闭默认扫描规则 -->
<!-- 此时必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类 -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<!--<context:include-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>-->
</context:component-scan>

说明:

use-default-filters=”false”,表示关闭默认扫描规则
context:include-filter,表示指定的过滤条件来确定哪些类应该被包含在组件扫描中

@Autowired注入

属性注入

通过@Autowired注释然后新建一个私有的属性,来注入该属性类。

set注入

把@Autowired注解用在set方法上进行注入。

构造注入

形参上注入

文件结构如下

image-20240308215712627

controller

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
//UserController.java
package com.atlant1c.spring6.atowired.controller;

import com.atlant1c.spring6.atowired.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
//方法一,属性注入
//@Autowired//根据类型找到对象
private UserService userService;

//方法二,set注入
/* @Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}*/
//方法三,构造方法注入
/* @Autowired
public UserController(UserService userService){
this.userService = userService;
}*/

//方法四,形参上注入
/* public UserController(@Autowired UserService userService){
this.userService = userService;}*/

//方法五,只有一个有参数构造函数,无注解注入
public UserController(UserService userService) {
this.userService = userService;
}

public void add(){
System.out.println("controller");
userService.add();
}
}


dao

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//UserDao.java
package com.atlant1c.spring6.atowired.dao;

public interface UserDao {
public void add();
}

//UserDaoImpl.java
package com.atlant1c.spring6.atowired.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImpl implements UserDao{

@Override
public void add(){
System.out.println("dao");
}
}

service

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
42
43
44
45
46
47
48
//UserService.java
package com.atlant1c.spring6.atowired.service;

public interface UserService {
void add();
}

//UserServiceImpl.java
package com.atlant1c.spring6.atowired.service;

import com.atlant1c.spring6.atowired.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService{
//方法一,属性注入
//@Autowired
private UserDao userDao;

//方法二,set注入
/* @Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}*/
//方法三,构造方法注入
/* @Autowired
public UserServiceImpl(UserDao userDao){
this.userDao = userDao;
}*/

//方法四,形参上注入
/*public UserServiceImpl(@Autowired UserDao userDao){
this.userDao = userDao;
}*/

//方法五,只有一个有参数构造函数,无注解注入
public UserServiceImpl(UserDao userDao){
this.userDao = userDao;
}

@Override
public void add() {
System.out.println("service");
userDao.add();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//TestUserController.java
package com.atlant1c.spring6.atowired;

import com.atlant1c.spring6.atowired.controller.UserController;
import com.atlant1c.spring6.bean.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUserController {
public static void main(String[] args){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
UserController controller = context.getBean(UserController.class);
controller.add();
}
}

@Autowired注解和@Qualifier注解联合

当dao层有两个类需要被注入时,就会报错

image-20240308223037545

这个时候就需要根据名称注入

@Resourse注解

@Resource注解是通过名称匹配的方式来实现注入的,默认按照名称进行匹配,如果找不到匹配的名称,则会尝试按照类型匹配。

@Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该注解是标准注解,更加具有通用性。(JSR-250标准中制定的注解类型。JSR是Java规范提案。)

@Resource注解既可以用在setter中也可以用在属性当中,当Resource指定属性name名字时,就只会按照指定的name去查找bean,否则会报错。

当注解写在字段上时,@Resource不指定name,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。如果最后都找不到与名称匹配的bean时才按照类型进行装配。我们运行也会成功 

面向切面AOP

代理模式

JDK动态代理 | Atlantic (atlant1c.cn)

横切关注点

从目标对象中抽取出来的非核心业务,比如之前代理模式中的日志功能,针对于计算器功能来说,日志就是非核心业务。

这个概念不是语法层面天然存在的,而是根据附加功能的逻辑上的需要:有十个附加功能,就有十个横切关注点。

通知

非核心的业务再目标对象中叫做横切关注点,将横切关注点抽取出来封装到切面类中,他就是这个类中的一个方法叫做通知。

每一个横切关注点要做的事情都封装成一个方法,这样的方法就叫做通知方法。

  • 前置通知:在被代理的目标方法前执行
  • 返回通知:在被代理的目标方法成功结束后执行(寿终正寝)
  • 异常通知:在被代理的目标方法异常结束后执行(死于非命)
  • 后置通知:在被代理的目标方法最终结束后执行(盖棺定论)
  • 环绕通知:使用try…catch…finally结构围绕整个被代理的目标方法,包括上面四种通知对应的所有位置
切面

封装横切关注点的类,通知的方法都写在切面类中

目标

被代理的目标对象,比如计算器的实现类

代理

代理对象

连接点

一个纯逻辑的概念:抽取横切关注点的位置,比如方法执行之前,方法捕获异常的时候等等。

连接点的作用:我们不但要抽取出来,还要套回去。

切入点表达式

在 AOP 中,切入点表达式指定了哪些方法需要被织入增强逻辑。它是一个表达式,用于匹配目标对象中的方法,并提供切入点的精确定义

8578fde55d6dd885a62f6c213c677d93

基于注解AOP

  1. 概述:在Java类、方法、参数等上添加注解的方式来实现切面的定义和应用

  2. 基本用例:

    步骤一:导入依赖

    步骤二:创建切面类(需要选择通知方式)

    步骤三:添加xml配置文件

  3. 通知方式:

    1. 前置通知:@Before
    2. 异常通知:@AfterThrowing
    3. 返回通知:@AfterReturning
    4. 后置通知:@After
    5. 环绕通知:@Around
  4. 获取通知信息

    1. 获取连接点:在方法中使用JoinPoint即可获取连接点信息

      1
      2
      public void beforeMethod(JoinPoint joinPoint)

    2. 获取目标对象的返回值:在目标对象的返回通知上添加returning属性

      1
      2
      @AfterReturning(value = "execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..))", returning = "result")
      public void afterReturningMethod(JoinPoint joinPoint, Object result)
    3. 获取目标对象的异常:在目标对象的异常通知上添加throwing属性

      1
      2
      @AfterThrowing(value = "execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..))", throwing = "ex")
      public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex)
  5. 重用切入点表达式

    1. 声明:在空参、空方法体、空返回值的方法上使用**@Pointcut**注解

      1
      2
      @Pointcut("execution(* com.atguigu.aop.annotation.*.*(..))")
      public void pointCut(){}
    2. 同切面使用:在同一切面中直接引用即可

      1
      @Before("pointCut()")
    3. 不同切面使用:在不同切面中

      1
      @Before("com.atguigu.aop.CommonPointCut.pointCut()")

基于XML注解的AOP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<context:component-scan base-package="com.atguigu.aop.xml"></context:component-scan>

<aop:config>
<!--配置切面类-->
<aop:aspect ref="loggerAspect">
<aop:pointcut id="pointCut"
expression="execution(* com.atguigu.aop.xml.CalculatorImpl.*(..))"/>
<aop:before method="beforeMethod" pointcut-ref="pointCut"></aop:before>
<aop:after method="afterMethod" pointcut-ref="pointCut"></aop:after>
<aop:after-returning method="afterReturningMethod" returning="result" pointcut-ref="pointCut"></aop:after-returning>
<aop:after-throwing method="afterThrowingMethod" throwing="ex" pointcut-ref="pointCut"></aop:after-throwing>
<aop:around method="aroundMethod" pointcut-ref="pointCut"></aop:around>
</aop:aspect>
</aop:config>

JDBC template

【Spring】通过JdbcTemplate实现CRUD操作-腾讯云开发者社区-腾讯云 (tencent.com)

JdbcTemplate (Spring Framework 6.1.4 API)

使用JDBC - 廖雪峰的官方网站 (liaoxuefeng.com)

这是 JDBC 核心包中的中心委托。它可以直接用于许多数据访问目的,支持任何类型的 JDBC操作。此类简化了 JDBC 的使用,并有助于避免常见错误。 它执行核心 JDBC 工作流,让应用程序代码提供 SQL 并提取结果。此类执行 SQL 查询或更新,启动 对 ResultSet 进行迭代,捕获 JDBC 异常并进行转换 它们添加到常见异常层次结构中。org.springframework.dao