ZB-039-01Spring基本概念

Spring是什么

  • Java世界的事实标准
    • Spring容器 一个Ioc容器
      • Spring MVC 基于 Spring 和 Servlet的Web 应用框架
        • Spring Boot 集成度和自动化程度更高

没有 Spring 时,我们怎么做

选择一:一个 main 程序打天下

  • 非常轻量,适用于非常简单的场景
    • 易懂
  • 一旦规模上来
    • 难以维护
    • 一场灾难

选择二:拆分并手动管理

  • 拆分成多个模块
  • 优点:
    • 方便测试
    • 方便共同开发
    • 方便维护
  • 缺点:
    • 依赖关系纷繁复杂

Spring出现了,解放了双手

Spring容器的核心概念

  • Bean
    • 容器中的最小工作单元,通常为一个 Java对象
  • BeanFactory/ApplicationContext
    • 容器本身对应的Java对象
  • 依赖注入(DI)
    • 容器负责注入所有的依赖
  • 控制反转(Ioc)
    • 用户将控制权交给容器

Spring容器的实质

001新建项目

pom.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
<?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>spring_di_ioc</groupId>
<artifactId>spring_di_ioc_demo</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<repositories>
<repository>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</repository>
</repositories>
</project>

002添加 spring依赖 搜索 spring maven

找到 spring context 添加它的依赖 到 pom.xml

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>

003新建 src/main/java/com/github/hcsp/SpringMain.java

1
2
3
4
5
public class SpringMain {
public static void main(String[] args) {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:config.xml");
}
}

004什么是config.xml,上古时代的spring配置

搜索 spring xml 得到它的格式文件开始抄

新建 src/main/resources/config.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 definitions here -->

</beans>

005新建 OrderDao 和 OrderService

src/main/java/com/github/hcsp/OrderDao.java

1
2
3
4
5
public class OrderDao {
public void select(){
System.out.println("select");
}
}

src/main/java/com/github/hcsp/OrderService.java

1
2
3
4
5
6
7
8
public class OrderService {
// 依赖另一个模块
private OrderDao orderDao;

public void doSomething(){
orderDao.select();
}
}

006修改config.xml

1
2
3
4
5
6
7
8
9
10
11
<?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 definitions here -->

<bean id="orderDao" class="com.github.hcsp.OrderDao"/>
<bean id="orderService" class="com.github.hcsp.OrderService"/>
</beans>

Bean是什么? 本质就是一个 java对象

那容器是什么呢? 容器就是 BeanFactory

007 修改 SpringMain.java

1
2
3
4
5
6
7
8
9
10
11
public class SpringMain {
public static void main(String[] args) {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:config.xml");

// 此行断点
OrderService orderService = (OrderService) beanFactory.getBean("orderService");
System.out.println(orderService);

orderService.doSomething();
}
}

debug运行 你会发现 orderService 会自动加载进来

而且还是单例的,完整运行会报错,因为 orderService 依赖了 OrderDao

008 通过注解告诉java 那些是依赖

你有三种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class OrderService {
// 三种注解告诉 java 依赖内容
// @Autowired 自动装配
// @Resource
// @Inject
// private OrderDao orderDao;

@Autowired
private OrderDao orderDao;

public void doSomething(){
System.out.println(orderDao);
orderDao.select();
}
}

当你 @Autowired 的时候发生了什么?

如果你学过注解,对于标记了它之后,其实对于这个类来说其实没有变化,只是多个注解

这个注解其实没有任何卵用,其实它是 被人动态的 在运行时扫描来完成对应工作。 如果没人 扫描这个注解 其实没用

009 搜索 spring xml annotation

得知 在 config.xml 里添加一句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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-3.0.xsd">

<!-- 添加这句:意思是 请你看到注解的时候帮我留意以下 -->
<context:annotation-config/>
<!-- bean definitions go here -->

</beans>

010再次运行 SpringMain.java

1
2
3
4
5
debug  你发现运行的时候
根据 config.xml 创建了 两个 bean实例 OrderService 和 OrderDao
而难能可贵的是
OrderService 依赖的 OrderDao
跟上面的 OrderDao 是同一个 (单例)

这就是 spring

DI 依赖注入

容器负责注入所有的依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// OrderService 依赖了 OrderDao
public class OrderService {
@Autowired
private OrderDao orderDao;

public void doSomething(){
System.out.println(orderDao);
orderDao.select();
}
}

// orderDao 一开始是 null
// 虽然声明了依赖但全部都是 null
// 在一个魔法一般的过程之后
// spring容器让他们所有的依赖都变成正确的依赖
// 这就是依赖注入

Ioc 控制反转

用户将控制权交给了容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
以前我们写程序要这样 手工的去创建对象
OrderService orderService = new OrderService();
orderService.select();
// 我们控制了对象的所有装配和运行
// 这是完全由人去控制 装配

// 而控制反转呢?
就是你通过声明 A 依赖了 B ,此时天上掉下来一个阿拉丁神灯。他挥了下魔法棒 biu 的一声,这些东西全部自动装配好了,变成了一个可以用的容器

这就是控制反转的过程,你不需要控制 它们所有的依赖 和装配的进行
你只需要声明 它们 谁依赖了谁。有人会自动的帮你进行装配

这就是 控制反转

这个挥魔法棒的人 叫做—— Spring 容器

代码仓库

https://github.com/slTrust/spring_ioc_demo