Spring IOC 与 DI
# Spring IOC 与 DI
# 1. IOC 控制反转 [Inversion Of Control]
# 1. 控制反转解决色问题
原来: 我们在获取对象时,都是采用 new 的方式。是主动的。
现在:我们获取对象时,同时跟工厂要,有工厂为我们查找或者创建对象。是被动的。
这种被动接收的方式获取对象的思想就是控制反转,它是 spring 框架的核心之一。
我的理解:
1.之前有自己new创建对象 [主动]
2.先在由媒人帮我找对象 [被动]
# 2. IOC的概述 解耦合
控制反转: 把创建的对象权利交给框架(工厂),是框架的重要特性,并非面向对象编程的专用术语,它包含**依赖注入(DI)**和依赖查询
明确 ioc 的作用:削减计算机程序的耦合(解除我们代码中的依赖关系)。降低程序间的耦合(依赖关系)
# 2. IOC入门应用
# 1. 依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
</dependencies>
1
2
3
4
5
6
7
2
3
4
5
6
7
# 2. 配置文件
- bean.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--1. 把对象的创建交给Spring来管理-->
<!--accountService-->
<bean id="accountService" class="com.chggx.service.impl.AccountServiceImpl"/>
<!--accountDao-->
<bean id="accountDao" class="com.chggx.dao.impl.AccountDaoImpl"/>
</beans>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 3. ApplicationContext操作
ApplicationContext接口
ClassPathXmlApplicationContext
- 可以加载类路径下的配置文件,要求配置文件必须在类路径下,不在的话,加载不了.[推荐]
FileSystemXmlApplicationContext
- 它可以加载磁盘任意路径下的配置文件(必须有访问权限)
AnnotationConfigApplicationContext
- 它是用于读取注解创建容器的.
/**
* 获取spring的Ioc核心容器,并根据id获取对象
* ApplicationContext:
* 1. ClassPathXmlApplicationContext: 可以加载类路径下的配置文件,要求配置文件必须在类路径下,不在的话,加载不了.[推荐]
* 2. FileSystemXmlApplicationContext: 它可以加载磁盘任意路径下的配置文件(必须有访问权限)
* 3. AnnotationConfigApplicationContext: 它是用于读取注解创建容器的.
*/
public static void main(String[] args) {
// 1. 获取核心容器兑现
// ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
ApplicationContext ac = new FileSystemXmlApplicationContext("D:\\java-code\\kuangjia\\spring\\spring\\spring_03_ioc\\src\\main\\resources\\bean.xml");
// 2. 根据id获取bean对象
AccountService accountService = (AccountService) ac.getBean("accountService");
AccountDao accountDao = ac.getBean("accountDao", AccountDao.class);
System.out.println(accountService);
System.out.println(accountDao);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 3. IOC核心容器的两个接口
# 1. ApplicationContext 单例对象使用
ApplicationContext: [单例对象使用 如: service,dao]
它在构建核心容器时,创建对象策略是采用立即加载的方式,也就是说,只要一读取完配置文件(bean.xml)马上就创建配置文件中配置的对象(通过反射实现)
如: 以下代码 [立即加载]
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); 读取配置文件时候,通过反射就创建对象了
1
2
3
4
2
3
4
# 2. BeanFactory 多例对象使用
BeanFactory: [多例对象使用]
它在构建核心容器时,创建对象的策略采用延迟加载的方式,也就是说,什么时候根据id(bean容器对象的唯一标识)获取对象了,什么时候才真正的创建对象.
如: 以下代码 [延迟加载]
BeanFactory factory = new XmlBeanFactory(resource); 读取配置文件
AccountService accountService = (AccountService) factory.getBean("accountService"); 根据ID调用对象时候,才创建对象
1
2
3
4
5
2
3
4
5
# 3. 使用
/**
* 1. 获取spring的Ioc核心容器,并根据id获取对象
* ApplicationContext:
* 1). ClassPathXmlApplicationContext: 可以加载类路径下的配置文件,要求配置文件必须在类路径下,不在的话,加载不了.[推荐]
* 2). FileSystemXmlApplicationContext: 它可以加载磁盘任意路径下的配置文件(必须有访问权限)
* 3). AnnotationConfigApplicationContext: 它是用于读取注解创建容器的.
* 2. 核心容器的两个接口引发出的问题:
* ApplicationContext: [单例对象使用 如: service,dao]
* 它在构建核心容器时,创建对象策略是采用立即加载的方式,也就是说,只要一读取完配置文件(bean.xml)马上就创建配置文件中配置的对象(通过反射实现)
* 如: 以下代码 [立即加载]
* ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); 读取配置文件时候,通过反射就创建对象了
* BeanFactory: [多例对象使用]
* 它在构建核心容器时,创建对象的策略采用延迟加载的方式,也就是说,什么时候根据id(bean容器对象的唯一标识)获取对象了,什么时候才真正的创建对象.
* 如: 以下代码 [延迟加载]
* BeanFactory factory = new XmlBeanFactory(resource); 读取配置文件
* AccountService accountService = (AccountService) factory.getBean("accountService"); 根据ID调用对象时候,才创建对象
*/
public static void main(String[] args) {
// ============= ApplicationContext [立即加载] =============
// // 1. 获取核心容器对象 [推荐 ClassPathXmlApplicationContext方式创建]
// ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//// ApplicationContext ac = new FileSystemXmlApplicationContext("D:\\java-code\\kuangjia\\spring\\spring\\spring_03_ioc\\src\\main\\resources\\bean.xml");
// // 2. 根据id获取bean对象 [service,dao都只创建一次,单例模式]
// AccountService accountService = (AccountService) ac.getBean("accountService");
// AccountDao accountDao = ac.getBean("accountDao", AccountDao.class);
//
// System.out.println(accountService);
// System.out.println(accountDao);
// ============= BeanFactory [延迟加载] =============
// 1. 加载配置文件"bean.xml"
ClassPathResource resource = new ClassPathResource("bean.xml");
// 2. 读取配置文件
BeanFactory factory = new XmlBeanFactory(resource);
// 3. 根据id创建Bean对象
AccountService accountService = (AccountService) factory.getBean("accountService");
System.out.println(accountService);
}
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
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
# 4. spring对bean的管理细节
# 1. 创建Bean的三种方式
# 1. 构造函数创建对象
第一种方式: 在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时,采用的就是默认构造函数创建bean对象,此时如果类中没有默认的构造函数,则对象无法创建
1
- 配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
spring对bean的管理细节:
1. 创建Bean的三种方式
2. bean对象的作用范围
3. bean对象的生命周期
-->
<!--创建Bean的三种方式-->
<!--
第一种方式: 使用默认的构造函数创建
在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时,采用的就是默认构造函数创建bean对象,此时如果类中没有默认的构造函数,则对象无法创建
-->
<bean id="accountService" class="com.chggx.service.impl.AccountServiceImpl"/>
</beans>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- 类 [构造函数]
public class AccountServiceImpl implements AccountService {
/**
* 创建bean的方式: 构造函数
*/
public AccountServiceImpl() {
System.out.println("AccountServiceImpl 对象创建了...");
}
/**
* 模拟保存账户
*/
@Override
public void saveAccount(){
System.out.println("service saveAccount() ......");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 2. 普通工厂的方法创建对象
第二种方式: 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
1
- 工厂类
package com.chggx.factory;
import com.chggx.service.AccountService;
import com.chggx.service.impl.AccountServiceImpl;
/**
* @Description: <h1> 模拟一个工厂类 </h1>
* 该类可能存在于jar包中的,我们无法通过修改源码的方式来提供默认构造函数
*/
public class InstanceFactory {
/**
* 构造函数
* @return AccountService
*/
public AccountService getAccountService(){
return new AccountServiceImpl();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--1. 把对象的创建交给Spring来管理-->
<!--
spring对bean的管理细节:
1. 创建Bean的三种方式
2. bean对象的作用范围
3. bean对象的生命周期
-->
<!--创建Bean的三种方式-->
<!--
第一种方式: 使用默认的构造函数创建
在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时,
采用的就是默认构造函数创建bean对象,此时如果类中没有默认的构造函数,则对象无法创建
<bean id="accountService" class="com.chggx.service.impl.AccountServiceImpl"/>
-->
<!--第二种方式: 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)-->
<bean id="instanceFactory" class="com.chggx.factory.InstanceFactory"/>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"/>
</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
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
# 3. 工厂中的静态方法创建对象
第三种方式: 使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
1
- 工厂类
package com.chggx.factory;
import com.chggx.service.AccountService;
import com.chggx.service.impl.AccountServiceImpl;
/**
* @Description: <h1> 模拟一个工厂类 </h1>
* 该类可能存在于jar包中的,我们无法通过修改源码的方式来提供默认构造函数
*/
public class StaticFactory {
/**
* 构造函数
* @return AccountService
*/
public static AccountService getAccountService(){
return new AccountServiceImpl();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--1. 把对象的创建交给Spring来管理-->
<!--
spring对bean的管理细节:
1. 创建Bean的三种方式
2. bean对象的作用范围
3. bean对象的生命周期
-->
<!--创建Bean的三种方式-->
<!--
第一种方式: 使用默认的构造函数创建
在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时,
采用的就是默认构造函数创建bean对象,此时如果类中没有默认的构造函数,则对象无法创建
<bean id="accountService" class="com.chggx.service.impl.AccountServiceImpl"/>
-->
<!--第二种方式: 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)-->
<!--
<bean id="instanceFactory" class="com.chggx.factory.InstanceFactory"/>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"/>
-->
<!--第三种方式: 使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)-->
<bean id="accountService" class="com.chggx.factory.StaticFactory" factory-method="getAccountService"/>
</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
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
# 2. bean对象的作用范围 scope
bean的scope属性:
作用: 用于指定bean的作用范围
取值: [常用单例的和多例的]
1
2
2
类型 | 描述 |
---|---|
singleton | 单例的(默认值) |
prototype | 多例的 |
request | 作用于web应用的请求范围 |
session | 作用于web应用的会话范围 |
global-session | 作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session |
- 应用
<bean id="accountService" class="com.chggx.service.impl.AccountServiceImpl" scope="prototype"/>
1
# 3. bean对象的生命周期
- 单例对象的生命周期和容器相同
# 1. 单例 ==立即加载==
- 配置文件
<!--bean对象生命周期-->
<!--
单例对象: [立即加载]
出生: 当容器创建时对象创建
活着: 只要容器还在,对象一直存在
死亡: 容器销毁,对象消亡
总结: 单例对象的生命周期和容器相同
-->
<!--init-method="init": 初始化 destroy-method="destroy": 销毁-->
<bean id="accountService" class="com.chggx.service.impl.AccountServiceImpl"
scope="singleton" init-method="init" destroy-method="destroy" />
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- 业务方法
public class AccountServiceImpl implements AccountService {
/**
* 创建bean的方式: 构造函数
*/
public AccountServiceImpl() {
System.out.println("AccountServiceImpl 对象创建了...");
}
/**
* 模拟保存账户
*/
@Override
public void saveAccount(){
System.out.println("service saveAccount() ......");
}
/**
* 初始化
*/
public void init(){
System.out.println("object init...");
}
/**
* 结束销毁
*/
public void destroy(){
System.out.println("object destroy...");
}
}
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
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
- 调用方法
public class AccountController {
public static void main(String[] args) {
// ============= ApplicationContext [立即加载] =============
// 1. 获取核心容器对象 [推荐 ClassPathXmlApplicationContext方式创建]
// 多态
// ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
// 2. 根据id获取bean对象 [service,dao都只创建一次,单例模式]
AccountService accountService = (AccountService) ac.getBean("accountService");
// 3. 调用方法
accountService.saveAccount();
// 手动关闭容器destroy
ac.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 执行结果
AccountServiceImpl 对象创建了...
object init...
service saveAccount() ......
object destroy...
1
2
3
4
2
3
4
# 2. 多例 ==懒加载==
- 配置文件
<!--bean对象生命周期-->
<!--
单例对象: [立即加载]
出生: 当容器创建时对象创建
活着: 只要容器还在,对象一直存在
死亡: 容器销毁,对象消亡
总结: 单例对象的生命周期和容器相同
多例对象: [懒加载]
出生: 当我们使用对象时spring框架为我们创建
活着: 对象只要是在使用过程中就一直存在
死亡: 当对象长时间不用,且没有别的对象引用时,有Java的垃圾回收器回收
-->
<!--init-method="init": 初始化 destroy-method="destroy": 销毁-->
<!--单例: 立即加载-->
<!-- <bean id="accountService" class="com.chggx.service.impl.AccountServiceImpl"
scope="singleton" init-method="init" destroy-method="destroy" />-->
<!--多例: 懒加载-->
<bean id="accountService" class="com.chggx.service.impl.AccountServiceImpl"
scope="prototype" init-method="init" destroy-method="destroy"/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 结果
AccountServiceImpl 对象创建了...
object init...
service saveAccount() ......
1
2
3
2
3
# 5. 依赖注入 DI
# 1. 概述
依赖注入: Dependency Injection
IOC作用: 降低程序间的耦合(依赖关系)
依赖关系管理: 以后都交给spring维护
* 在当前类需要用到其类的对象,有spring为我们提供,我们只需要在配置文件中说明
1
- 依赖关系的维护: 称之为 依赖注入.
# 2. 注入方式
# 1. 构造方法
- 使用标签: constructor-arg
- 标签出现位置: bean标签的内部
- 标签中的属性
属性 | 描述 |
---|---|
type | 用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数类型 |
index | 用于指定要注入的数据给构造函数中指定指定索引位置的参数赋值,所以得位置从0开始 |
name | 用于指定给构造函数中名称的参数赋值 [推荐] |
value | 用于基本类型和String类型的数据 |
ref | 用于指定其他的bean类型数据.它指的就是spring的Ioc核心容器中出现过的bean对象 |
- 优势
- 在获取bean对象时,注入数据是必须操作.否则对象无法创建成功
- 弊端
- 改变了bean对象的实例化方式,使我们创建对象时,如果用不到这些数据,也必须提供
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--1. 把对象的创建交给Spring来管理-->
<!--
spring中的依赖注入 DI:
1. 依赖注入: Dependency Injection
2. IOC作用: 降低程序间的耦合(依赖关系)
3. 依赖关系管理: 以后都交给spring维护
* 在当前类需要用到其类的对象,有spring为我们提供,我们只需要在配置文件中说明
4. 依赖关系的维护: 称之为 依赖注入.
5. 依赖注入:
5.1 能注入的数据: [3类]
基本类型
其他bean类型(在配置文件中或者注解配置过得bean)
复杂类型/集合类型
5.2 注入的方式: [3种]
第一种: 使用构造方法
第二种: 使用set方法提供
第三种: 使用注解提供
-->
<!--
构造函数注入
使用标签: constructor-arg
标签出现位置: bean标签的内部
标签中的属性
type: 用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数类型
index: 用于指定要注入的数据给构造函数中指定指定索引位置的参数赋值,所以得位置从0开始
name: 用于指定给构造函数中名称的参数赋值 [推荐]
============= 以上三个用于指定给构造函数中哪个参数赋值 ===========
value: 用于基本类型和String类型的数据
ref: 用于指定其他的bean类型数据.它指的就是spring的Ioc核心容器中出现过的bean对象
优势:
在获取bean对象时,注入数据是必须操作.否则对象无法创建成功
弊端:
改变了bean对象的实例化方式,使我们创建对象时,如果用不到这些数据,也必须提供
-->
<bean id="accountService" class="com.chggx.service.impl.AccountServiceImpl">
<constructor-arg name="name" value="构造函数注入"/>
<!--String可自动转换为Integer-->
<constructor-arg name="age" value="18"/>
<!--Date: 需要配置日期对象-->
<constructor-arg name="birthday" ref="now"/>
</bean>
<!--配置一个日期对象-->
<bean id="now" class="java.util.Date"/>
</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
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
- 构造方法类
public class AccountServiceImpl implements AccountService {
/**
* 如果是经常变化的数据,并不适用与注入方式
*/
private String name;
private Integer age;
private Date birthday;
/**
* 依赖注入: 使用构造方法
*/
public AccountServiceImpl(String name, Integer age, Date birthday) {
this.name = name;
this.age = age;
this.birthday = birthday;
}
/**
* 模拟保存账户
*/
@Override
public void saveAccount() {
System.out.println("service saveAccount() ......" + name + "," + age + "," + birthday);
}
}
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
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
- 应用
public class AccountController {
public static void main(String[] args) {
// ============= ApplicationContext [立即加载] =============
// 1. 获取核心容器对象 [推荐 ClassPathXmlApplicationContext方式创建]
// 多态
// ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
// ============= 依赖注入方式: 构造方法 ==============
// 2. 根据id获取bean对象 [service,dao都只创建一次,单例模式]
AccountService accountService = (AccountService) ac.getBean("accountService");
// 3. 调用方法
accountService.saveAccount();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 2. set方法 [推荐: 可以使用默认的构造方法]
- 使用标签: property
- 标签出现位置: bean标签的内部
- 标签中的属性
属性 | 描述 |
---|---|
name | 用于指定给构造函数中名称的参数赋值 |
value | 用于基本类型和String类型的数据 |
ref | 用于指定其他的bean类型数据.它指的就是spring的Ioc核心容器中出现过的bean对象 |
优势
- 创建对象时没有明确的限制,可以直接使用默认的构造函数
弊端
- 如果有某个成员那必须有值,则获取对象是有可能set方法没有执行
- 配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--1. 把对象的创建交给Spring来管理-->
<!--
spring中的依赖注入 DI:
1. 依赖注入: Dependency Injection
2. IOC作用: 降低程序间的耦合(依赖关系)
3. 依赖关系管理: 以后都交给spring维护
* 在当前类需要用到其类的对象,有spring为我们提供,我们只需要在配置文件中说明
4. 依赖关系的维护: 称之为 依赖注入.
5. 依赖注入:
5.1 能注入的数据: [3类]
基本类型
其他bean类型(在配置文件中或者注解配置过得bean)
复杂类型/集合类型
5.2 注入的方式: [3种]
第一种: 使用构造方法
第二种: 使用set方法提供
第三种: 使用注解提供
-->
<!--配置一个日期对象-->
<bean id="now" class="java.util.Date"/>
<!--
set方法注入 [推荐]
使用标签: property
标签出现位置: bean标签的内部
标签中的属性
name: 用于指定注入是所调用的set方法名称
set方法名称: setName ==== name
value: 用于基本类型和String类型的数据
ref: 用于指定其他的bean类型数据.它指的就是spring的Ioc核心容器中出现过的bean对象
优势:
创建对象时没有明确的限制,可以直接使用默认的构造函数
弊端:
如果有某个成员那必须有值,则获取对象是有可能set方法没有执行
-->
<bean id="accountService2" class="com.chggx.service.impl.AccountService2Impl">
<property name="name" value="set方法注入"/>
<property name="age" value="21"/>
<property name="birthday" ref="now"/>
</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
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
- set方法类
public class AccountService2Impl implements AccountService {
/**
* 如果是经常变化的数据,并不适用与注入方式
*/
private String name;
private Integer age;
private Date birthday;
/**
* 依赖注入: 使用set方法
*/
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
/**
* 模拟保存账户
*/
@Override
public void saveAccount() {
System.out.println("service saveAccount() ......" + name + "," + age + "," + birthday);
}
}
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
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
- 应用
public class AccountController {
public static void main(String[] args) {
// ============= ApplicationContext [立即加载] =============
// 1. 获取核心容器对象 [推荐 ClassPathXmlApplicationContext方式创建]
// 多态
// ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
// ============= 依赖注入方式: set方法 ==============
// 2. 根据id获取bean对象 [service,dao都只创建一次,单例模式]
AccountService accountService2 = (AccountService) ac.getBean("accountService2");
// 3. 调用方法
accountService2.saveAccount();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 3. 注解方式
- 详细参考 ioc 注解
# 3. 能注入的数据
# 1. 基本类型
- 参考 注入方式 中的使用
# 2. 其他bean类型(在配置文件中或者注解配置过得bean)
- 参考 注入方式 中的使用
# 3. 复杂类型/集合类型
- 结论: 结构相同,标签可以互换
- 配置文件
<!--复杂类型的注入/集合类型的注入-->
<!--
用于list结构集合注入的标签: list,array,set
用于Map结构集合注入的标签: map,prop
* 结论: 结构相同,标签可以互换
-->
<bean name="accountService3" class="com.chggx.service.impl.AccountService3Impl">
<!--1. 数组-->
<property name="myStr">
<array>
<value>array1</value>
<value>array2</value>
<value>array3</value>
</array>
</property>
<!--2. list集合-->
<property name="myList">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</list>
</property>
<!--3. set集合-->
<property name="mySet">
<set>
<value>set1</value>
<value>set2</value>
<value>set3</value>
</set>
</property>
<!--4. map集合-->
<property name="myMap">
<map>
<entry key="map1" value="aaa"/>
<entry key="map2" value="bbb"/>
</map>
</property>
<!--5. map集合-->
<property name="myProps">
<props>
<prop key="prop1">111</prop>
<prop key="prop2">222</prop>
</props>
</property>
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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
- 类
public class AccountService3Impl implements AccountService {
/**
* 能注入的数据类型: 复杂类型/集合类型
*/
private String[] myStr;
private List<String> myList;
private Set<String> mySet;
private Map<String,String> myMap;
private Properties myProps;
/**
* 依赖注入: 使用set方法
*/
public void setMyStr(String[] myStr) {
this.myStr = myStr;
}
public void setMyList(List<String> myList) {
this.myList = myList;
}
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public void setMyProps(Properties myProps) {
this.myProps = myProps;
}
/**
* 模拟保存账户
*/
@Override
public void saveAccount() {
System.out.println(Arrays.toString(myStr));
System.out.println(myList);
System.out.println(mySet);
System.out.println(myMap);
System.out.println(myProps);
}
}
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
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
- 应用
public class AccountController {
public static void main(String[] args) {
// ============= ApplicationContext [立即加载] =============
// 1. 获取核心容器对象 [推荐 ClassPathXmlApplicationContext方式创建]
// 多态
// ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
// ============= 能注入的数据类型: 复杂类型/集合类型 set方法注入 ==============
// 2. 根据id获取bean对象 [service,dao都只创建一次,单例模式]
AccountService accountService3 = (AccountService) ac.getBean("accountService3");
// 3. 调用方法
accountService3.saveAccount();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 6. ioc注解
# 1. 用于创建对象的注解
- 它们的作用就和XML配置文件中编写一个
标签实现的功能是一样的
注解 | 作用 | 属性 |
---|---|---|
@Component | 用于把当前类作为对象,存入spring容器中 | value:用于指定bean的id.当我们不写时,它默认是当前类名,且首字母改小写 |
@Controller | 一般用于表现层 | 属性/作用同上 |
@Service | 一般用于业务层 | 属性/作用同上 |
@Repository | 一般用于持久层 | 属性/作用同上 |
# 1. @Component
/**
* @Description: <h1> 账户业务层实现类 </h1>
* xml配置
* <bean id="accountService" class="com.chggx.service.impl.AccountServiceImpl"/>
* 属性: id,class,scope,init-method,destroy-method,property,name,value|ref
* 注解
* 1. 用于创建对象的注解:
* 它们的作用就和XML配置文件中编写一个<bean></bean>标签实现的功能是一样的
* @Component:
* 作用: 用于把当前类作为对象,存入spring容器中
* 属性:
* value: 用于指定bean的id.当我们不写时,它默认是当前类名,且首字母改小写
衍生注解: 下面三个 与 @Component 的作用和属性一模一样,是spring框架为我们提供明确的三层使用的注解,使用我们的三层对象更加清晰
* @Controller: 一般用于表现层
* @Service: 一般用于业务层
* @Repository: 一般用于持久层
* 2. 用于注入数据的
* 它们的作用就和XML配置文件中编写一个bean标签写一个<property></property>的标签是一样的
* 3. 用于改变作用范围的
* 它们的作用就和XML配置文件中编写一个bean标签使用scope属性实现的功能是一样的
* 4. 和生命周期有关的
* 它们的作用就和XML配置文件中编写一个bean标签使用init-method,destroy-method的作用是一样的
*/
@Component(value="accountServiceImpl")
public class AccountServiceImpl implements AccountService {
/**
* 普通方式 (耦合度高)
*/
private AccountDao accountDao;
public AccountServiceImpl() {
System.out.println("AccountServiceImpl 对象创建了...");
}
/**
* 模拟保存账户
*/
@Override
public void saveAccount() {
accountDao.saveAccount();
}
}
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
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
- 配置文件 (开启包扫描,使用注解)
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--把对象的创建交给Spring来管理-->
<!--1. xml方式实现-->
<!--accountService-->
<!--<bean id="accountService" class="com.chggx.service.impl.AccountServiceImpl"/>-->
<!--accountDao-->
<!--<bean id="accountDao" class="com.chggx.dao.impl.AccountDaoImpl"/>-->
<!--2. 注解方式实现-->
<!--
告知spring在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中,而是一个名称为content名称空间和约束中
-->
<!--包扫描-->
<context:component-scan base-package="com.chggx"/>
</beans>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- 应用
public class AccountController {
public static void main(String[] args) {
// ============= ApplicationContext [立即加载] =============
// 1. 获取核心容器对象 [推荐 ClassPathXmlApplicationContext方式创建]
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
// 2. 根据id获取bean对象 [service,dao都只创建一次,单例模式]
AccountService accountService = (AccountService) ac.getBean("accountServiceImpl");
System.out.println(accountService);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 2. 衍生注解使用
- dao
@Repository(value = "accountDao")
public class AccountDaoImpl implements AccountDao {
/**
* 模拟保存账户
*/
@Override
public void saveAccount() {
System.out.println("save success...");
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- service
@Service(value="accountService")
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
// public AccountServiceImpl() {
// System.out.println("AccountServiceImpl 对象创建了...");
// }
/**
* 模拟保存账户
*/
@Override
public void saveAccount() {
accountDao.saveAccount();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 应用
public class AccountController {
public static void main(String[] args) {
// ============= ApplicationContext [立即加载] =============
// 1. 获取核心容器对象 [推荐 ClassPathXmlApplicationContext方式创建]
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
// 2. 根据id获取bean对象 [service,dao都只创建一次,单例模式]
AccountService accountService = (AccountService) ac.getBean("accountService");
System.out.println(accountService);
AccountDao accountDao = ac.getBean("accountDao", AccountDao.class);
System.out.println(accountDao);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 2. 用于注入数据的
- 它们的作用就和XML配置文件中编写一个bean标签写一个
的标签是一样的
注解 | 作用 | 类型 |
---|---|---|
@Autowired | 注入数据(按照类型) | 注入其他bean类型 |
@Qualifier | 注入数据(配置和@Autowired解决多类型注入问题 | 注入其他bean类型 |
@Resource | 注入数据(取代上面两个注解,根据bean的id注入) | 注入其他bean类型 |
@Value | 注入基本数据类型和String类型 | 基本类型和String类型 |
# 1. @Autowired ==自动按照类型注入==
作用: 自动按照类型注入.
1. 容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
2. 如果ioc容器中没有任何bean的类型和要注入变量类型匹配,则报错(不能注入)
3. 如果ioc容器中有多个类型匹配时,报错,引出新的注解: @Qualifier
出现位置: 可以是变量上,也可以是方法上
细节: 使用注解注入时,set方法不是必须的
1
2
3
4
5
6
2
3
4
5
6
- 问题
如果ioc容器中有多个类型匹配时 使用@Autowired怎样操作?
# 2. @Qualifier ==解决@Autowired多类型匹配==
作用: 在自动按照类中注入的基础之上,在按照名称注入.
它在给类成员注入时不能单独使用.但是在给方法参数注入时可以
属性:
value: 用于指定注入bean的id
1
2
3
4
2
3
4
- dao
@Repository(value = "accountDao2")
public class AccountDao2Impl implements AccountDao {
/**
* 模拟保存账户
*/
@Override
public void saveAccount() {
System.out.println("save success 222...");
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
@Repository(value = "accountDao1")
public class AccountDaoImpl implements AccountDao {
/**
* 模拟保存账户
*/
@Override
public void saveAccount() {
System.out.println("save success 111...");
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- service调用
@Service(value="accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
@Qualifier(value = "accountDao1")
private AccountDao accountDao;
/**
* 模拟保存账户
*/
@Override
public void saveAccount() {
accountDao.saveAccount();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 3. @Resource ==替换上边两个==
作用: 直接按照bean的id注入.可以单独使用
属性:
name: 用于指定bean的id
1
2
3
2
3
@Service(value="accountService")
public class AccountServiceImpl implements AccountService {
// @Autowired
// @Qualifier(value = "accountDao1")
@Resource(name = "accountDao1")
private AccountDao accountDao;
// public AccountServiceImpl() {
// System.out.println("AccountServiceImpl 对象创建了...");
// }
/**
* 模拟保存账户
*/
@Override
public void saveAccount() {
accountDao.saveAccount();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 4. @Value ==注入基本类型和String类型==
作用: 用于注入基本类型和String类型的数据
属性:
value: 用于指定数据的值,可以使用spring中SpEL(也就是spring的el表达式)
SpEL写法: ${表达式}
1
2
3
4
2
3
4
# 5. 总结
@Autowired,@Qualifier,@Resource: 只能注入其他bean类型,而基本类型和String类型无法使用上述注解实现,另外,集合类型的注入只能通过xml来实现
@Value 解决了 ==基本类型和String类型== 的注入
# 3. 用于改变作用范围的
- 它们的作用就和XML配置文件中编写一个bean标签使用scope属性实现的功能是一样的
@Scope
作用: 用于指定bean的作用范围
属性:
value: 指定范围的取值,常用取值: singleton(默认),property
1
2
3
2
3
@Scope(value = "singleton") // 方法时
1
# 4. 和生命周期有关的
- 它们的作用就和XML配置文件中编写一个bean标签使用init-method,destroy-method的作用是一样的
# 1. @PreDestroy ==销毁==
- 作用: 用于指定销毁方法
# 2. @PostConstruct ==初始胡==
- 用于指定初始化方法
# 3. 应用
- 方法
/**
* @Description: <h1> 账户业务层实现类 </h1>
* xml配置
* <bean id="accountService" class="com.chggx.service.impl.AccountServiceImpl"/>
* 属性: id,class,scope,init-method,destroy-method,property,name,value|ref
* 注解
* 1. 用于创建对象的注解:
* 它们的作用就和XML配置文件中编写一个<bean></bean>标签实现的功能是一样的
* @Component:
* 作用: 用于把当前类作为对象,存入spring容器中
* 属性:
* value: 用于指定bean的id.当我们不写时,它默认是当前类名,且首字母改小写
* 衍生注解: 下面三个 与 @Component 的作用和属性一模一样,是spring框架为我们提供明确的三层使用的注解,使用我们的三层对象更加清晰
* @Controller: 一般用于表现层
* @Service: 一般用于业务层
* @Repository: 一般用于持久层
*
* 2. 用于注入数据的
* 它们的作用就和XML配置文件中编写一个bean标签写一个<property></property>的标签是一样的
* @Autowired
* 作用: 自动按照类型注入.
* 1. 容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
* 2. 如果ioc容器中没有任何bean的类型和要注入变量类型匹配,则报错(不能注入)
* 3. 如果ioc容器中有多个类型匹配时,报错,引出新的注解 @Qualifier
* 出现位置: 可以是变量上,也可以是方法上
* 细节: 使用注解注入时,set方法不是必须的
* @Qualifier:
* 作用: 在自动按照类中注入的基础之上,在按照名称注入.
* 它在给类成员注入时不能单独使用.但是在给方法参数注入时可以
* 属性:
* value: 用于指定注入bean的id
* @Resource:
* 作用: 直接按照bean的id注入.可以单独使用
* 属性:
* name: 用于指定bean的id
* 总结: 以上三个注解只能注入其他bean类型,而基本类型和String类型无法使用上述注解实现.
* 另外,集合类型的注入只能通过xml来实现
* @Value:
* 作用: 用于注入基本类型和String类型的数据
* 属性:
* value: 用于指定数据的值,可以使用spring中SpEL(也就是spring的el表达式)
* SpEL写法: ${表达式}
*
* 3. 用于改变作用范围的
* 它们的作用就和XML配置文件中编写一个bean标签使用scope属性实现的功能是一样的
* @Scope:
* 作用: 用于指定bean的作用范围
* 属性:
* value: 指定范围的取值,常用取值: singleton(默认),property
*
* 4. 和生命周期有关的 [了解]
* 它们的作用就和XML配置文件中编写一个bean标签使用init-method,destroy-method的作用是一样的
* @PreDestroy:
* 作用: 用于指定销毁方法
* @PostConstruct:
* 作用: 用于指定初始化方法
*/
@Service(value="accountService")
@Scope(value = "singleton")
public class AccountServiceImpl implements AccountService {
// @Autowired
// @Qualifier(value = "accountDao1")
@Resource(name = "accountDao1")
private AccountDao accountDao;
// public AccountServiceImpl() {
// System.out.println("AccountServiceImpl 对象创建了...");
// }
/**
* 初始化方法
*/
@PostConstruct
public void init() {
System.out.println("init...");
}
/**
* 销毁方法
*/
@PreDestroy
public void destroy() {
System.out.println("destroy...");
}
/**
* 模拟保存账户
*/
@Override
public void saveAccount() {
accountDao.saveAccount();
}
}
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
- 调用
public class AccountController {
public static void main(String[] args) {
// ============= ApplicationContext [立即加载] =============
// 1. 获取核心容器对象 [推荐 ClassPathXmlApplicationContext方式创建]
// ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
// 2. 根据id获取bean对象 [service,dao都只创建一次,单例模式]
AccountService accountService = (AccountService) ac.getBean("accountService");
// System.out.println(accountService);
// AccountDao accountDao = ac.getBean("accountDao", AccountDao.class);
// System.out.println(accountDao);
// 3. 调用方法
accountService.saveAccount();
// 4. 销毁
ac.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
init...
save success 111...
destroy...
1
2
3
2
3
上次更新: 2023/03/27, 08:56:25