一篇Spring IOC笔记

Spring IOC
1. 主要内容
2. Spring 框架
2.1. Spring 框架概念
Spring 是众多开源 java 项⽬中的⼀员,基于分层的 javaEE 应⽤⼀站式轻量级开源框架,主要核⼼是
IOC (控制反转 / 依赖注⼊)与 AOP (⾯向切⾯)两⼤技术,实现项⽬在开发过程中的轻松解耦,提⾼项
⽬的开发效率。
在项⽬中引⼊ Spring ⽴即可以带来下⾯的好处 降低组件之间的耦合度,实现软件各层之间的解耦。可
以使⽤容器提供的众多服务,如:事务管理服务、消息服务等等。当我们使⽤容器管理事务时,开发⼈
员就不再需要⼿⼯控制事务 . 也不需处理复杂的事务传播。 容器提供单例模式⽀持,开发⼈员不再需要
⾃⼰编写实现代码。 容器提供了 AOP 技术,利⽤它很容易实现如权限拦截、运⾏期监控等功能。 2.2. Spring 源码架构
Spring 总共⼤约有 20 个模块,由 1300 多个不同的⽂件构成。⽽这些组件被分别整合在核⼼容器( Core
Container )、 Aop Aspect Oriented Programming )和设备⽀持( Instrmentation )、数据访问及集成
Data Access/Integeration )、 Web 、报⽂发送( Messaging )、测试 6 个模块集合中。
1. 核⼼容器: Spring-beans Spring-core 模块是 Spring 框架的核⼼模块,包含控制反转( Inversion
of Control, IoC )和依赖注⼊( Dependency Injection, DI , 核⼼容器提供 Spring 框架的基本功能。
核⼼容器的主要组件是 BeanFactory ,⼯⼚模式的实现。 BeanFactory 使⽤控制反转( IOC ) 思想
将应⽤程序的配置和依赖性规范与实际的应⽤程序代码分开。
Spring 上下⽂ Spring Context Spring 上下⽂是⼀个配置⽂件,向 Spring 框架提供上下⽂信息。
Spring 上下⽂包括企业服务,例如 JNDI EJB 、电⼦邮件、国际化、校验和调度功能。
Spring-Expression 模块是统⼀表达式语⾔( unified EL )的扩展模块,可以查询、管理运⾏中的对
象,同时也⽅便的可以调⽤对象⽅法、操作数组、集合等。它的语法类似于传统 EL ,但提供了额
外的功能,最出⾊的要数函数调⽤和简单字符串的模板函数。
2. Spring-AOP Spring-aop Spring 的另⼀个核⼼模块 , Spring 中,他是以 JVM 的动态代理技术为基
础,然后设计出了⼀系列的 Aop 横切实现,⽐如前置通知、返回通知、异常通知等。通过其配置
管理特性, Spring AOP 模块直接将⾯向切⾯的编程功能集成到了 Spring 框架中。所以,可以很容
易地使 Spring 框架管理的任何对象⽀持 AOP
3. Spring Data Access( 数据访问 ) :由 Spring-jdbc Spring-tx Spring-orm Spring-jms Spring-oxm 5
个模块组成 Spring-jdbc 模块是 Spring 提供的 JDBC 抽象框架的主要实现模块,⽤于简化 Spring
JDBC Spring-tx 模块是 SpringJDBC 事务控制实现模块。使⽤ Spring 框架,它对事务做了很好的封装,通
过它的 Aop 配置,可以灵活的配置在任何⼀层。
Spring-Orm 模块是 ORM 框架⽀持模块,主要集成 hibernate, Java Persistence API (JPA) Java Data
Objects (JDO) ⽤于资源管理、数据访问对象 (DAO) 的实现和事务策略。
Spring-Jms 模块( Java Messaging Service )能够发送和接受信息。
Spring-Oxm 模块主要提供⼀个抽象层以⽀撑 OXM OXM Object-to-XML-Mapping 的缩写,它是⼀
O/M-mapper ,将 java 对象映射成 XML 数据,或者将 XML 数据映射成 java 对象),例如: JAXB,
Castor, XMLBeans, JiBX XStream 等。
4. Web 模块:由 Spring-web Spring-webmvc Spring-websocket Spring-webmvc-portlet 4 个模块组
成, Web 上下⽂模块建⽴在应⽤程序上下⽂模块之上,为基于 Web 的应⽤程序提供了上下⽂。
Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的⼯作。
5. 报⽂发送:即 Spring-messaging 模块。
Spring-messaging Spring4 新加⼊的⼀个模块,主要职责是为 Spring 框架集成⼀些基础的报⽂传
送应⽤。
6. 单元测试:即 Spring-test 模块。 Spring-test 模块主要为测试提供⽀持
2.3. Spring 框架环境搭建
2.3.1. 环境要求
JDK 版本:
JDK 1.7 及以上版本
Spring 版本:
Spring 5.x 版本
2.3.2. 新建 Maven 项⽬
1. 创建 Maven 的普通 Java 项⽬ 2. 设置项⽬的坐标
3. 设置项⽬的 Maven 环境 4. 设置项⽬的名称和存放的⼯作空间
2.3.3. 调整项⽬环境
1. 修改 JDK 版本 2. 修改单元测试 JUnit 版本
3. build 标签中的 pluginManagement 标签
2.3.4. 添加 Spring 框架的依赖坐标
Maven 仓库: https://mvnrepository.com/
2.3.5. 编写 Bean 对象
2.3.6. 添加 Spring 配置⽂件
1. 在项⽬的 src 下创建⽂件夹 resources Alt + insert
<properties>
<project.build.sourceEncoding> UTF-8 </project.build.sourceEncoding>
<maven.compiler.source> 1.8 </maven.compiler.source>
<maven.compiler.target> 1.8 </maven.compiler.target>
</properties>
<dependency>
<groupId> junit </groupId>
<artifactId> junit </artifactId>
<version> 4.12 </version>
<scope> test </scope>
</dependency>
<!-- 删除 build 标签中的 pluginManagement 标签 -->
<build>
</build>
<!-- 添加 Spring 框架的核⼼依赖 -->
<dependency>
<groupId> org.springframework </groupId>
<artifactId> spring-context </artifactId>
<version> 5.2.4.RELEASE </version>
</dependency>
package com . xxxx . service ;
public class UserService {
public void test (){
System . out . println ( "Hello Spring!" );
}
} 2. resources 标记为资源⽬录
3. src\main\resources ⽬录下新建 spring.xml ⽂件,并拷⻉官⽹⽂档提供的模板内容到 xml 中。
配置 bean xml 中,把对应 bean 纳⼊到 Spring 容器来管理
spring.xml
4. spring.xml 中配置 Bean 对象
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd" >
<!--
xmlns xml namespace xml 使⽤的命名空间
xmlns:xsi xml schema instance xml 遵守的具体规范
xsi:schemaLocation 本⽂档 xml 遵守的规范 官⽅指定
-->
<bean id = "userService" class = "com.xxxx.service.UserService" ></bean>
</beans> 2.3.7. 加载配置⽂件,获取实例化对象
3. Spring IOC 容器 Bean 对象实例化模拟
思路 :
1. 定义 Bean ⼯⼚接⼝,提供获取 bean ⽅法
2. 定义 Bean ⼯⼚接⼝实现类,解析配置⽂件,实例化 Bean 对象
3. 实现获取 Bean ⽅法
3.1. 定义 Bean 属性对象
<!--
id bean 对象的 id ,唯⼀标识。⼀般是 Bean 对象的名称的⾸字⺟⼩写
class bean 对象的类路径
-->
<bean id = "userService" class = "com.xxxx.service.UserService" ></bean>
package com . xxxx ;
import com . xxxx . service . UserService ;
import org . springframework . context . ApplicationContext ;
import org . springframework . context . support . ClassPathXmlApplicationContext ;
public class App {
public static void main ( String [] args ) {
// 获取 Spring 上下⽂环境 ( 加载配置⽂件 )
ApplicationContext ac = new ClassPathXmlApplicationContext ( "spring.xml" );
// 通过 getBean ⽅法得到 Spring 容器中实例化好的 Bean 对象 (实例化 Bean 对象)
// userService 代表的是配置⽂件中 bean 标签的 id 属性值
UserService userService = ( UserService ) ac . getBean ( "userService" );
// 调⽤⽅法 (使⽤实例化对象)
userService . test ();
}
}
package com . xxxx . spring ;
/**
* bean 对象
* ⽤来接收配置⽂件中 bean 标签的 id class 属性值
*/
public class MyBean {
private String id ; // bean 对象的 id 属性值 3.2. 添加 dom4j 坐标依赖
3.3. 准备⾃定义配置⽂件
spring.xml
private String clazz ; // bean 对象的类路径
public MyBean () {
}
public MyBean ( String id , String clazz ) {
this . id = id ;
this . clazz = clazz ;
}
public String getId () {
return id ;
}
public void setId ( String id ) {
this . id = id ;
}
public String getClazz () {
return clazz ;
}
public void setClazz ( String clazz ) {
this . clazz = clazz ;
}
}
<!-- dom4j -->
<dependency>
<groupId> dom4j </groupId>
<artifactId> dom4j </artifactId>
<version> 1.6.1 </version>
</dependency>
<!-- XPath -->
<dependency>
<groupId> jaxen </groupId>
<artifactId> jaxen </artifactId>
<version> 1.1.6 </version>
</dependency> 3.4. 定义 Bean ⼯⼚接⼝
3.5. 定义 Bean 接⼝的实现类
<?xml version="1.0" encoding="utf-8" ?>
<beans>
<bean id = "userService" class = "com.xxxx.service.UserService" ></bean>
<bean id = "accountService" class = "com.xxxx.service.AccountService" ></bean>
</beans>
package com . xxxx . spring ;
/**
* Bean ⼯⼚接⼝定义
*/
public interface MyFactory {
// 通过 id 值获取对象
public Object getBean ( String id );
}
package com . xxxx . spring ;
import org . dom4j . Document ;
import org . dom4j . DocumentException ;
import org . dom4j . Element ;
import org . dom4j . XPath ;
import org . dom4j . io . SAXReader ;
import java . net . URL ;
import java . util . ArrayList ;
import java . util . HashMap ;
import java . util . List ;
import java . util . Map ;
/**
* 模拟 Spring 的实现
* 1 、通过构造器得到相关配置⽂件
* 2 、通过 dom4j 解析 xml ⽂件,得到 List 存放 id class
* 3 、通过反射实例化得到对象 Class.forName( 类的全路径 ).newInstance(); 通过 Map<id,Class>
* 4 、得到指定的实例化对象
*/
public class MyClassPathXmlApplicationContext implements BeanFactory {
private Map beans = new HashMap (); // 实例化后的对象放⼊ map
private List < MyBean > myBeans ; // 存放已读取 bean 配置信息
/* 1 、通过构造器得到相关配置⽂件 */
public MyClassPathXmlApplicationContext ( String fileName ) {
/* 2 、通过 dom4j 解析 xml ⽂件,得到 List (存放 id class */
this . parseXml ( fileName );
/* 3 、通过反射实例化得到对象 Class.forName( 类路径 ).newInstance(); 通过 Map 存储 */
this . instanceBean ();
}
/**
* 通过 dom4j 解析 xml ⽂件,得到 List 存放 id class
* 1 、获取解析器
* 2 、得到配置⽂件的 URL
* 3 、通过解析器解析 xml ⽂件( spring.xml
* 4 、通过 xpath 语法,获取 beans 标签下的所有 bean 标签
* 5 、通过指定语法解析⽂档对象,返回集合
* 6 、判断集合是否为空,遍历集合
* 7 、获取标签元素中的属性
* 8 、得到 Bean 对象,将 Bean 对象设置到集合中
* @param fileName
*/
private void parseXml ( String fileName ) {
// 1 、获取解析器
SAXReader reader = new SAXReader ();
// 2 、得到配置⽂件的 URL
URL url = this . getClass (). getClassLoader (). getResource ( fileName );
try {
// 3 、通过解析器解析 xml ⽂件( spring.xml
Document document = reader . read ( url );
// 4 、通过 xpath 语法,获取 beans 标签下的所有 bean 标签
XPath xPath = document . createXPath ( "beans/bean" );
// 通过指定语法解析⽂档对象,返回集合
List < Element > list = xPath . selectNodes ( document );
// 判断集合是否为空,遍历集合
if ( list != null && list . size () > 0 ) {
myBeans = new ArrayList <> ();
for ( Element el : list ) {
// 获取标签元素中的属性
String id = el . attributeValue ( "id" ); // id 属性值
String clazz = el . attributeValue ( "class" ); // class 属性值
System . out . println ( el . attributeValue ( "id" ));
System . out . println ( el . attributeValue ( "class" ));
// 得到 Bean 对象
MyBean bean = new MyBean ( id , clazz );
// Bean 对象设置到集合中
myBeans . add ( bean );
}
}
} catch ( DocumentException e ) {
e . printStackTrace ();
} 3.6. 测试⾃定义 IOC 容器
1. 创建与配置⽂件中对应的 Bean 对象
UserService.java
AccountService.java
}
/**
* 通过反射实例化得到对象
* Class.forName( 类的全路径 ).newInstance();
* 通过 Map<id,Class> 存储
*/
private void instanceBean () {
// 判断 bean 集合是否为空,不为空遍历得到对应 Bean 对象
if ( myBeans != null && myBeans . size () > 0 ) {
for ( MyBean bean : myBeans ){
try {
// 通过类的全路径实例化对象
Object object = Class . forName ( bean . getClazz ()). newInstance ();
// id 与实例化对象设置到 map 对象中
beans . put ( bean . getId (), object );
} catch ( Exception e ) {
e . printStackTrace ();
}
}
}
}
/**
* 通过 key 获取 map 中的指定 value
* @param id
* @return
*/
@Override
public Object getBean ( String id ) {
Object object = beans . get ( id );
return object ;
}
}
package com . xxxx . service ;
public class UserService {
public void test (){
System . out . println ( "UserService Test..." );
}
} 2. 测试是否可以获取实例化的 Bean 对象
Spring 容器在启动的时候 读取 xml 配置信息,并对配置的 bean 进⾏实例化(这⾥模拟的⽐较简
单,仅⽤于帮助⼤家理解),同时通过上下⽂对象提供的 getBean() ⽅法拿到我们配置的 bean
象,从⽽实现外部容器⾃动化维护并创建 bean 的效果。
4. Spring IOC 配置⽂件加载
4.1. Spring 配置⽂件加载
spring.xml
package com . xxxx . service ;
public class AccountService {
public void test (){
System . out . println ( "AccountService Test..." );
}
}
package com . xxxx ;
import com . xxxx . spring . MyFactory ;
import com . xxxx . spring . MyClassPathXmlApplicationContext ;
import com . xxxx . service . AccountService ;
import com . xxxx . service . UserService ;
public class App {
public static void main ( String [] args ) {
MyFactory factory = new MyClassPathXmlApplicationContext ( "spring.xml" );
// 得到实例化对象
UserService userService = ( UserService ) factory . getBean ( "userService" );
userService . test ();
UserService userService2 = ( UserService ) factory . getBean ( "userService" );
System . out . println ( userService + "=====" + userService2 );
AccountService accountService =
( AccountService ) factory . getBean ( "accountService" );
accountService . test ();
}
} 4.1.1. 根据相对路径加载资源
4.1.2. 根据绝对路径加载资源(了解)
4.2. Spring 多配置⽂件加载
Spring 框架启动时可以加载多个配置⽂件到环境中。对于⽐较复杂的项⽬,可能对应的配置⽂件有多
个,项⽬在启动部署时会将多个配置⽂件同时加载进来。
service.xml
dao.xml
4.2.1. 可变参数,传⼊多个⽂件名
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd" >
<bean id = "userService" class = "com.xxxx.service.UserService" ></bean>
</beans>
ApplicationContext ac = new ClassPathXmlApplicationContext ( "spring.xml" );
ApplicationContext ac = new
FileSystemXmlApplicationContext ( "C:/IdeaWorkspace/spring01/src/main/resources/spring.x
ml" );
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd" >
<bean id = "userService" class = "com.xxxx.service.UserService" ></bean>
</beans>
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd" >
<bean id = "userDao" class = "com.xxxx.dao.UserDao" ></bean>
</beans> 4.2.2. 通过总的配置⽂件 import 其他配置⽂件
spring.xml
加载时只需加载总的配置⽂件即可
5. Spring IOC 容器 Bean 对象实例化
5.1. 构造器实例化
注: 通过默认构造器创建 空构造⽅法必须存在 否则创建失败
1. 设置配置⽂件 spring.xml
2. 获取实例化对象
// 同时加载多个资源⽂件
ApplicationContext ac = new ClassPathXmlApplicationContext ( "spring.xml" , "dao.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
https://www.springframework.org/schema/beans/spring-beans.xsd" >
<!-- 导⼊需要包含的资源⽂件 -->
<import resource = "service.xml" />
<import resource = "dao.xml" />
</beans>
// 加载总的资源⽂件
ApplicationContext ac = new ClassPathXmlApplicationContext ( "spring.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
https://www.springframework.org/schema/beans/spring-beans.xsd" >
<bean id = "userService" class = "com.xxxx.service.UserService" ></bean>
</beans>
ApplicationContext ac = new ClassPathXmlApplicationContext ( "spring.xml" );
UserService userService = ( UserService ) ac . getBean ( "userService" );
userService . test (); 5.2. 静态⼯⼚实例化(了解)
注:
要有该⼯⼚类及⼯⼚⽅法
⼯⼚⽅法为静态的
1. 定义静态⼯⼚类
2. 设置配置⽂件 spring.xml
3. 获取实例化对象
当我们指定 Spring 使⽤静态⼯⼚⽅法来创建 Bean 实例时, Spring 将先解析配置⽂件,并根据配置
⽂件指定的信息, 通过反射调⽤静态⼯⼚类的静态⼯⼚⽅法,并将该静态⼯⼚⽅法的返回值作为
Bean 实例 ,在这个过程中, Spring 不再负责创建 Bean 实例, Bean 实例是由⽤户提供的静态⼯⼚⽅
法提供 的。
package com . xxxx . factory ;
import com . xxxx . service . UserService ;
/**
* 定义静态⼯⼚类
*/
public class StaticFactory {
/**
* 定义对应的静态⽅法,返回实例化对象
* @return
*/
public static UserService createUserService () {
return new UserService ();
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd" >
<!-- 静态⼯⼚ -->
<bean id = "userService" class = "com.xxxx.factory.StaticFactory" factory
method = "createUserService" ></bean>
</beans>
ApplicationContext ac = new ClassPathXmlApplicationContext ( "spring.xml" );
UserService userService = ( UserService ) ac . getBean ( "userService" );
userService . test (); 5.3. 实例化⼯⼚实例化(了解)
注:
⼯⼚⽅法为⾮静态⽅法
需要配置⼯⼚ bean ,并在业务 bean 中配置 factory-bean factory-method 属性
1. 定义⼯⼚类
2. 设置配置⽂件 spring.xml
3. 获取实例化对象
package com . xxxx . factory ;
import com . xxxx . service . UserService ;
/**
* 定义⼯⼚类
*/
public class InstanceFactory {
/**
* 定义⽅法,返回实例化对象
* @return
*/
public UserService createUserService () {
return new UserService ();
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd" >
<!--
实例化⼯⼚
1. 定义实例化⼯⼚ bean
2. 引⽤⼯⼚ bean 指定⼯⼚创建⽅法 ( ⽅法为⾮静态 )
-->
<bean id = "instanceFactory" class = "com.xxxx.factory.InstanceFactory" ></bean>
<bean id = "userService" factory-bean = "instanceFactory" factory
method = "createUserService" ></bean>
</beans> 5.4. Spring 三种实例化 Bean 的⽅式⽐较
⽅式⼀: 通过 bean 的缺省构造函数创建 ,当各个 bean 的业务逻辑相互⽐较独⽴的时候或者和外界
关联较少的时候可以使⽤。
⽅式⼆:利⽤静态 factory ⽅法创建,可以统⼀管理各个 bean 的创建,如各个 bean 在创建之前需要
相同的初始化处理,则可⽤这个 factory ⽅法险进⾏统⼀的处理等等。
⽅式三:利⽤实例化 factory ⽅法创建,即将 factory ⽅法也作为了业务 bean 来控制, 1 可⽤于集成其
他框架的 bean 创建管理⽅法, 2 能够使 bean factory 的⻆⾊互换。
开发中项⽬⼀般使⽤⼀种⽅式实例化 bean ,项⽬开发基本采⽤第⼀种⽅式,交给 Spring 托管,使⽤时
直接拿来使⽤即可。另外两种了解
6. Spring IOC 注⼊
⼿动实例化与外部引⼊
图⼀:
图⼆:
ApplicationContext ac = new ClassPathXmlApplicationContext ( "spring.xml" );
UserService userService = ( UserService ) ac . getBean ( "userService" );
userService . test (); 对⽐发现:图⼆中对于 UserDao 对象的创建并没有像图⼀那样主动的去实例化,⽽是通过带参⽅法形
式将 UserDao 传⼊过来,从⽽实现 UserService UserDao 的依赖。
⽽实际创建对象的幕后对象即是交给了外部来创建。
6.1. Spring IOC ⼿动装配(注⼊)
Spring ⽀持的注⼊⽅式共有四种: set 注⼊、构造器注⼊、静态⼯⼚注⼊、实例化⼯⼚注⼊。
6.1.1. set ⽅法注⼊
注:
属性字段需要提供 set ⽅法
四种⽅式,推荐使⽤ set ⽅法注⼊
6.1.1.1. 业务对象 JavaBean
1. 属性字段提供 set ⽅法
2. 配置⽂件的 bean 标签设置 property 标签
public class UserService {
// 业务对象 UserDao set 注⼊(提供 set ⽅法)
private UserDao userDao ;
public void setUserDao ( UserDao userDao ) {
this . userDao = userDao ;
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd" >
6.1.1.2. 常⽤对象和基本类型
1. 属性字段提供 set ⽅法
2. 配置⽂件的 bean 标签设置 property 标签
<!--
IOC 通过 property 标签⼿动装配(注⼊):
Set ⽅法注⼊
name bean 对象中属性字段的名称
ref :指定 bean 标签的 id 属性值
-->
<bean id = "userDao" class = "com.xxxx.dao.UserDao" ></bean>
<bean id = "userService" class = "com.xxxx.service.UserService" >
<!-- 业务对象 注⼊ -->
<property name = "userDao" ref = "userDao" />
</bean>
</beans>
public class UserService {
// 常⽤对象 String set 注⼊(提供 set ⽅法)
private String host ;
public void setHost ( String host ) {
this . host = host ;
}
// 基本类型 Integer set 注⼊(提供 set ⽅法)
private Integer port ;
public void setPort ( Integer port ) {
this . port = port ;
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd" >
<!--
IOC 通过 property 标签⼿动装配(注⼊):
Set ⽅法注⼊
name bean 对象中属性字段的名称
value: 具体的值(基本类型 常⽤对象 | ⽇期 集合)
-->
<bean id = "userService" class = "com.xxxx.service.UserService" >
<!-- 常⽤对象 String 注⼊ -->
<property name = "host" value = "127.0.0.1" />
<!-- 基本类型注⼊ -->
<property name = "port" value = "8080" />
</bean> 6.1.1.3. 集合类型和属性对象
1. 属性字段提供 set ⽅法
2. 配置⽂件的 bean 标签设置 property 标签
</beans>
public class UserService {
// List 集合 set 注⼊(提供 set ⽅法)
public List < String > list ;
public void setList ( List < String > list ) {
this . list = list ;
}
// Set 集合 set 注⼊(提供 set ⽅法)
private Set < String > set ;
public void setSet ( Set < String > set ) {
this . set = set ;
}
// Map set 注⼊(提供 set ⽅法)
private Map < String , Object > map ;
public void setMap ( Map < String , Object > map ) {
this . map = map ;
}
// Properties set 注⼊(提供 set ⽅法)
private Properties properties ;
public void setProperties ( Properties properties ) {
this . properties = properties ;
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd" >
<!--
IOC 通过 property 标签⼿动装配(注⼊):
Set ⽅法注⼊
name bean 对象中属性字段的名称
value: 具体的值(基本类型 常⽤对象 | ⽇期 集合)
-->
<bean id = "userService" class = "com.xxxx.service.UserService" >
<!--List 集合 注⼊ --> 6.1.1.4. 测试代码
UserService.java
<property name = "list" >
<list>
<value> 上海 </value>
<value> 北京 </value>
<value> 杭州 </value>
</list>
</property>
<!--Set 集合注⼊ -->
<property name = "set" >
<set>
<value> 上海 SH </value>
<value> 北京 BJ </value>
<value> 杭州 HZ </value>
</set>
</property>
<!--Map 注⼊ -->
<property name = "map" >
<map>
<entry>
<key><value> 周杰伦 </value></key>
<value> 我是如此相信 </value>
</entry>
<entry>
<key><value> 林俊杰 </value></key>
<value> 可惜没如果 </value>
</entry>
<entry>
<key><value> 陈奕迅 </value></key>
<value> ⼗年 </value>
</entry>
</map>
</property>
<!--Properties 注⼊ -->
<property name = "properties" >
<props>
<prop key = " 上海 " > 东⽅明珠 </prop>
<prop key = " 北京 " > 天安⻔ </prop>
<prop key = " 杭州 " > ⻄湖 </prop>
</props>
</property>
</bean>
</beans>
public class UserService {
// 业务对象 UserDao set 注⼊(提供 set ⽅法)
private UserDao userDao ;
public void setUserDao ( UserDao userDao ) {
this . userDao = userDao ;
}
// 常⽤对象 String set 注⼊(提供 set ⽅法)
private String host ;
public void setHost ( String host ) {
this . host = host ;
}
// 基本类型 Integer set 注⼊(提供 set ⽅法)
private Integer port ;
public void setPort ( Integer port ) {
this . port = port ;
}
// List 集合 set 注⼊(提供 set ⽅法)
public List < String > list ;
public void setList ( List < String > list ) {
this . list = list ;
}
// List 集合输出
public void printList () {
list . forEach ( s -> System . out . println ( s ));
}
// Set 集合 set 注⼊(提供 set ⽅法)
private Set < String > set ;
public void setSet ( Set < String > set ) {
this . set = set ;
}
// Set 集合输出
public void printSet () {
set . forEach ( s -> System . out . println ( s ));
}
// Map set 注⼊(提供 set ⽅法)
private Map < String , Object > map ;
public void setMap ( Map < String , Object > map ) {
this . map = map ;
}
// Map 输出
public void printMap () {
map . forEach (( k , v ) -> System . out . println ( k + " " + v ));
}
// Properties set 注⼊(提供 set ⽅法)
private Properties properties ; spring.xml
public void setProperties ( Properties properties ) {
this . properties = properties ;
}
// Properties 输出
public void printProperties (){
properties . forEach (( k , v ) -> System . out . println ( k + " " + v ));
}
public void test (){
System . out . println ( "UserService Test..." );
userDao . test ();
studentDao . test ();
System . out . println ( "Host " + host + " port " + port );
// List 集合
printList ();
// Set 集合
printSet ();
// Map
printMap ();
// Properties
printProperties ();
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd" >
<!--
IOC 通过 property 标签⼿动装配(注⼊):
Set ⽅法注⼊
name bean 对象中属性字段的名称
ref :指定 bean 标签的 id 属性值
value: 具体的值(基本类型 常⽤对象 | ⽇期 集合)
-->
<bean id = "userDao" class = "com.xxxx.dao.UserDao" ></bean>
<bean id = "userService" class = "com.xxxx.service.UserService" >
<!-- 业务对象 注⼊ -->
<property name = "userDao" ref = "userDao" />
<property name = "studentDao" ref = "studentDao" />
<!-- 常⽤对象 String 注⼊ -->
<property name = "host" value = "192.168.1.109" />
<!-- 基本类型注⼊ -->
<property name = "port" value = "8080" />
<!--List 集合 注⼊ -->
<property name = "list" >
<list>
<value> 上海 </value>
<value> 北京 </value>
<value> 杭州 </value>
</list>
</property>
<!--Set 集合注⼊ -->
<property name = "set" >
<set>
<value> 上海 SH </value>
<value> 北京 BJ </value>
<value> 杭州 HZ </value>
</set>
</property>
<!--Map 注⼊ -->
<property name = "map" >
<map>
<entry>
<key><value> 周杰伦 </value></key>
<value> 我是如此相信 </value>
</entry>
<entry>
<key><value> 林俊杰 </value></key>
<value> 可惜没如果 </value>
</entry>
<entry>
<key><value> 陈奕迅 </value></key>
<value> ⼗年 </value>
</entry>
</map>
</property>
<!--Properties 注⼊ -->
<property name = "properties" >
<props>
<prop key = " 上海 " > 东⽅明珠 </prop>
<prop key = " 北京 " > 天安⻔ </prop>
<prop key = " 杭州 " > ⻄湖 </prop>
</props> 6.1.2. 构造器注⼊
注:
提供带参构造器
6.1.2.1. 单个 Bean 对象作为参数
Java 代码
XML 配置
</property>
</bean>
</beans>
public class UserService {
private UserDao userDao ; // JavaBean 对象
public UserService ( UserDao userDao ) {
this . userDao = userDao ;
}
public void test (){
System . out . println ( "UserService Test..." );
userDao . test ();
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd" >
<!--
IOC 通过构造器注⼊:
通过 constructor-arg 标签进⾏注⼊
name :属性名称
ref :指定 bean 标签的 id 属性值
-->
<bean id = "userDao" class = "com.xxxx.dao.UserDao" ></bean>
<bean id = "userService" class = "com.xxxx.service.UserService" >
<constructor-arg name = "userDao" ref = "userDao" ></constructor-arg>
</bean> 6.1.2.2. 多个 Bean 对象作为参数
Java 代码
XML 配置
6.1.2.3. Bean 对象和常⽤对象作为参数
</beans>
public class UserService {
private UserDao userDao ; // JavaBean 对象
private AccountDao accountDao // JavaBean 对象
public UserService ( UserDao userDao , AccountDao accountDao ) {
this . userDao = userDao ;
this . accountDao = accountDao ;
}
public void test (){
System . out . println ( "UserService Test..." );
userDao . test ();
accountDao . test ();
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd" >
<!--
IOC 通过构造器注⼊:
通过 constructor-arg 标签进⾏注⼊
name :属性名称
ref :指定 bean 标签的 id 属性值
-->
<bean id = "userDao" class = "com.xxxx.dao.UserDao" ></bean>
<bean id = "accountDao" class = "com.xxxx.dao.AccountDao" ></bean>
<bean id = "userService" class = "com.xxxx.service.UserService" >
<constructor-arg name = "userDao" ref = "userDao" ></constructor-arg>
<constructor-arg name = "accountDao" ref = "accountDao" ></constructor-arg>
</bean>
</beans> Java 代码
XML 配置
6.1.2.4. 循环依赖问题
循环问题产⽣的原因:
public class UserService {
private UserDao userDao ; // JavaBean 对象
private AccountDao accountDao ; // JavaBean 对象
private String uname ; // 字符串类型
public UserService ( UserDao userDao , AccountDao accountDao , String uname ) {
this . userDao = userDao ;
this . accountDao = accountDao ;
this . uname = uname ;
}
public void test (){
System . out . println ( "UserService Test..." );
userDao . test ();
accountDao . test ();
System . out . println ( "uname " + uname );
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd" >
<!--
IOC 通过构造器注⼊:
通过 constructor-arg 标签进⾏注⼊
name :属性名称
ref :指定 bean 标签的 id 属性值
value :基本类型 常⽤对象的值
index :构造器中参数的下标,从 0 开始
-->
<bean id = "userDao" class = "com.xxxx.dao.UserDao" ></bean>
<bean id = "accountDao" class = "com.xxxx.dao.AccountDao" ></bean>
<bean id = "userService" class = "com.xxxx.service.UserService" >
<constructor-arg name = "userDao" ref = "userDao" ></constructor-arg>
<constructor-arg name = "accountDao" ref = "accountDao" ></constructor-arg>
<constructor-arg name = "uname" value = "admin" ></constructor-arg>
</bean>
</beans> Bean 通过构造器注⼊,之间彼此相互依赖对⽅导致 bean ⽆法实例化。
问题展示:
1. Java 代码
2. XML 配置
如何解决:将构造器注⼊改为 set ⽅法注⼊
1. Java 代码
public class AccountService {
private RoleService roleService ;
public AccountService ( RoleService roleService ) {
this . roleService = roleService ;
}
public void test () {
System . out . println ( "AccountService Test..." );
}
}
public class RoleService {
private AccountService accountService ;
public RoleService ( AccountService accountService ) {
this . accountService = accountService ;
}
public void test () {
System . out . println ( "RoleService Test..." );
}
}
<!--
如果多个 bean 对象中互相注⼊,则会出现循环依赖的问题
可以通过 set ⽅法注⼊解决
-->
<bean id = "accountService" class = "com.xxxx.service.AccountService" >
<constructor-arg name = "roleService" ref = "roleService" />
</bean>
<bean id = "roleService" class = "com.xxxx.service.RoleService" >
<constructor-arg name = "accountService" ref = "accountService" />
</bean> 2. XML 配置
public class AccountService {
private RoleService roleService ;
/* public AccountService(RoleService roleService) {
this.roleService = roleService;
}*/
public void setRoleService ( RoleService roleService ) {
this . roleService = roleService ;
}
public void test () {
System . out . println ( "AccountService Test..." );
}
}
public class RoleService {
private AccountService accountService ;
/* public RoleService(AccountService accountService) {
this.accountService = accountService;
}*/
public void setAccountService ( AccountService accountService ) {
this . accountService = accountService ;
}
public void test () {
System . out . println ( "RoleService Test..." );
}
}
<!--
<bean id="accountService" class="com.xxxx.service.AccountService">
<constructor-arg name="roleService" ref="roleService"/>
</bean>
<bean id="roleService" class="com.xxxx.service.RoleService">
<constructor-arg name="accountService" ref="accountService"/>
</bean>
-->
<!-- 修改为 set ⽅法注⼊ -->
<bean id = "accountService" class = "com.xxxx.service.AccountService" >
<property name = "roleService" ref = "roleService" />
</bean>
<bean id = "roleService" class = "com.xxxx.service.RoleService" >
<property name = "accountService" ref = "accountService" /> 6.1.3. 静态⼯⼚注⼊
1. 定义静态⼯⼚类
2. Java 代码
3. XML 配置
在配置⽂件中设置 bean 标签,指定⼯⼚对象并设置对应的⽅法
6.1.4. 实例化⼯⼚注⼊
1. 定义⼯⼚类
</bean>
public class StaticFactory {
// 定义静态⽅法
public static TypeDao createTypeDao () {
return new TypeDao ();
}
}
public class TypeService {
private TypeDao typeDao ;
public void setTypeDao ( TypeDao typeDao ) {
this . typeDao = typeDao ;
}
public void test () {
System . out . println ( "TypeService Test..." );
}
}
<bean id = "typeService" class = "com.xxxx.service.TypeService" >
<property name = "typeDao" ref = "typeDao" />
</bean>
<!--
静态⼯⼚注⼊:
静态⼯⼚注⼊也是借助 set ⽅法注⼊,只是被注⼊的 bean 对象的实例化是通过静态⼯⼚实例化的
-->
<bean id = "typeDao" class = "com.xxxx.factory.StaticFactory" factory
method = "createTypeDao" ></bean> 2. Java 代码
3. XML 配置
声明⼯⼚ bean 标签,声明 bean 对象,指明⼯⼚对象和⼯⼚⽅法
重点掌握 set 注⼊和构造器注⼊,⼯⼚⽅式了解即可。实际开发中基本使⽤ set ⽅式注⼊ bean
6.1.5. 注⼊⽅式的选择
开发项⽬中 set ⽅式注⼊⾸选
使⽤构造注⼊可以在构建对象的同时⼀并完成依赖关系的建⽴,对象⼀建⽴则所有的⼀切也就准备好
了,但如果要建⽴的对象关系很多,使⽤构造器注⼊会在构建函数上留下⼀⻓串的参数 , 且不易记忆 ,
时使⽤ Set 注⼊会是个不错的选择。
  使⽤ Set 注⼊可以有明确的名称,可以了解注⼊的对象会是什么,像 setXXX() 这样的名称会⽐记忆
Constructor 上某个参数的位置代表某个对象更好。
p 名称空间的使⽤
public class InstanceFactory {
public TypeDao createTypeDao () {
return new TypeDao ();
}
}
public class TypeService {
private TypeDao typeDao ;
public void setTypeDao ( TypeDao typeDao ) {
this . typeDao = typeDao ;
}
public void test () {
System . out . println ( "TypeService Test..." );
}
}
<bean id = "typeService" class = "com.xxxx.service.TypeService" >
<property name = "typeDao" ref = "typeDao" />
</bean>
<!--
实例化⼯⼚注⼊:
实例化⼯⼚注⼊也是借助 set ⽅法注⼊,只是被注⼊的 bean 对象的实例化是通过实例化⼯⼚实例化的
-->
<bean id = "instanceFactory" class = "com.xxxx.factory.InstanceFactory" ></bean>
<bean id = "typeDao" factory-bean = "instanceFactory" factory-method = "createTypeDao" >
</bean> spring2.5 以后,为了简化 setter ⽅法属性注⼊,引⽤ p 名称空间的概念,可以将 ⼦元素,简化为元素属
性配置。
1. 属性字段提供 set ⽅法
2. 在配置⽂件 spring.xml 引⼊ p 名称空间
6.2. Spring IOC ⾃动装配(注⼊)
注解⽅式注⼊ Bean
对于 bean 的注⼊,除了使⽤ xml 配置以外,可以使⽤注解配置。注解的配置,可以简化配置⽂件,
提⾼开发的速度,使程序看上去更简洁。对于注解的解释, Spring 对于注解有专⻔的解释器,对定义的
注解进⾏解析,实现对应 bean 对象的注⼊。通过 反射技术实现
public class UserService {
// 业务对象 UserDao set 注⼊(提供 set ⽅法)
private UserDao userDao ;
public void setUserDao ( UserDao userDao ) {
this . userDao = userDao ;
}
// 常⽤对象 String set 注⼊(提供 set ⽅法)
private String host ;
public void setHost ( String host ) {
this . host = host ;
}
}
xmlns:p="http://www.springframework.org/schema/p"
<?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:p = "http://www.springframework.org/schema/p"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd" >
<bean id = "userDao" class = "com.xxxx.dao.UserDao" ></bean>
<!--
p: 属性名 :="xxx" 引⼊常量值
p: 属性名 -ref:="xxx" 引⼊其他 Bean 对象的 id 属性值
-->
<bean id = "userService" class = "com.xxxx.service.UserService"
p:userDao-ref = "userDao"
p:host = "127.0.0.1" />
</beans> 6.2.1. 准备环境
1. 修改配置⽂件
2. 开启⾃动化注⼊
3. 给注⼊的 bean 对象添加注解
6.2.2. @Resource 注解
@Resource 注解实现⾃动注⼊(反射)
默认根据属性字段名称查找对应的 bean 对象 (属性字段的名称与 bean 标签的 id 属性值相等)
如果属性字段名称未找到,则会通过类型( Class 类型)查找
属性可以提供 set ⽅法,也可以不提供 set ⽅法
注解可以声明在属性级别 或 set ⽅法级别
可以设置 name 属性, name 属性值必须与 bean 标签的 id 属性值⼀致;如果设置了 name 属性值,就只
会按照 name 属性值查找 bean 对象
当注⼊接⼝时,如果接⼝只有⼀个实现则正常实例化;如果接⼝存在多个实现,则需要使⽤ name
属性指定需要被实例化的 bean 对象
代码示例
1. 默认根据属性字段名称查找对应的 bean 对象 (属性字段的名称与 bean 标签的 id 属性值相等)
<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
http://www.springframework.org/schema/context/spring-context.xsd" >
<!-- 开启⾃动化装配(注⼊) -->
<context:annotation-config/>
<bean id = "userDao" class = "com.xxxx.dao.UserDao" ></bean>
<bean id = "userService" class = "com.xxxx.service.UserService" ></bean>
/**
* @Resource 注解实现⾃动注⼊(反射)
* 默认根据属性字段名称查找对应的 bean 对象 (属性字段的名称与 bean 标签的 id 属性值相等)
*/
public class UserService {
@Resource
private UserDao userDao ; // 属性字段的名称与 bean 标签的 id 属性值相等
public void setUserDao ( UserDao userDao ) {
this . userDao = userDao ;
} 2. 如果属性字段名称未找到,则会通过类型( Class 类型)查找
3. 属性可以提供 set ⽅法,也可以不提供 set ⽅法
4. 注解可以声明在属性级别 或 set ⽅法级别
public void test () {
// 调⽤ UserDao 的⽅法
userDao . test ();
}
}
/**
* @Resource 注解实现⾃动注⼊(反射)
* 如果属性字段名称未找到,则会通过类型( Class 类型)查找
*/
public class UserService {
@Resource
private UserDao ud ; // 当在配置⽂件中属性字段名( ud )未找到,则会查找对应的
class UserDao 类型)
public void setUd ( UserDao ud ) {
this . ud = ud ;
}
public void test () {
// 调⽤ UserDao 的⽅法
ud . test ();
}
}
/**
* @Resource 注解实现⾃动注⼊(反射)
* 属性可以提供 set ⽅法,也可以不提供 set ⽅法
*/
public class UserService {
@Resource
private UserDao userDao ; // 不提供 set ⽅法
public void test () {
// 调⽤ UserDao 的⽅法
userDao . test ();
}
}
/**
* @Resource 注解实现⾃动注⼊(反射)
* 注解可以声明在属性级别 或 set ⽅法级别
*/ 5. 可以设置 name 属性, name 属性值必须与 bean 标签的 id 属性值⼀致;如果设置了 name 属性值,就
只会按照 name 属性值查找 bean 对象
6. 当注⼊接⼝时,如果接⼝只有⼀个实现则正常实例化;如果接⼝存在多个实现,则需要使⽤ name
属性指定需要被实例化的 bean 对象
定义接⼝类 IUserDao.java
定义接⼝实现类 UserDao01.java
public class UserService {
private UserDao userDao ;
@Resource // 注解也可设置在 set ⽅法上
public void setUserDao ( UserDao userDao ) {
this . userDao = userDao ;
}
public void test () {
// 调⽤ UserDao 的⽅法
userDao . test ();
}
}
/**
* @Resource 注解实现⾃动注⼊(反射)
* 可以设置 name 属性, name 属性值必须与 bean id 属性值⼀致;
* 如果设置了 name 属性值,就只会按照 name 属性值查找 bean 对象
*/
public class UserService {
@Resource ( name = "userDao" ) // name 属性值与配置⽂件中 bean 标签的 id 属性值⼀致
private UserDao ud ;
public void test () {
// 调⽤ UserDao 的⽅法
ud . test ();
}
}
package com . xxxx . dao ;
/**
* 定义接⼝类
*/
public interface IUserDao {
public void test ();
} 定义接⼝实现类 UserDao02.java
XML 配置⽂件
使⽤注解 UserService.java
package com . xxxx . dao ;
/**
* 接⼝实现类
*/
public class UserDao01 implements IUserDao {
@Override
public void test (){
System . out . println ( "UserDao01..." );
}
}
package com . xxxx . dao ;
/**
* 接⼝实现类
*/
public class UserDao02 implements IUserDao {
@Override
public void test (){
System . out . println ( "UserDao02..." );
}
}
<!-- 开启⾃动化装配(注⼊) -->
<context:annotation-config/>
<bean id = "userService" class = "com.xxxx.service.UserService" ></bean>
<bean id = "userDao01" class = "com.xxxx.dao.UserDao01" ></bean>
<bean id = "userDao02" class = "com.xxxx.dao.UserDao01" ></bean> 6.2.3. @Autowired 注解
@Autowired 注解实现⾃动化注⼊:
默认通过类型( Class 类型)查找 bean 对象 与属性字段的名称⽆关
属性可以提供 set ⽅法,也可以不提供 set ⽅法
注解可以声明在属性级别 或 set ⽅法级别
可以添加 @Qualifier 结合使⽤,通过 value 属性值查找 bean 对象( value 属性值必须要设置,且值要与
bean 标签的 id 属性值对应)
1. 默认通过类型( Class 类型)查找 bean 对象 与属性字段的名称⽆关
2. 属性可以提供 set ⽅法,也可以不提供 set ⽅法
/**
* @Resource 注解实现⾃动注⼊(反射)
* 当注⼊接⼝时,如果接⼝只有⼀个实现则正常实例化;如果接⼝存在多个实现,则需要使⽤ name 属性指
定需要被实例化的 bean 对象
*/
public class UserService {
@Resource ( name = "userDao01" ) // name 属性值与其中⼀个实现类的 bean 标签的 id 属性值⼀致
private IUserDao iUserDao ; // 注⼊接⼝(接⼝存在多个实现)
public void test () {
iUserDao . test ();
}
}
/**
* @Autowired 注解实现⾃动化注⼊
* 默认通过类型( Class 类型)查找 bean 对象 与属性字段的名称⽆关
*/
public class UserService {
@Autowired
private UserDao userDao ; // 默认通过类型( Class 类型)查找 bean 对象 与属性字段的名称
⽆关
public void setUserDao ( UserDao userDao ) {
this . userDao = userDao ;
}
public void test () {
// 调⽤ UserDao 的⽅法
userDao . test ();
}
}
/**
* @Autowired 注解实现⾃动化注⼊ 3. 注解可以声明在属性级别 或 set ⽅法级别
4. 可以添加 @Qualifier 结合使⽤,通过 value 属性值查找 bean 对象( value 属性值必须要设置,且值要
bean 标签的 id 属性值对应)
* 属性可以提供 set ⽅法,也可以不提供 set ⽅法
*/
public class UserService {
@Autowired
private UserDao userDao ; // 不提供 set ⽅法
public void test () {
// 调⽤ UserDao 的⽅法
userDao . test ();
}
}
/**
* @Autowired 注解实现⾃动化注⼊
* 注解可以声明在属性级别 或 set ⽅法级别
*/
public class UserService {
private UserDao userDao ;
@Autowired // 注解可以声明在 set ⽅法级别
public void setUserDao ( UserDao userDao ) {
this . userDao = userDao ;
}
public void test () {
// 调⽤ UserDao 的⽅法
userDao . test ();
}
}
/**
* @Autowired 注解实现⾃动化注⼊
* 可以添加 @Qualifier 结合使⽤,通过 value 属性值查找 bean 对象
value 属性值必须要设置,且值要与 bean 标签的 id 属性值对应
*/
public class UserService {
@Autowired
@Qualifier ( value = "userDao" ) // value 属性值必须要设置,且值要与 bean 标签的 id 属性值对应
private UserDao userDao ;
public void test () {
userDao . test ();
}
} 推荐使⽤ @Resource 注解是属于 J2EE 的,减少了与 Spring 的耦合。
7. Spring IOC 扫描器
实际的开发中, bean 的数量⾮常多,采⽤⼿动配置 bean 的⽅式已⽆法满⾜⽣产需要, Spring 这时候同
样提供了扫描的⽅式,对扫描到的 bean 对象统⼀进⾏管理,简化开发配置,提⾼开发效率。
7.1. Spring IOC 扫描器的配置
1. 设置⾃动化扫描范围
2. 使⽤特定的注解
@Repository Dao 层)
Spring IOC 扫描器
作⽤: bean 对象统⼀进⾏管理,简化开发配置,提⾼开发效率
1 、设置⾃动化扫描的范围
如果 bean 对象未在指定包范围,即使声明了注解,也⽆法实例化
2 、使⽤指定的注解(声明在类级别) bean 对象的 id 属性默认是 类的⾸字⺟⼩写
Dao 层:
@Repository
Service 层:
@Service
Controller 层:
@Controller
任意类:
@Component
注:开发过程中建议按照指定规则声明注解
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd" >
<!-- 设置⾃动化扫描的范围 -->
<context:component-scan base-package = "com.xxxx" />
</beans> @Service Service
@Controller Controller 层 )
@Component (任意层)
7.2. Spring 模拟⽤户登录流程
7.2.1. Dao 层 (查询⽤户记录)
1. 定义 JavaBean User.java
@Repository
public class ResourceDao {
public void test () {
System . out . println ( "ResourceDao..." );
}
}
@Service
public class ResourceService {
@Resource
private ResourceDao resourceDao ; // service 层注⼊ dao 层的 bean 对象
public void test () {
System . out . println ( "ResourceService..." );
resourceDao . test ();
}
}
@Controller
public class ResourceController {
@Autowired
private ResourceService resourceService ; // Controller 层注⼊ service 层的 bean 对象
public void test () {
System . out . println ( "ResourceController..." );
resourceService . test ();
}
}
@Component
public class PropertyUtils {
public void test (){
System . out . println ( "PropertyUtils..." );
}
} 2. 编写 Dao UserDao.java
package com . xxxx . po ;
/**
* User ⽤户实体类
*/
public class User {
private String userName ; // ⽤户名称
private String userPwd ; // ⽤户密码
public String getUserName () {
return userName ;
}
public void setUserName ( String userName ) {
this . userName = userName ;
}
public String getUserPwd () {
return userPwd ;
}
public void setUserPwd ( String userPwd ) {
this . userPwd = userPwd ;
}
}
package com . xxxx . dao ;
import com . xxxx . po . User ;
import org . springframework . stereotype . Repository ;
@Repository
public class UserDao {
private final String USERNAME = "admin" ;
private final String USERPWD = "admin" ;
/**
* 通过⽤户名称查询⽤户对象
* @param userName
* @return
*/
public User queryUserByUserName ( String userName ){
User user = null ;
// 判断⽤户名称是否正确
if ( ! USERNAME . equals ( userName )){
// 如果不正确,返回 null
return null ;
} 7.2.2. Service 层 (业务逻辑处理)
1. 定义业务处理返回消息模型 MessageModel.java
2. 编写 Service UserService.java
// 如果正确,将⽤户名称和密码设置到 user 对象中
user = new User ();
user . setUserName ( USERNAME );
user . setUserPwd ( USERPWD );
return user ;
}
}
package com . xxxx . po . vo ;
/**
* 定义业务处理返回消息模型
* 封装返回结果
*/
public class MessageModel {
private Integer resultCode = 1 ; // 结果状态码 1= 成功, 0= 失败
private String resultMsg = " 操作成功! " ; // 结果提示信息
public Integer getResultCode () {
return resultCode ;
}
public void setResultCode ( Integer resultCode ) {
this . resultCode = resultCode ;
}
public String getResultMsg () {
return resultMsg ;
}
public void setResultMsg ( String resultMsg ) {
this . resultMsg = resultMsg ;
}
}
package com . xxxx . service ;
import com . xxxx . dao . UserDao1 ;
import com . xxxx . po . User ;
import com . xxxx . po . vo . MessageModel ;
import org . springframework . stereotype . Service ;
import javax . annotation . Resource ; 7.2.3. Controller 层 (接收请求)
@Service
public class UserService {
@Resource
private UserDao userDao ;
/**
* 验证⽤户登录
* @param userName
* @param userPwd
* @return
*/
public MessageModel userLoginCheck ( String userName , String userPwd ){
// 定义业务处理返回消息模型
MessageModel messageModel = new MessageModel ();
// 判断⽤户名称是否⾮空
if ( null == userName || "" . equals ( userName . trim ())){
messageModel . setResultCode ( 0 );
messageModel . setResultMsg ( " ⽤户名不能为空! " );
return messageModel ;
}
// 判断⽤户密码是否为空
if ( null == userPwd || "" . equals ( userPwd . trim ())){
messageModel . setResultCode ( 0 );
messageModel . setResultMsg ( " 密码不能为空! " );
return messageModel ;
}
// 通过⽤户名称查询⽤户对象
User user = userDao . queryUserByUserName ( userName );
// 判断⽤户对象是否为空
if ( null == user ){
messageModel . setResultCode ( 0 );
messageModel . setResultMsg ( " 该⽤户不存在! " );
return messageModel ;
}
// 如果⽤户对象不为空,判断密码是否正确
if ( ! user . getUserPwd (). equals ( userPwd )){
messageModel . setResultCode ( 0 );
messageModel . setResultMsg ( " ⽤户密码不正确! " );
return messageModel ;
}
// 登录成功
messageModel . setResultMsg ( " 登录成功! " );
return messageModel ;
}
} 1. 编写 Controller UserController.java
7.2.4. 通过 JUnit 进⾏测试
package com . xxxx . controller ;
import com . xxxx . po . vo . MessageModel ;
import com . xxxx . service . UserService1 ;
import org . springframework . stereotype . Controller ;
import javax . annotation . Resource ;
@Controller
public class UserController {
@Resource
private UserService userService ;
/**
* ⽤户登录
* @param userName
* @param userPwd
* @return
*/
public MessageModel login ( String userName , String userPwd ){
// 调⽤ Dao 层判断⽤户登录操作,返回结果
MessageModel messageModel = userService . userLoginCheck ( userName ,
userPwd );
return messageModel ;
}
}
package com . xxxx ;
import com . xxxx . controller . UserController ;
import com . xxxx . po . vo . MessageModel ;
import org . junit . Test ;
import org . springframework . context . ApplicationContext ;
import org . springframework . context . support . ClassPathXmlApplicationContext ;
public class TestLogin {
@Test
public void test () {
// 得到 Spring 容器上下⽂环境
ApplicationContext ac = new ClassPathXmlApplicationContext ( "spring.xml" );
// 得到 UserController 实例化对象
UserController userController = ( UserController ) ac . getBean ( "userController" );
// 传⼊参数调⽤ UserController 的⽅法,返回封装类
MessageModel messageModel = userController . login ( "admin" , "admin" );
System . out . println ( " 状态码: " + messageModel . getResultCode () + " ,提示信息: " +
messageModel . getResultMsg ()); 8. Bean 的作⽤域与⽣命周期
8.1. Bean 的作⽤域
默认情况下,我们从 Spring 容器中拿到的对象均是 单例 的,对于 bean 的作⽤域类型如下:
8.1.1. singleton 作⽤域
注意 : lazy-init 是懒加载 , 如果等于 true 时作⽤是指 Spring 容器启动的时候不会去实例化这个 bean, ⽽是
在程序调⽤时才去实例化 . 默认是 false Spring 容器启动时实例化 .
默认情况下,被管理的 bean 只会 IOC 容器中存在⼀个实例,对于所有获取该 Bean 的操作 Spring 容器将只
返回同⼀个 Bean
容器在启动的情况下就实例化所有 singleton bean 对象,并缓存与容器中
lazy-init 属性(懒加载)
如果为 false ,则在 IOC 容器启动时会实例化 bean 对象,默认 false
如果为 true ,则 IOC 容器启动时不会实例化 Bean 对象,在使⽤ bean 对象时才会实例化
lazy-init 设置为 false 有什么好处?
1 )可以提前发现潜在的配置问题
2 Bean 对象存在于缓存中,使⽤时不⽤再去实例化 bean ,加快程序运⾏效率
什么对象适合作为单例对象?
⼀般来说对于⽆状态或状态不可改变的对象适合使⽤单例模式。(不存在会改变对象状态的成员变
量)
⽐如: controller 层、 service 层、 dao
}
} 什么是⽆状态或状态不可改变的对象?
实际上对象状态的变化往往均是由于属性值得变化⽽引起的,⽐如 user 类 姓名属性会有变化,属性姓
名的变化⼀般会引起 user 对象状态的变化。对于我们的程序来说,⽆状态对象没有实例变量的存在,保
证了线程的安全性, service 层业务对象即是⽆状态对象。线程安全的。
8.1.2. prototype 作⽤域
通过 scope="prototype" 设置 bean 的类型 ,每次向 Spring 容器请求获取 Bean 都返回⼀个全新的 Bean ,相
对于 "singleton" 来说就是不缓存 Bean ,每次都是⼀个根据 Bean 定义创建的全新 Bean
8.1.3. Web 应⽤中的作⽤域
1. request 作⽤域
表示每个请求需要容器创建⼀个全新 Bean 。⽐如提交表单的数据必须是对每次请求新建⼀个 Bean
来保持这些表单数据,请求结束释放这些数据。
2. session 作⽤域
表示每个会话需要容器创建⼀个全新 Bean 。⽐如对于每个⽤户⼀般会有⼀个会话,该⽤户的⽤户
信息需要存储到会话中,此时可以将该 Bean 作⽤域配置为 session 级别。
3. globalSession 作⽤域
类似于 session 作⽤域,其⽤于 portlet(Portlet 是基于 Java Web 组件,由 Portlet 容器管理,并由容
器处理请求,⽣产动态内容 ) 环境的 web 应⽤。如果在⾮ portlet 环境将视为 session 作⽤域。 配置⽅式和基本的作⽤域相同,只是必须要有 web 环境⽀持,并配置相应的容器监听器或拦截器从⽽
能应⽤这些作⽤域,⽬前先熟悉概念,后续集成 web 时讲解具体使⽤,⼤家只需要知道有这些作⽤域就
可以了。
8.2. Bean 的⽣命周期
对⽐已经学过的 servlet ⽣命周期(容器启动装载并实例化 servlet 类,初始化 servlet ,调⽤ service
法,销毁 servlet )。
同样对于 Spring 容器管理的 bean 也存在⽣命周期的概念
Spring 中, Bean 的⽣命周期包括 Bean 的定义、初始化、使⽤和销毁 4 个阶段
8.2.1. Bean 的定义
Spring 中,通常是通过配置⽂档的⽅式来定义 Bean 的。
在⼀个配置⽂档中,可以定义多个 Bean
8.2.2. Bean 的初始化
默认在 IOC 容器加载时,实例化对象。
Spring bean 初始化有两种⽅式:
⽅式⼀: 在配置⽂档中通过指定 init-method 属性来完成。
⽅式⼆: 实现 org.springframework.beans.factory.InitializingBean 接⼝。
public class RoleService {
// 定义初始化时需要被调⽤的⽅法
public void init () {
System . out . println ( "RoleService init..." );
}
}
<!-- 通过 init-method 属性指定⽅法 -->
<bean id = "roleService" class = "com.xxxx.service.RoleService" init-method = "init" ></bean>
public class RoleService implements InitializingBean {
@Override
public void afterPropertiesSet () throws Exception {
System . out . println ( "RoleService init..." );
}
}
<bean id = "roleService" class = "com.xxxx.service.RoleService" ></bean> Bean 对象实例化过程是在 Spring 容器初始化时被实例化的,但也不是不可改变的,可以通过 lazy
init="true" 属性延迟 bean 对象的初始化操作,此时再调⽤ getBean ⽅法时才会进⾏ bean 的初始化操作
8.2.3. Bean 的使⽤
⽅式⼀: 使⽤ BeanFactory
⽅式⼆: 使⽤ ApplicationContext
8.2.4. Bean 的销毁
实现销毁⽅式 (Spring 容器会维护 bean 对象的管理,可以指定 bean 对象的销毁所要执⾏的⽅法 )
步骤⼀: 实现销毁⽅式 (Spring 容器会维护 bean 对象的管理,可以指定 bean 对象的销毁所要执⾏的⽅
)
步骤⼆: 通过 AbstractApplicationContext 对象,调⽤其 close ⽅法实现 bean 的销毁过程
// 得到 Spring 的上下⽂环境
BeanFactory factory = new ClassPathXmlApplicationContext ( "spring.xml" );
RoleService roleService = ( RoleService ) factory . getBean ( "roleService" );
// 得到 Spring 的上下⽂环境
ApplicationContext ac = new ClassPathXmlApplicationContext ( "spring.xml" );
RoleService roleService = ( RoleService ) ac . getBean ( "roleService" );
<bean id = "roleService" class = "com.xxxx.service.RoleService" destroy-method = "destroy" >
</bean>
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext ( "spring.xml" );
ctx . close ();
IOC/DI- 控制反转和依赖注⼊
将对象实例化的创建过程转交给外部容器( IOC 容器 充当⼯⼚⻆⾊)去负责;属性赋值的操作;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1545257.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

[大语言模型-论文精读] MoRAG - 基于多部分融合的检索增强型人体动作生成

MoRAG--Multi-Fusion Retrieval Augmented Generation for Human Motion KS Shashank, S Maheshwari, RK Sarvadevabhatla - arXiv preprint arXiv:2409.12140, 2024 MoRAG - 基于多部分融合的检索增强型人体动作生成 1. 目录 MoRAG--Multi-Fusion Retrieval Augmented Generat…

5.使用 VSCode 过程中的英语积累 - Go 菜单(每一次重点积累 5 个单词)

前言 学习可以不局限于传统的书籍和课堂&#xff0c;各种生活的元素也都可以做为我们的学习对象&#xff0c;本文将利用 VSCode 页面上的各种英文元素来做英语的积累&#xff0c;如此做有 3 大利 这些软件在我们工作中是时时刻刻接触的&#xff0c;借此做英语积累再合适不过&a…

mysql怎么让字段从1开始自增?

mysql怎么让字段从1开始自增&#xff1f; 要确保一个 AUTO_INCREMENT 字段从1开始自增&#xff0c;你需要在创建表的时候指定 AUTO_INCREMENT 的起始值为1&#xff0c; 或者在表创建之后手动设置 AUTO_INCREMENT 的值。 1.创建表时指定 当你创建表的时候&#xff0c;可以直接…

win10开机自启动方案总汇

win10开机自启动方案总汇 一、开始文件目录添加二、添加注册表启动程序三、服务启动3.1. 将程序注册为服务使用命令行创建服务设置服务启动类型启动服务 3.2. 使用 Windows 服务管理器配置服务3.3. 删除服务 四、定时任务或程序4.1 设置程序自启动&#xff08;使用任务计划程序…

读构建可扩展分布式系统:方法与实践14流处理系统

1. 流处理系统 1.1. 时间就是金钱 1.1.1. 从数据中提取有价值的知识和获得洞见的速度越快&#xff0c;就能越快地响应系统所观察的世界的变化 1.1.2. 信用卡欺诈检测 1.1.3. 网络安全中异常网络流量的捕获 1.1.4. 在支持GPS的驾驶应用程序中进行的实时路线规划 1.1.5. 社交…

误删系统引导如何恢复?如何创建系统引导?

Default Boot Device Missing or Boot Fai led.Insert Recovery Media and Hit any keyThen Select “Boot Manager’ to choose a new Boot Device or to Boot Recovery Media 一、事出原因&#xff1a; 同事强迫症格式化所有系统引导盘后&#xff0c;重装系统后无法开机问题…

cpu的运行进程

我们知道在Linux之中有一个runqueue&#xff0c; 里面有很多内容&#xff0c;但是我们只需要关心红色和蓝色的地方就行。 我们简单理解为蓝色和红色部分其实事被封装成为一个struct queue&#xff0c;然后由array管理两个结构体。 而两个封装的结构体就是cpu能完成优先又公平的…

9.创新与未来:ChatGPT的新功能和趋势【9/10】

创新与未来&#xff1a;ChatGPT的新功能和趋势 引言 在探讨人工智能的发展历程时&#xff0c;我们可以看到它已经从早期的图灵机和人工神经网络模型&#xff0c;发展到了今天能够模拟人类智能的复杂系统。人工智能的起源可以追溯到20世纪40年代&#xff0c;而它的重要里程碑包…

简单了解Redis(初识阶段)

1.认识Redis 对于Redis有一个很重要的点就是&#xff0c;它存储数据是在内存中存储的。 但是对于单机程序&#xff0c;直接通过变量存储数据的方式是更优的&#xff0c;在分布式系统下 Redis才能发挥威力 因为进程是有隔离性的&#xff0c;Redis可以基于网络&#xff0c;把进…

Lesson1 MySQL的安装(环境为CentOS云服务器)

卸载内置环境 我们初期使用root账号&#xff0c;后期再切换成普通账号 使用 ps axj | grep mysql 查看系统中是否有MySQL相关的进程 使用 systemctl stop mysqld 关停进程 使用 rpm -qa | grep mysql 查看MySQL相关的安装包 使用 rpm -qa | grep mysql | xargs yum -y remo…

计算机毕业设计非遗项目网站 登录注册搜索 评论留言资讯 前后台管理/springboot/javaWEB/J2EE/MYSQL数据库/vue前后分离小程序

遗项目网站需求&#xff0c;以下是一个基于Spring Boot、Java Web、J2EE技术栈&#xff0c;使用MySQL数据库&#xff0c;并结合Vue实现前后端分离的简要设计方案&#xff1a; 系统功能概述 ‌用户登录与注册‌&#xff1a;实现用户的注册、登录功能&#xff0c;确保用户信息的…

【Docker】解决Docker Engine stopped

解决Docker Engine stopped 解决Docker Engine stopped1.检查虚拟设置2 安装wslwindows安装wsl 解决Docker Engine stopped 在安装完docker之后不少用户会遇到Docker Engine stopped。下面就下给出解决方法让docker正常运行起来 1.检查虚拟设置 打开任务管理器查看cpu页面&a…

华为全联接大会HUAWEI Connect 2024印象(五):讯飞星火企业级智能体平台

在HC大会上&#xff0c;除了有华为自己的产品&#xff0c;还有很多合作伙伴的产品&#xff0c;今天就简单说一下讯飞星火的企业级智能体平台。讯飞星火此次在HC上有多个展台。我以前是讯飞星火的拥泵&#xff0c;在B站发过视频介绍其API的使用&#xff08;利用API访问讯飞星火认…

PR视频剪辑工具全指南:开启专业剪辑之旅

pr视频剪辑可以说是视频剪辑里的一把好手&#xff0c;就是如果你想在这方面深耕那还是掌握这个工具的使用比较方便。如果你只是刚入门&#xff0c;那也有不少可以快速帮你剪辑出片的工具。这次我介绍几款我用过的视频剪辑工具&#xff0c;助你开启视频剪辑大门。 1.福昕视频剪…

构建预测睡眠质量模型_相关性分析,多变量分析和聚类分析

数据入口&#xff1a;睡眠质量记录数据集 - Heywhale.com 本数据集目的是探究不同因素是如何影响睡眠质量和整体健康的。 数据说明 字段说明Heart Rate Variability心率变异性&#xff1a;心跳时间间隔的模拟变化Body Temperature体温&#xff1a;以摄氏度为单位的人工生成体…

深度学习(2):梯度下降

文章目录 梯度下降梯度是什么常见梯度下降算法 代码实现批量梯度下降 梯度下降 梯度是什么 类似y ax b这种单变量的函数来说&#xff0c;导数就是它的斜率&#xff0c;这种情况下可以说梯度就是导数。 但在多变量函数中&#xff0c;梯度是一个向量&#xff0c;其分量是各个…

时间序列LSTM实现

这个代码参考了时间序列预测模型实战案例(三)(LSTM)(Python)(深度学习)时间序列预测(包括运行代码以及代码讲解)_lstm预测模型-CSDN博客 结合我之前所学的lstm-seq2seq里所学习到的知识对其进行预测 import time import numpy as np import pandas as pd import torch import…

STM32F407之超声波模块使用

#include "sys.h" #include "delay.h" #include "usart.h" #include "includes.h" #include "HC_SR04.h"int main() {OS_ERR err;//错误uart_init(9600);//串口初始化//超声波初始化HC_SR04();//OS初始化 他是第一个运行的函…

Karmada新版本发布,支持联邦应用跨集群滚动升级

摘要&#xff1a;本次升级支持联邦应用跨集群滚动升级&#xff0c;使用户版本发布流程更加灵活可控&#xff1b;透明同事karmadactl 新增了多项运维能力&#xff0c;提供独特的多集群运维体验。 本文分享自华为云社区 《Karmada v1.11 版本发布&#xff01;新增应用跨集群滚动升…

nfs版本问题导致挂载失败

一、系统环境 环境版本操作系统Linux Mint 22 Wilma内核版本6.8.0-44-genericgcc 版本arm-none-linux-gnueabihf-gcc (GNU Toolchain for the A-profile Architecture 9.2-2019.12 (arm-9.10)) 9.2.1 20191025uboot 版本2020.01开发板Linux版本5.4.31 二、问题描述 内核通过…