Spring入门指南:通俗易懂的Java开发框架教程

从零开始学习Spring框架,搞懂IoC/DI依赖注入、AOP面向切面编程,适合所有Java初学者

前言

“Spring是什么?”

“学Java为什么要学Spring?”

“IoC是什么?DI又是什么?”

“面向切面编程听不懂啊!”

别担心,这篇文章就是为零基础同学准备的。用最通俗的语言,最直白的例子,带你彻底搞懂Spring。


一、Spring是什么?

1.1 一句话理解Spring

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
┌─────────────────────────────────────────────────────────────────┐
│                    Spring是什么?                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Spring = Java开发的"超级工具箱"                               │
│                                                                 │
│   就像:                                                        │
│   ├── 厨房有各种工具(刀、锅、铲子...)                        │
│   └── Spring有各种功能(帮你快速开发)                          │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │   没有Spring:                                          │   │
│   │   你要自己造轮子、自己组装、自己调试                      │   │
│   │                                                         │   │
│   │   有Spring:                                            │   │
│   │   Spring帮你做好一切,你只管用!                        │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

1.2 Spring能做什么?

 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
┌─────────────────────────────────────────────────────────────────┐
│                      Spring功能一览                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │ 1️⃣ Web开发                                              │   │
│   │    做个网站、处理用户请求、返回网页                       │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │ 2️⃣ 数据库操作                                           │   │
│   │    连接数据库、增删改查                                  │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │ 3️⃣ 事务管理                                             │   │
│   │    保证数据一致性,转账不出错                            │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │ 4️⃣ 安全控制                                             │   │
│   │    登录验证、权限控制                                    │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │ 5️⃣ 远程调用                                             │   │
│   │    调用其他系统的接口                                    │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │ 6️⃣ 消息队列                                             │   │
│   │    异步处理、解耦                                        │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   等等...Spring几乎能帮你做所有事情!                           │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

1.3 Spring家族成员

 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
┌─────────────────────────────────────────────────────────────────┐
│                      Spring家族                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│                        ┌──────────┐                            │
│                        │  Spring  │                            │
│                        │  框架    │                            │
│                        └────┬─────┘                            │
│                             │                                   │
│     ┌──────────┬───────────┼───────────┬──────────┐             │
│     │          │           │           │          │             │
│     ▼          ▼           ▼           ▼          ▼             │
│ ┌───────┐ ┌───────┐ ┌──────────┐ ┌───────┐ ┌──────────┐        │
│ │Spring │ │Spring │ │ Spring   │ │Spring │ │ Spring   │        │
│ │ Web   │ │DAO/   │ │ Context  │ │ AOP   │ │ TX       │        │
│ │ (MVC) │ │ ORM   │ │ (容器)   │ │ (切面) │ │ (事务)   │        │
│ └───────┘ └───────┘ └──────────┘ └───────┘ └──────────┘        │
│                                                                 │
│                        Spring生态                                │
│     ┌──────────┬───────────┬───────────┬──────────┐             │
│     │          │           │           │          │             │
│     ▼          ▼           ▼           ▼          ▼             │
│ ┌───────┐ ┌──────────┐ ┌──────────┐ ┌───────┐ ┌──────────┐      │
│ │Spring │ │ Spring   │ │ Spring   │ │Spring │ │ Spring   │      │
│ │Boot   │ │ Cloud    │ │ Security │ │ Data  │ │ Batch   │      │
│ │启动器 │ │ 微服务   │ │ 安全    │ │ 数据   │ │ 批处理  │      │
│ └───────┘ └──────────┘ └──────────┘ └───────┘ └──────────┘      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

二、第一个Spring程序

2.1 创建Maven项目

 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
<!-- pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>spring-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- Spring核心依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.11</version>
        </dependency>

        <!-- 单元测试 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.10.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

2.2 创建User类

 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
package com.example.spring;

/**
 * 用户类 - 我们的第一个Spring Bean
 */
public class User {

    private String name;
    private int age;

    // 构造方法
    public User() {
        System.out.println("User对象被创建了!");
    }

    // Getter和Setter
    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;
    }

    // 业务方法
    public void sayHello() {
        System.out.println("Hello, 我是" + name + ",今年" + age + "岁!");
    }

    @Override
    public String toString() {
        return "User{name='" + name + "', age=" + age + "}";
    }
}

2.3 创建Spring配置文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<!-- resources/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">

    <!--
        bean标签:告诉Spring创建一个对象
        class: 要创建对象的类(全限定类名)
        id: 给这个对象起个名字,方便后面使用
    -->
    <bean id="user" class="com.example.spring.User">
        <!-- property标签:设置属性值 -->
        <property name="name" value="张三"/>
        <property name="age" value="25"/>
    </bean>

</beans>

2.4 创建测试类

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

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

public class SpringTest {

    @Test
    public void testFirstSpring() {
        // 1. 加载Spring配置文件,创建Spring容器
        ApplicationContext context =
            new ClassPathXmlApplicationContext("applicationContext.xml");

        // 2. 从容器中获取对象(根据bean的id)
        User user = (User) context.getBean("user");

        // 3. 调用对象的方法
        user.sayHello();

        // 打印结果:Hello, 我是张三,今年25岁!
    }
}

运行结果:

1
2
User对象被创建了!
Hello, 我是张三,今年25岁!

2.5 图解第一个Spring程序

 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
┌─────────────────────────────────────────────────────────────────┐
│                    Spring程序执行流程                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   1. 创建ApplicationContext(Spring容器)                       │
│      applicationContext.xml                                     │
│           │                                                     │
│           ▼                                                     │
│      ┌────────────────────────────────────────────────────┐    │
│      │              Spring容器(Container)                 │    │
│      │                                                     │    │
│      │   user ──────────────────→ User对象                 │    │
│      │   (id)                    name="张三"               │    │
│      │                          age=25                     │    │
│      │                                                     │    │
│      └────────────────────────────────────────────────────┘    │
│           │                                                     │
│           ▼                                                     │
│      getBean("user")                                           │
│           │                                                     │
│           ▼                                                     │
│      ┌────────────────┐                                        │
│      │   User对象     │                                        │
│      │   sayHello()  │                                        │
│      └────────────────┘                                        │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

三、IoC控制反转

3.1 什么是IoC?

 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
┌─────────────────────────────────────────────────────────────────┐
│                    IoC控制反转 - 通俗解释                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   IoC = Inversion of Control = 控制反转                         │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │   举个例子:汽车和轮子                                   │   │
│   │                                                         │   │
│   │   ❌ 传统方式(主动创建):                              │   │
│   │      class 汽车 {                                       │   │
│   │          轮子 = new 轮子();  // 自己造轮子              │   │
│   │      }                                                  │   │
│   │                                                         │   │
│   │   ✅ Spring方式(IoC):                                 │   │
│   │      class 汽车 {                                       │   │
│   │          轮子轮子;  // 别人给我,我等着                  │   │
│   │      }                                                  │   │
│   │                                                         │   │
│   │      Spring会帮你 new 轮子(),然后"给"你               │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   简单说:                                                       │
│   ├── 以前:自己 new 对象                                       │
│   └── 现在:Spring帮你 new,你等着用就行                         │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

3.2 IoC的原理

 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
┌─────────────────────────────────────────────────────────────────┐
│                    IoC原理图解                                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   没有IoC(主动创建):                                         │
│   ┌────────────┐                                              │
│   │   User类    │                                              │
│   │            │                                              │
│   │ new User() │ ──────→ User对象                             │
│   └────────────┘                                              │
│       │                                                        │
│       │ 自己控制                                               │
│       └────────────────────────────────────────────→ 耦合严重  │
│                                                                 │
│   有IoC(被动接收):                                           │
│   ┌────────────┐                                              │
│   │   User类    │                                              │
│   │            │                                              │
│   │  轮子轮子; │ ←──────────┐                                 │
│   └────────────┘           │                                   │
│       │                    │                                   │
│       │ 不需要new          │ Spring注入                        │
│       │ 只要一个属性       │ 轮子轮子 = new 轮子()             │
│       │                    │                                   │
│       └──────────────────────────────→ 耦合度低               │
│                                                                 │
│   好处:                                                        │
│   ├── 类之间的耦合降低了                                        │
│   ├── 代码更容易测试                                           │
│   ├── 代码更灵活,容易替换组件                                  │
│   └── 便于管理对象                                             │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

四、DI依赖注入

4.1 什么是DI?

 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
┌─────────────────────────────────────────────────────────────────┐
│                    DI依赖注入 - 通俗解释                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   DI = Dependency Injection = 依赖注入                          │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │   依赖:一个类要用到另一个类                             │   │
│   │                                                         │   │
│   │   class 汽车 {                                          │   │
│   │       轮子轮子;  // 汽车依赖轮子                        │   │
│   │   }                                                     │   │
│   │                                                         │   │
│   │   注入:把依赖的对象传进来                               │   │
│   │                                                         │   │
│   │   class 汽车 {                                          │   │
│   │       轮子轮子;                                          │   │
│   │                                                         │   │
│   │       // 构造方法注入                                    │   │
│   │       public 汽车(轮子 w) {                             │   │
│   │           轮子 = w;                                     │   │
│   │       }                                                 │   │
│   │   }                                                     │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   简单说:                                                       │
│   └── 我需要什么,Spring就给我什么                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

4.2 三种注入方式

方式1:构造方法注入

 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
// 1. 创建轮子类
public class Wheel {
    private String brand;

    public Wheel(String brand) {
        this.brand = brand;
    }

    @Override
    public String toString() {
        return "Wheel{brand='" + brand + "'}";
    }
}

// 2. 创建汽车类(使用构造方法注入)
public class Car {
    private String name;
    private Wheel wheel;

    // 构造方法注入
    public Car(String name, Wheel wheel) {
        this.name = name;
        this.wheel = wheel;
    }

    public void drive() {
        System.out.println(name + "使用" + wheel + "在行驶");
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<!-- Spring配置文件 -->
<bean id="wheel" class="com.example.Wheel">
    <constructor-arg value="米其林"/>
</bean>

<bean id="car" class="com.example.Car">
    <!-- constructor-arg:构造方法参数 -->
    <constructor-arg value="宝马"/>
    <constructor-arg ref="wheel"/>
</bean>
1
执行结果:宝马使用Wheel{brand='米其林'}在行驶

方式2: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
// 1. 创建手机类
public class Phone {
    private String brand;

    public void setBrand(String brand) {
        this.brand = brand;
    }

    @Override
    public String toString() {
        return "Phone{brand='" + brand + "'}";
    }
}

// 2. 创建人类(使用Set方法注入)
public class Person {
    private String name;
    private Phone phone;

    // Set方法注入
    public void setName(String name) {
        this.name = name;
    }

    public void setPhone(Phone phone) {
        this.phone = phone;
    }

    public void call() {
        System.out.println(name + "用" + phone + "打电话");
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<!-- Spring配置文件 -->
<bean id="phone" class="com.example.Phone">
    <property name="brand" value="苹果"/>
</bean>

<bean id="person" class="com.example.Person">
    <property name="name" value="李四"/>
    <!-- ref:引用另一个bean -->
    <property name="phone" ref="phone"/>
</bean>
1
执行结果:李四用Phone{brand='苹果'}打电话

方式3:p命名空间注入(简化写法)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<!-- 使用p命名空间简化 -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       ...>

    <bean id="phone" class="com.example.Phone" p:brand="华为"/>

    <bean id="person" class="com.example.Person"
          p:name="王五" p:phone-ref="phone"/>

</beans>

4.3 注入方式对比

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
┌─────────────────────────────────────────────────────────────────┐
                    三种注入方式对比                               
├─────────────────────────────────────────────────────────────────┤
                                                                 
   ┌─────────────┬─────────────┬─────────────┐                   
     方式          写法         推荐程度                      
   ├─────────────┼─────────────┼─────────────┤                   
    构造方法注入  通过constructor-arg ⭐⭐⭐⭐⭐  
                               推荐使用                      
   ├─────────────┼─────────────┼─────────────┤                   
    Setter注入   通过property  ⭐⭐⭐⭐    
                               常用                         
   ├─────────────┼─────────────┼─────────────┤                   
    p命名空间    简化写法     ⭐⭐⭐      
                               简化配置                      
   └─────────────┴─────────────┴─────────────┘                   
                                                                 
   选择建议:                                                     
   ├── 必选依赖用构造方法                                         
   ├── 可选依赖用Setter方法                                       
   └── 简单配置用p命名空间                                        
                                                                 
└─────────────────────────────────────────────────────────────────┘

五、Bean管理

5.1 Bean的作用域

1
2
3
<!-- bean的作用域 -->
<bean id="user" class="com.example.User" scope="作用域">
</bean>
作用域 说明 示例
singleton 单例,整个容器只有一个实例(默认) 每次getBean都返回同一个对象
prototype 原型,每次getBean都创建新实例 每次getBean都返回新对象
request 每次HTTP请求创建一个 Web应用中
session 每次HTTP会话创建一个 Web应用中
 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
┌─────────────────────────────────────────────────────────────────┐
│                    singleton vs prototype                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   singleton(单例):                                            │
│   ┌────────────┐                                                │
│   │ Bean       │                                                │
│   │ ┌────────┐ │                                                │
│   │ │ User   │ │ ← 只有1个对象                                  │
│   │ └────────┘ │                                                │
│   └────────────┘                                                │
│        ▲     ▲     ▲                                           │
│        │     │     │                                           │
│        └──┬──┴─────┘                                           │
│           getBean()                                            │
│                                                                 │
│   prototype(原型):                                            │
│   ┌────────────┐                                                │
│   │ Bean       │                                                │
│   │ ┌────────┐ │ ┌────────┐ │ ┌────────┐                      │
│   │ │ User1 │ │ │ User2 │ │ │ User3 │  ← 每次都创建新对象     │
│   │ └────────┘ │ └────────┘ │ └────────┘                      │
│   └────────────┘                                                │
│        ▲     ▲     ▲                                           │
│        └──┬──┴─────┘                                           │
│           getBean()                                            │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

5.2 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
42
43
44
45
46
47
48
49
┌─────────────────────────────────────────────────────────────────┐
│                    Bean生命周期                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   创建对象                                                       │
│       │                                                         │
│       ▼                                                         │
│   ┌─────────────────┐                                          │
│   │ 1. 调用构造方法  │ ← Bean的构造方法被调用                   │
│   └────────┬────────┘                                          │
│            ▼                                                    │
│   ┌─────────────────┐                                          │
│   │ 2. 设置属性值    │ ← 依赖注入(DI)                         │
│   └────────┬────────┘                                          │
│            ▼                                                    │
│   ┌─────────────────┐                                          │
│   │ 3. BeanNameAware│ ← Spring把Bean的名字告诉你               │
│   └────────┬────────┘                                          │
│            ▼                                                    │
│   ┌─────────────────┐                                          │
│   │ 4. BeanFactoryAware│ ← Spring把BeanFactory给你            │
│   └────────┬────────┘                                          │
│            ▼                                                    │
│   ┌─────────────────┐                                          │
│   │ 5. InitializingBean│ ← 对象初始化                          │
│   │    afterPropertiesSet() │                                 │
│   └────────┬────────┘                                          │
│            ▼                                                    │
│   ┌─────────────────┐                                          │
│   │ 6. init-method  │ ← 自定义初始化方法                       │
│   └────────┬────────┘                                          │
│            ▼                                                    │
│   ════════════════════                                          │
│   ║   Bean可以使用  ║  ← 正常工作状态                          │
│   ════════════════════                                          │
│            │                                                    │
│            ▼                                                    │
│   ┌─────────────────┐                                          │
│   │ 7. DisposableBean│ ← 对象销毁                              │
│   │    destroy()    │                                         │
│   └────────┬────────┘                                          │
│            ▼                                                    │
│   ┌─────────────────┐                                          │
│   │ 8. destroy-method│ ← 自定义销毁方法                        │
│   └────────┬────────┘                                          │
│            ▼                                                    │
│       对象被销毁                                                 │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

六、注解开发

6.1 为什么用注解?

 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
┌─────────────────────────────────────────────────────────────────┐
│                    XML配置 vs 注解                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   XML配置:                                                     │
│   ┌──────────────────────────────────────────────────────┐     │
│   │ <bean id="user" class="com.example.User">            │     │
│   │     <property name="name" value="张三"/>             │     │
│   │     <property name="age" value="25"/>               │     │
│   │ </bean>                                               │     │
│   └──────────────────────────────────────────────────────┘     │
│                                                                 │
│   注解:                                                        │
│   ┌──────────────────────────────────────────────────────┐     │
│   │ @Component                                             │     │
│   │ public class User {                                    │     │
│   │     @Value("张三")                                    │     │
│   │     private String name;                              │     │
│   │     @Value("25")                                      │     │
│   │     private int age;                                  │     │
│   │ }                                                     │     │
│   └──────────────────────────────────────────────────────┘     │
│                                                                 │
│   注解的好处:                                                  │
│   ├── 代码更简洁                                               │
│   ├── 配置更集中(就在类上)                                    │
│   └── 开发效率更高                                            │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

6.2 常用注解

6.2.1 对象创建注解

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

import org.springframework.stereotype.Component;

/**
 * @Component:把这个类交给Spring管理,创建对象
 * value:指定bean的id,默认是类名首字母小写
 */
@Component(value = "user")
public class User {

    private String name;
    private int age;

    public void sayHello() {
        System.out.println("Hello!");
    }
}

// 等价于XML:
// <bean id="user" class="com.example.User"/>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 其他衍生注解(功能一样,只是语义更明确)

@Service      // 用于Service层
public class UserService {}

@Repository   // 用于DAO层
public class UserDao {}

@Controller   // 用于Web层
public class UserController {}

6.2.2 属性注入注解

 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
package com.example;

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

@Component
public class Car {

    private String brand;

    // @Value:注入简单值
    @Value("宝马")
    public void setBrand(String brand) {
        this.brand = brand;
    }
}

@Component
public class Person {

    private String name;
    private Car car;

    @Value("张三")
    public void setName(String name) {
        this.name = name;
    }

    // @Autowired:自动注入
    // Spring会自动从容器中找Car类型的对象,注入进来
    @Autowired
    public void setCar(Car car) {
        this.car = car;
    }

    public void drive() {
        System.out.println(name + "开" + car);
    }
}

6.2.3 完全注解开发

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 创建一个配置类,替代XML配置文件
package com.example;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration  // 这是一个配置类
@ComponentScan("com.example")  // 扫描哪些包
public class SpringConfig {
    // 配置类内容
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 测试类
@Test
public void test() {
    // 使用AnnotationConfigApplicationContext加载配置类
    ApplicationContext context =
        new AnnotationConfigApplicationContext(SpringConfig.class);

    // 获取对象
    Person person = context.getBean("person", Person.class);
    person.drive();
}

七、AOP面向切面编程

7.1 什么是AOP?

 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
┌─────────────────────────────────────────────────────────────────┐
│                    AOP面向切面编程 - 通俗解释                      │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   AOP = Aspect Oriented Programming = 面向切面编程               │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │   场景:记录日志                                         │   │
│   │                                                         │   │
│   │   传统方式(每个方法都写日志):                          │   │
│   │   ─────────────────────                                 │   │
│   │   public void addUser() {                               │   │
│   │       log.info("开始添加用户");                          │   │
│   │       // 业务代码                                       │   │
│   │       log.info("添加用户完成");                          │   │
│   │   }                                                    │   │
│   │                                                         │   │
│   │   public void deleteUser() {                            │   │
│   │       log.info("开始删除用户");                          │   │
│   │       // 业务代码                                       │   │
│   │       log.info("删除用户完成");                          │   │
│   │   }                                                    │   │
│   │                                                         │   │
│   │   问题:日志代码重复!每个方法都要写!                     │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │   AOP方式(切面统一处理):                               │   │
│   │   ─────────────────────                                 │   │
│   │   切面:记录日志                                         │   │
│   │                                                         │   │
│   │   ┌─────────┐                                           │   │
│   │   │ addUser │ ← 切面自动加日志                          │   │
│   │   └─────────┘                                           │   │
│   │         │                                               │   │
│   │         ▼                                               │   │
│   │   ┌─────────┐                                           │   │
│   │   │deleteUser│ ← 切面自动加日志                          │   │
│   │   └─────────┘                                           │   │
│   │                                                         │   │
│   │   好处:日志只写一次,作用于所有方法!                     │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

7.2 AOP术语

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌─────────────────────────────────────────────────────────────────┐
│                    AOP核心术语                                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │   Join point(连接点):可以被增强的方法                 │   │
│   │   → 你的业务方法(addUser, deleteUser...)              │   │
│   │                                                         │   │
│   │   Pointcut(切入点):实际被增强的方法                   │   │
│   │   → 真正被加了日志的方法                                │   │
│   │                                                         │   │
│   │   Advice(通知/增强):你要做的事                        │   │
│   │   → 日志打印、事务开启、性能监控...                      │   │
│   │                                                         │   │
│   │   Aspect(切面):通知 + 切入点                          │   │
│   │   → 把"在哪里增强"和"增强什么"合起来                    │   │
│   │                                                         │   │
│   │   Weaving(织入):把通知应用到目标对象的过程            │   │
│   │   → 编译时/运行时/加载时                                │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

7.3 通知类型

 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
┌─────────────────────────────────────────────────────────────────┐
│                    通知类型(增强时机)                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │  @Before   │ 前置通知    │ 方法执行前                   │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │  @After    │ 后置通知    │ 方法执行后(finally)          │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │  @AfterReturning │ 返回通知 │ 方法正常返回后             │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │  @AfterThrowing  │ 异常通知 │ 方法抛出异常后             │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │  @Around    │ 环绕通知    │ 方法执行前后都执行           │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                     执行顺序图                           │   │
│   │                                                         │   │
│   │        @Before                                          │   │
│   │           │                                             │   │
│   │           ▼                                             │   │
│   │     ┌──────────┐                                       │   │
│   │     │ 业务方法  │                                       │   │
│   │     └──────────┘                                       │   │
│   │           │                                             │   │
│   │     ┌─────┴─────┐                                      │   │
│   │     │ 正常/异常  │                                      │   │
│   │     └─────┬─────┘                                      │   │
│   │           │                                             │   │
│   │    ┌──────┴──────┐                                    │   │
│   │    │             │                                     │   │
│   │    ▼             ▼                                     │   │
│   │ @AfterReturning  @AfterThrowing                        │   │
│   │    │             │                                     │   │
│   │    └──────┬──────┘                                    │   │
│   │           │                                            │   │
│   │           ▼                                            │   │
│   │        @After                                         │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

7.4 AOP小实战

1. 添加依赖

1
2
3
4
5
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.19</version>
</dependency>

2. 创建切面类

 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
package com.example.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * 日志切面:自动给所有业务方法加日志
 */
@Aspect  // 标记这是一个切面类
@Component  // 交给Spring管理
public class LogAspect {

    // 定义切入点:哪些方法要被增强
    // execution(访问修饰符 返回类型 包名.类名.方法名(参数))
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void pointcut() {}

    // 前置通知
    @Before("pointcut()")
    public void before() {
        System.out.println("【日志】方法开始执行...");
    }

    // 后置通知
    @AfterReturning("pointcut()")
    public void afterReturning() {
        System.out.println("【日志】方法正常返回...");
    }

    // 异常通知
    @AfterThrowing("pointcut()")
    public void afterThrowing() {
        System.out.println("【日志】方法抛出异常...");
    }

    // 后置通知(始终执行)
    @After("pointcut()")
    public void after() {
        System.out.println("【日志】方法执行完毕...");
    }

    // 环绕通知
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("【环绕-前】开始...");
        Object result = joinPoint.proceed();  // 执行目标方法
        System.out.println("【环绕-后】结束...");
        return result;
    }
}

3. 业务类

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

import org.springframework.stereotype.Service;

@Service
public class UserService {

    public void addUser(String name) {
        System.out.println("添加用户:" + name);
    }

    public void deleteUser(int id) {
        System.out.println("删除用户:" + id);
    }

    public int findUser() {
        System.out.println("查找用户...");
        return 100;
    }
}

4. 配置类

1
2
3
4
5
6
7
8
9
package com.example;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan("com.example")
@EnableAspectJAutoProxy  // 开启AOP自动代理
public class AppConfig {}

5. 测试

1
2
3
4
5
6
7
8
@Test
public void testAOP() {
    ApplicationContext context =
        new AnnotationConfigApplicationContext(AppConfig.class);

    UserService userService = context.getBean(UserService.class);
    userService.addUser("张三");
}

输出结果:

1
2
3
4
5
6
【日志】方法开始执行...
【环绕-前】开始...
添加用户:张三
【环绕-后】结束...
【日志】方法正常返回...
【日志】方法执行完毕...

八、Spring整合MyBatis

8.1 添加依赖

 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
<dependencies>
    <!-- Spring核心 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>6.0.11</version>
    </dependency>

    <!-- Spring JDBC(数据库操作) -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>6.0.11</version>
    </dependency>

    <!-- MyBatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.14</version>
    </dependency>

    <!-- MyBatis整合Spring -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>3.0.2</version>
    </dependency>

    <!-- 数据库驱动 -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.33</version>
    </dependency>

    <!-- 阿里连接池 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.18</version>
    </dependency>
</dependencies>

8.2 配置类

 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
package com.example.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

@Configuration
public class MyBatisConfig {

    // 数据源
    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis?useSSL=false");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        return dataSource;
    }

    // SqlSessionFactory
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        // 配置mapper文件位置
        factoryBean.setMapperLocations(
            new PathMatchingResourcePatternResolver()
                .getResources("classpath:mapper/*.xml")
        );
        return factoryBean.getObject();
    }
}

8.3 完整项目结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
spring-mybatis-demo/
├── src/main/java/com/example/
│   ├── config/
│   │   ├── AppConfig.java
│   │   └── MyBatisConfig.java
│   ├── entity/
│   │   └── User.java
│   ├── mapper/
│   │   ├── UserMapper.java
│   │   └── UserMapper.xml
│   ├── service/
│   │   ├── UserService.java
│   │   └── impl/
│   │       └── UserServiceImpl.java
│   └── SpringApplication.java
├── src/main/resources/
│   ├── applicationContext.xml
│   └── mapper/
│       └── UserMapper.xml
└── pom.xml

九、总结

9.1 Spring核心知识点

 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核心知识点                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   1️⃣ Spring是什么?                                            │
│      → Java开发框架,提供IoC和AOP等核心功能                      │
│                                                                 │
│   2️⃣ IoC控制反转                                              │
│      → 对象由Spring创建,程序被动接收                             │
│      → 降低耦合                                                 │
│                                                                 │
│   3️⃣ DI依赖注入                                                │
│      → Spring把依赖的对象注入进来                                 │
│      → 构造方法注入 / Setter注入                                 │
│                                                                 │
│   4️⃣ Bean管理                                                  │
│      → 作用域:singleton / prototype                            │
│      → 生命周期:创建 → 初始化 → 使用 → 销毁                    │
│                                                                 │
│   5️⃣ 注解开发                                                  │
│      → @Component, @Service, @Repository, @Controller           │
│      → @Autowired, @Value                                     │
│                                                                 │
│   6️⃣ AOP面向切面编程                                           │
│      → 通知类型:@Before/@After/@Around...                    │
│      → 把横切关注点与业务分离                                    │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

9.2 学习路线

 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
┌─────────────────────────────────────────────────────────────────┐
│                    Spring学习路线                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   第一阶段:Spring Core                                        │
│   ├── IoC/DI                                                  │
│   ├── Bean管理                                                 │
│   └── 注解开发                                                 │
│                                                                 │
│   第二阶段:Spring AOP                                         │
│   ├── AOP概念                                                 │
│   ├── 通知类型                                                 │
│   └── 切面编程                                                 │
│                                                                 │
│   第三阶段:Spring整合                                          │
│   ├── 整合MyBatis                                             │
│   ├── 整合JUnit                                                │
│   └── 事务管理                                                 │
│                                                                 │
│   第四阶段:Spring MVC                                         │
│   ├── Web开发                                                 │
│   └── 控制器                                                  │
│                                                                 │
│   第五阶段:Spring Boot                                       │
│   └── 快速开发框架(后面单独讲)                                 │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

希望这篇文章能帮你入门Spring!如果有问题,欢迎在评论区交流。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计