Spring IOC

2021年04月01日 20:52 · 阅读(457) ·

开发环境

名称 版本
操作系统 Windows 10 X64
JDK JDK1.8(jdk-8u151-windows-x64)
IntelliJ IDEA IntelliJ IDEA 2018.3
Maven Maven 3.6.0
Spring 5.2.4.RELEASE

参考

Spring+SpringMVC+SpringBoot最详细完整版念安小姐姐全套视频教程【IDEA版】由浅入深&全方位讲解,一天学习Spring框架从入门到精通

Spring 框架环境搭建

1.新建 Maven 项目

Maven 配置

名称 说明 配置
Maven Home Directory Maven 安装包路径 D:\Program Files\apache-maven-3.6.0
User settings file 用户配置文件 D:\Program Files\apache-maven-3.6.0\conf\settings.xml
Local repository 本地仓库 D:\Program Files\Maven\Repository

2.调整项目环境【pom.xml】

(1)修改 JDK 版本

  1. <properties>
  2. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  3. <maven.compiler.source>1.8</maven.compiler.source>
  4. <maven.compiler.target>1.8</maven.compiler.target>
  5. </properties>

(2)修改单元测试 JUnit 版本

  1. <dependencies>
  2. <dependency>
  3. <groupId>junit</groupId>
  4. <artifactId>junit</artifactId>
  5. <version>4.12</version>
  6. <scope>test</scope>
  7. </dependency>
  8. </dependencies>

(3)build 标签中的 pluginManagement 标签

  1. <!--删除 build 标签中的 pluginManagement 标签-->
  2. <build>
  3. </build>

3.添加 Spring 框架的依赖坐标【pom.xml】

  1. <!-- 添加Spring框架的核⼼依赖-->
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-context</artifactId>
  5. <version>5.2.4.RELEASE</version>
  6. </dependency>

4.编写 Bean 对象

  1. package com.demo.spring;
  2. public class UserService {
  3. public void test(){
  4. System.out.println("Hello Spring!");
  5. }
  6. }

5.添加 Spring 配置文件

1.在项目的 src 下创建文件夹 resources(Alt+insert)
2.将 resources 标记为资源目录

3.在 src\main\resources 目录下新建 spring.xml 文件,并拷贝官网文档提供的模板内容到 xml 中。

配置 bean 到 xml 中,把对应 bean 纳入到 Spring 容器来管理 spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <!--xmlns 即 xml namespace xml使用的命名空间
  6. xmlns:xsi 即xml schema instance xml 遵守的具体规范
  7. xsi:schemaLocation 本文档 xml遵守的规范 官方指定-->
  8. <!--
  9. id:bean对象的id,唯一标识。一般是Bean对象的名称的首字母小写 class:bean对象的类路径
  10. -->
  11. <bean id="userService" class="com.demo.spring.UserService"></bean>
  12. </beans>

6.加载配置文件,获取实例化对象

  1. package com.demo.spring;
  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;
  4. public class App {
  5. public static void main(String[] args) {
  6. // 获取Spring上下文环境(加载配置文件)
  7. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
  8. // 通过getBean方法得到Spring容器中实例化好的Bean对象 (实例化Bean对象)
  9. // userService代表的是配置文件中bean标签的id属性值
  10. UserService userService = (UserService) ac.getBean("userService");
  11. // 调用方法 (使用实例化对象)
  12. userService.test();
  13. }
  14. }

运行结果

  1. Hello Spring!

SpringIOC 容器 Bean 对象实例化模拟

1.定义 Bean 属性对象

  1. package com.demo.spring;
  2. /**
  3. * bean 对象
  4. *
  5. */
  6. public class MyBean {
  7. private String id; // bean对象的id属性值
  8. private String clazz; // bean对象的类路径
  9. public MyBean() {
  10. }
  11. public MyBean(String id, String clazz) {
  12. this.id = id;
  13. this.clazz = clazz;
  14. }
  15. public String getId() {
  16. return id;
  17. }
  18. public void setId(String id) {
  19. this.id = id;
  20. }
  21. public String getClazz() {
  22. return clazz;
  23. }
  24. public void setClazz(String clazz) {
  25. this.clazz = clazz;
  26. }
  27. }

2.添加 dom4j 坐标依赖【pom.xml】

  1. <dependency>
  2. <groupId>dom4j</groupId>
  3. <artifactId>dom4j</artifactId>
  4. <version>1.6.1</version>
  5. </dependency>
  6. <!-- XPath -->
  7. <dependency>
  8. <groupId>jaxen</groupId>
  9. <artifactId>jaxen</artifactId>
  10. <version>1.1.6</version>
  11. </dependency>
  12. `

3.准备自定义配置文件

spring.xml

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <beans>
  3. <bean id="userService" class="com.demo.spring.service.UserService"></bean>
  4. <bean id="accountService" class="com.demo.spring.service.AccountService"></bean>
  5. </beans>

4.定义 Bean 工厂接口

  1. package com.demo.spring;
  2. /**
  3. * Bean 工厂接⼝定义
  4. */
  5. public interface MyFactory {
  6. // 通过id值获取对象
  7. public Object getBean(String id);
  8. }

5.定义 Bean 接口的实现类

  1. package com.demo.spring;
  2. import com.demo.spring.bean.MyBean;
  3. import com.demo.spring.factory.MyFactory;
  4. import org.dom4j.Document;
  5. import org.dom4j.DocumentException;
  6. import org.dom4j.Element;
  7. import org.dom4j.XPath;
  8. import org.dom4j.io.SAXReader;
  9. import java.net.URL;
  10. import java.util.ArrayList;
  11. import java.util.HashMap;
  12. import java.util.List;
  13. import java.util.Map;
  14. /**
  15. * 模拟Spring的实现
  16. * 1、通过构造器得到相关配置文件
  17. * 2、通过dom4j解析xml文件,得到List 存放id和class
  18. * 3、通过反射实例化得到对象 Class.forName(类的全路径).newInstance(); 通过
  19. Map<id,Class>存储
  20. * 4、得到指定的实例化对象
  21. */
  22. public class MyClassPathXmlApplicationContext implements MyFactory {
  23. private Map beans = new HashMap(); // 实例化后的对象放入map
  24. private List<MyBean> myBeans; // 存放已读取bean 配置信息
  25. /* 1、通过构造器得到相关配置文件 */
  26. public MyClassPathXmlApplicationContext(String fileName) {
  27. /* 2、通过 dom4j 解析 xml 文件,得到 List (存放id 和 class) */
  28. this.parseXml(fileName);
  29. /* 3、通过反射实例化得到对象Class.forName(类路径).newInstance(); 通过Map存储
  30. */
  31. this.instanceBean();
  32. }
  33. /**
  34. * 通过dom4j解析xml文件,得到List 存放id和class
  35. * 1、获取解析器
  36. * 2、得到配置文件的URL
  37. * 3、通过解析器解析xml文件(spring.xml)
  38. * 4、通过xpath语法,获取beans标签下的所有bean标签
  39. * 5、通过指定语法解析文档对象,返回集合
  40. * 6、判断集合是否为空,遍历集合
  41. * 7、获取标签元素中的属性
  42. * 8、得到Bean对象,将Bean对象设置到集合中
  43. * @param fileName
  44. */
  45. private void parseXml(String fileName) {
  46. // 1、获取解析器
  47. SAXReader reader = new SAXReader();
  48. // 2、得到配置文件的URL
  49. URL url = this.getClass().getClassLoader().getResource(fileName);
  50. try {
  51. // 3、通过解析器解析xml文件(spring.xml)
  52. Document document = reader.read(url);
  53. // 4、通过xpath语法,获取beans标签下的所有bean标签
  54. XPath xPath = document.createXPath("beans/bean");
  55. // 通过指定语法解析文档对象,返回集合
  56. List<Element> list = xPath.selectNodes(document);
  57. // 判断集合是否为空,遍历集合
  58. if (list != null && list.size() > 0){
  59. myBeans = new ArrayList<>();
  60. for(Element el : list) {
  61. // 获取标签元素中的属性
  62. String id = el.attributeValue("id"); // id 属性值
  63. String clazz = el.attributeValue("class"); // class 属 性 值
  64. System.out.println(el.attributeValue("id"));
  65. System.out.println(el.attributeValue("class"));
  66. // 得到Bean对象
  67. MyBean bean = new MyBean(id, clazz);
  68. // 将Bean对象设置到集合中
  69. myBeans.add(bean);
  70. }
  71. }
  72. } catch (DocumentException e){
  73. e.printStackTrace();
  74. }
  75. }
  76. /**
  77. * 通过反射实例化得到对象
  78. * Class.forName(类的全路径).newInstance();
  79. * 通过Map<id,Class>存储
  80. */
  81. private void instanceBean() {
  82. // 判断bean集合是否为空,不为空遍历得到对应Bean对象
  83. if (myBeans != null && myBeans.size() > 0){
  84. for (MyBean bean : myBeans){
  85. try {
  86. // 通过类的全路径实例化对象
  87. Object object = Class.forName(bean.getClazz()).newInstance();
  88. // 将id与实例化对象设置到map对象中
  89. beans.put(bean.getId(), object);
  90. } catch (Exception e){
  91. e.printStackTrace();
  92. }
  93. }
  94. }
  95. }
  96. /**
  97. * 通过 key 获取 map 中的指定 value
  98. * @param id
  99. * @return
  100. */
  101. @Override
  102. public Object getBean(String id){
  103. Object object = beans.get(id);
  104. return object;
  105. }
  106. }

6.测试自定义 IOC 容器

(1)创建与配置文件中对应的 Bean 对象

UserService.java

  1. package com.demo.spring.service;
  2. public class UserService {
  3. public void test(){
  4. System.out.println("UserService Test...");
  5. }
  6. }

AccountService.java

  1. package com.demo.spring.service;
  2. public class AccountService {
  3. public void test(){
  4. System.out.println("AccountService Test...");
  5. }
  6. }

(2)测试是否可以获取实例化的 Bean 对象

  1. package com.demo.spring;
  2. import com.demo.spring.factory.MyFactory;
  3. import com.demo.spring.service.AccountService;
  4. import com.demo.spring.service.UserService;
  5. public class App {
  6. public static void main(String[] args) {
  7. MyFactory factory = new MyClassPathXmlApplicationContext("spring.xml");
  8. // 得到实例化对象
  9. UserService userService = (UserService) factory.getBean("userService");
  10. userService.test();
  11. UserService userService2 = (UserService)factory.getBean("userService");
  12. System.out.println(userService+"=====" + userService2);
  13. AccountService accountService =(AccountService)factory.getBean("accountService");
  14. accountService.test();
  15. }
  16. }

运行结果

  1. userService
  2. com.demo.spring.service.UserService
  3. accountService
  4. com.demo.spring.service.AccountService
  5. UserService Test...
  6. com.demo.spring.service.UserService@53e25b76=====com.demo.spring.service.UserService@53e25b76
  7. AccountService Test...

Spring IOC 配置文件加载

1.Spring 配置文件加载

spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <bean id="userService" class="com.demo.spring.service.UserService"></bean>
  7. </beans>

根据相对路径加载资源

  1. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");

根据绝对路径加载资源(了解)

  1. ApplicationContext ac = new FileSystemXmlApplicationContext("D:/Java/SpringStudy/src/main/resources/spring.xml");

2.Spring 多配置文件加载

Spring 框架启动时可以加载多个配置文件到环境中。

对于比较复杂的项目,可能对应的配置文件有多个,项目在启动部署时会将多个配置文件同时加载进来。

(1)service.xml

service.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <bean id="userService" class="com.demo.spring.service.UserService"></bean>
  7. </beans>

(2)dao.xml

dao.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <bean id="userDao" class="com.demo.spring.dao.UserDao"></bean>
  7. </beans>

(3)可变参数,传入多个文件名

  1. // 同时加载多个资源文件
  2. ApplicationContext ac = new ClassPathXmlApplicationContext("service.xml","dao.xml");

(4)通过总的配置文件 import 其他配置文件

spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!--导入需要包含的资源文件-->
  7. <import resource="service.xml"/>
  8. <import resource="dao.xml"/>
  9. </beans>

加载时只需加载总的配置文件即可

  1. // 加载总的资源文件
  2. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");

Spring IOC 容器 Bean 对象实例化

一.构造器实例化

注:通过默认构造器创建 空构造方法必须存在 否则创建失败

1.设置配置文件 spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <bean id="userService" class="com.demo.spring.service.UserService"></bean>
  7. </beans>

2.获取实例化对象

  1. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
  2. UserService userService = (UserService) ac.getBean("userService");
  3. userService.test();

二.静态工厂实例化(了解)

注:要有该工厂类及工厂方法,工厂方法为静态的

1.定义静态工厂类

  1. package com.demo.spring.factory;
  2. import com.demo.spring.service.UserService;
  3. /**
  4. * 定义静态工厂类
  5. */
  6. public class StaticFactory {
  7. /**
  8. * 定义对应的静态方法,返回实例化对象
  9. * @return
  10. */
  11. public static UserService createUserService(){
  12. return new UserService();
  13. }
  14. }

2.设置配置文件 spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!--静态工厂-->
  7. <bean id="userService"
  8. class="com.demo.spring.factory.StaticFactory" factory-method="createUserService">
  9. </bean>
  10. </beans>

3.获取实例化对象

  1. package com.demo.spring;
  2. import com.demo.spring.service.UserService;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. public class App {
  6. public static void main(String[] args) {
  7. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
  8. UserService userService = (UserService) ac.getBean("userService");
  9. userService.test();
  10. }
  11. }

运行结果

  1. UserService Test...

当我们指定 Spring 使用静态方法来创建 Bean 实例时,Spring 将先解析配置文件,并根据配置文件指定的信息,通过反射调用静态工厂类的静态工厂方法,并将该静态方法的返回值作为 Bean 实例,在这个过程中,Spring 不再负责创建 Bean 实例,Bean 实例是由用户提供的静态工厂法提供的。

三.实例化工厂实例化(了解)

注:
工厂方法为非静态方法
需要配置工厂 bean,并在业务 bean 中配置 factory-bean,factory-method 属性

1.定义工厂类

  1. package com.demo.spring.factory;
  2. import com.demo.spring.service.UserService;
  3. /**
  4. * 定义工厂类
  5. */
  6. public class InstanceFactory {
  7. /**
  8. * 定义方法,返回实例化对象
  9. * @return
  10. */
  11. public UserService createUserService(){
  12. return new UserService();
  13. }
  14. }

2.设置配置文件 spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!--
  7. 实例化工厂
  8. 1.定义实例化工厂bean
  9. 2.引用工厂bean 指定工厂创建方法(方法为非静态)
  10. -->
  11. <bean id="instanceFactory" class="com.demo.spring.factory.InstanceFactory">
  12. </bean>
  13. <bean id="userService"
  14. factory-bean="instanceFactory"
  15. factory-method="createUserService">
  16. </bean>
  17. </beans>

3.获取实例化对象

  1. package com.demo.spring;
  2. import com.demo.spring.service.UserService;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. public class App {
  6. public static void main(String[] args) {
  7. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
  8. UserService userService = (UserService) ac.getBean("userService");
  9. userService.test();
  10. }
  11. }

运行结果

  1. UserService Test...

Spring 三种实例化 Bean 的方式比较

方式一:通过 bean 的缺省构造函数创建,当各 个bean 的业务逻辑相互比较独⽴的时候或者和外界
关联较少的时候可以使用。
方式二:利用静态 factory 方法创建,可以统一管理各个 bean 的创建,如各个 bean 在创建之前需要
相同的初始化处理,则可用这个 factory 方法险进行统一的处理等等。
方式三:利用实例化 factory 方法创建,即将 factory 方法也作为了业务 bean 来控制,1 可用于集成
其他框架的 bean 创建管理方法,2 能够使 bean 和 factory 的⻆⾊互换。

开发中项目一般使用一种方式实例化 bean,项目开发基本采用第一种方式,交给 Spring 托管,使用
时直接拿来使用即可。另外两种了解。

Spring IOC 注入

手动实例化与外部引入

  1. package com.demo.spring.service;
  2. import com.demo.spring.dao.UserDao;
  3. public class UserService {
  4. UserDao dao = new UserDao();
  5. }
  1. package com.demo.spring.service;
  2. import com.demo.spring.dao.UserDao;
  3. public class UserService {
  4. UserDao dao;
  5. public UserService(UserDao dao){
  6. this.dao = dao;
  7. }
  8. }

对比发现:代码二中对于 UserDao 对象的创建并没有像代码一那样主动的去实例化,而是通过带参方法形
式将 UserDao 传入过来,从而实现 UserService 对 UserDao 类的依赖。

而实际创建对象的幕后对象即是交给了外部来创建。

一.Spring IOC 手动装配(注入)

Spring 支持的注入方式共有四种:set 注入、构造器注入、静态工厂注入、实例化工厂注入。

1.set 方法注入

注:
属性字段需要提供 set 方法
四种方式,推荐使用 set 方法注入

(1)业务对象 JavaBean

属性字段提供 set 方法

  1. package com.demo.spring.service;
  2. import com.demo.spring.dao.UserDao;
  3. public class UserService {
  4. // 业务对象UserDao set注入(提供set方法)
  5. private UserDao userDao;
  6. public void setUserDao(UserDao userDao){
  7. this.userDao = userDao;
  8. }
  9. }

配置文件的 bean 标签设置 property 标签

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!--
  7. IOC通过property标签手动装配(注入):
  8. Set方法注入
  9. name:bean对象中属性字段的名称
  10. ref:指定bean标签的id属性值
  11. -->
  12. <bean id="userDao" class="com.demo.spring.dao.UserDao"></bean>
  13. <bean id="userService" class="com.demo.spring.service.UserService">
  14. <!--业务对象 注入-->
  15. <property name="userDao" ref="userDao"/>
  16. </bean>
  17. </beans>

(2)常用对象和基本类型

属性字段提供 set 方法

  1. package com.demo.spring.service;
  2. public class UserService {
  3. // 常用对象String set注入(提供set方法)
  4. private String host;
  5. public void setHost(String host){
  6. this.host = host;
  7. }
  8. // 基本类型Integer set注入(提供set方法)
  9. private Integer port;
  10. public void setPort(Integer port){
  11. this.port = port;
  12. }
  13. }

配置文件的 bean 标签设置 property 标签

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!--
  7. IOC通过property标签手动装配(注入):
  8. Set方法注入
  9. name:bean对象中属性字段的名称
  10. value:具体的值(基本类型 常用对象|日期 集合)
  11. -->
  12. <bean id="userService" class="com.demo.spring.service.UserService">
  13. <!--常用对象String 注入-->
  14. <property name="host" value="127.0.0.1"/>
  15. <!--基本类型注入-->
  16. <property name="port" value="8080"/>
  17. </bean>
  18. </beans>

(3)集合类型和属性对象

属性字段提供 set 方法

  1. package com.demo.spring.service;
  2. import java.util.List;
  3. import java.util.Map;
  4. import java.util.Properties;
  5. import java.util.Set;
  6. public class UserService {
  7. // List集合 set注入(提供set方法)
  8. public List<String> list;
  9. public void setList(List<String> list){
  10. this.list = list;
  11. }
  12. // Set集合 set注入(提供set方法)
  13. private Set<String> set;
  14. public void setSet(Set<String> set){
  15. this.set = set;
  16. }
  17. // Map set注入(提供set方法)
  18. private Map<String,Object> map;
  19. public void setMap(Map<String, Object> map){
  20. this.map = map;
  21. }
  22. // Properties set注入(提供set方法)
  23. private Properties properties;
  24. public void setProperties(Properties properties){
  25. this.properties = properties;
  26. }
  27. }

配置文件的 bean 标签设置 property 标签

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!--
  7. IOC通过property标签手动装配(注入): Set方法注入
  8. name:bean对象中属性字段的名称
  9. value:具体的值(基本类型 常用对象|日期 集合)
  10. -->
  11. <!--List集合 注入-->
  12. <property name="list">
  13. <list>
  14. <value>上海</value>
  15. <value>北京</value>
  16. <value>杭州</value>
  17. </list>
  18. </property>
  19. <!--Set集合注入-->
  20. <property name="set">
  21. <set>
  22. <value>上海SH</value>
  23. <value>北京BJ</value>
  24. <value>杭州HZ</value>
  25. </set>
  26. </property>
  27. <!--Map注入-->
  28. <property name="map">
  29. <map>
  30. <entry>
  31. <key><value>周杰伦</value></key>
  32. <value>我是如此相信</value>
  33. </entry>
  34. <entry>
  35. <key><value>林俊杰</value></key>
  36. <value>可惜没如果</value>
  37. </entry>
  38. <entry>
  39. <key><value>陈奕迅</value></key>
  40. <value>十年</value>
  41. </entry>
  42. </map>
  43. </property>
  44. <!--Properties注入-->
  45. <property name="properties">
  46. <props>
  47. <prop key="上海">东方明珠</prop>
  48. <prop key="北京">天安门</prop>
  49. <prop key="杭州">西湖</prop>
  50. </props>
  51. </property>
  52. </beans>

测试代码

1.spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!--
  7. IOC通过property标签手动装配(注入):
  8. Set方法注入
  9. name:bean对象中属性字段的名称
  10. ref:指定bean标签的id属性值
  11. value:具体的值(基本类型 常用对象|日期 集合)
  12. -->
  13. <bean id="userDao" class="com.demo.spring.dao.UserDao"></bean>
  14. <bean id="userService" class="com.demo.spring.service.UserService">
  15. <!--业务对象 注入-->
  16. <property name="userDao" ref="userDao"/>
  17. <!--常用对象String 注入-->
  18. <property name="host" value="192.168.1.109"/>
  19. <!--基本类型注入-->
  20. <property name="port" value="8080"/>
  21. <!--List集合 注入-->
  22. <property name="list">
  23. <list>
  24. <value>上海</value>
  25. <value>北京</value>
  26. <value>杭州</value>
  27. </list>
  28. </property>
  29. <!--Set集合注入-->
  30. <property name="set">
  31. <set>
  32. <value>上海SH</value>
  33. <value>北京BJ</value>
  34. <value>杭州HZ</value>
  35. </set>
  36. </property>
  37. <!--Map注入-->
  38. <property name="map">
  39. <map>
  40. <entry>
  41. <key><value>周杰伦</value></key>
  42. <value>我是如此相信</value>
  43. </entry>
  44. <entry>
  45. <key><value>林俊杰</value></key>
  46. <value>可惜没如果</value>
  47. </entry>
  48. <entry>
  49. <key><value>陈奕迅</value></key>
  50. <value>十年</value>
  51. </entry>
  52. </map>
  53. </property>
  54. <!--Properties注入-->
  55. <property name="properties">
  56. <props>
  57. <prop key="上海">东方明珠</prop>
  58. <prop key="北京">天安门</prop>
  59. <prop key="杭州">西湖</prop>
  60. </props>
  61. </property>
  62. </bean>
  63. </beans>

2.UserService

  1. package com.demo.spring.service;
  2. import com.demo.spring.dao.UserDao;
  3. import java.util.List;
  4. import java.util.Map;
  5. import java.util.Properties;
  6. import java.util.Set;
  7. public class UserService {
  8. // 业务对象UserDao set注入(提供set方法)
  9. private UserDao userDao;
  10. public void setUserDao(UserDao userDao) { this.userDao = userDao; }
  11. // 常用对象String set注入(提供set方法)
  12. private String host;
  13. public void setHost(String host) { this.host = host; }
  14. // 基本类型Integer set注入(提供set方法)
  15. private Integer port;
  16. public void setPort(Integer port) { this.port = port; }
  17. // List集合 set注入(提供set方法)
  18. public List<String> list;
  19. public void setList(List<String> list){
  20. this.list = list;
  21. }
  22. // List集合输出
  23. public void printList() { list.forEach(s -> System.out.println(s)); }
  24. // Set集合 set注入(提供set方法)
  25. private Set<String> set;
  26. public void setSet(Set<String> set){
  27. this.set = set;
  28. }
  29. // Set集合输出
  30. public void printSet() { set.forEach(s -> System.out.println(s)); }
  31. // Map set注入(提供set方法)
  32. private Map<String,Object> map;
  33. public void setMap(Map<String, Object> map){
  34. this.map = map;
  35. }
  36. // Map输出
  37. public void printMap() { map.forEach((k,v) -> System.out.println(k + "," + v)); }
  38. // Properties set注入(提供set方法)
  39. private Properties properties;
  40. public void setProperties(Properties properties){
  41. this.properties = properties;
  42. }
  43. // Properties输出
  44. public void printProperties(){ properties.forEach((k,v) -> System.out.println(k + ","+ v )); }
  45. public void test(){
  46. System.out.println("UserService Test...");
  47. userDao.test();
  48. System.out.println("Host:" + host + ",port:" + port);
  49. // List集合
  50. printList();
  51. // Set集合
  52. printSet();
  53. // Map
  54. printMap();
  55. // Properties
  56. printProperties();
  57. }
  58. }

3.UserDao

  1. package com.demo.spring.dao;
  2. public class UserDao {
  3. public void test(){
  4. System.out.println("UserDao Test...");
  5. }
  6. }

4.App

  1. package com.demo.spring;
  2. import com.demo.spring.service.UserService;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. public class App {
  6. public static void main(String[] args) {
  7. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
  8. UserService userService = (UserService) ac.getBean("userService");
  9. userService.test();
  10. }
  11. }

运行结果

  1. UserService Test...
  2. UserDao Test...
  3. Host192.168.1.109port8080
  4. 上海
  5. 北京
  6. 杭州
  7. 上海SH
  8. 北京BJ
  9. 杭州HZ
  10. 周杰伦,我是如此相信
  11. 林俊杰,可惜没如果
  12. 陈奕迅,十年
  13. 上海,东方明珠
  14. 北京,天安门
  15. 杭州,西湖

2.构造器注入

注:提供带参构造器

(1)单个 Bean 对象作为参数

Java 代码

  1. package com.demo.spring.service;
  2. import com.demo.spring.dao.UserDao;
  3. public class UserService {
  4. private UserDao userDao; // JavaBean 对 象
  5. public UserService(UserDao userDao) {
  6. this.userDao = userDao;
  7. }
  8. public void test(){
  9. System.out.println("UserService Test...");
  10. userDao.test();
  11. }
  12. public UserService(){}
  13. }

Spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!--
  7. IOC通过构造器注入:
  8. 通过constructor-arg标签进行注入
  9. name: 属 性 名 称
  10. ref:指定bean标签的id属性值
  11. -->
  12. <bean id="userDao" class="com.demo.spring.dao.UserDao" ></bean>
  13. <bean id="userService" class="com.demo.spring.service.UserService">
  14. <constructor-arg name="userDao" ref="userDao"></constructor-arg>
  15. </bean>
  16. </beans>

App

  1. package com.demo.spring;
  2. import com.demo.spring.service.UserService;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. public class App {
  6. public static void main(String[] args) {
  7. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
  8. UserService userService = (UserService) ac.getBean("userService");
  9. userService.test();
  10. }
  11. }

运行结果

  1. UserService Test...
  2. UserDao Test...

(2)多个 Bean 对象作为参数

Java 代码

  1. package com.demo.spring.dao;
  2. public class AccountDao {
  3. public void test(){
  4. System.out.println("AccountDao Test...");
  5. }
  6. }
  1. package com.demo.spring.dao;
  2. public class UserDao {
  3. public void test(){
  4. System.out.println("UserDao Test...");
  5. }
  6. }
  1. package com.demo.spring.service;
  2. import com.demo.spring.dao.AccountDao;
  3. import com.demo.spring.dao.UserDao;
  4. public class UserService {
  5. private UserDao userDao; // JavaBean 对象
  6. private AccountDao accountDao;
  7. public UserService(UserDao userDao, AccountDao accountDao) {
  8. this.userDao = userDao;
  9. this.accountDao = accountDao;
  10. }
  11. public void test(){
  12. System.out.println("UserService Test...");
  13. userDao.test();
  14. accountDao.test();
  15. }
  16. public UserService(){}
  17. }

Spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!--
  7. IOC通过构造器注入:
  8. 通过constructor-arg标签进行注入
  9. name: 属 性 名 称
  10. ref:指定bean标签的id属性值
  11. -->
  12. <bean id="userDao" class="com.demo.spring.dao.UserDao" ></bean>
  13. <bean id="accountDao" class="com.demo.spring.dao.AccountDao" ></bean>
  14. <bean id="userService" class="com.demo.spring.service.UserService">
  15. <constructor-arg name="userDao" ref="userDao"></constructor-arg>
  16. <constructor-arg name="accountDao" ref="accountDao"></constructor-arg>
  17. </bean>
  18. </beans>
  1. package com.demo.spring;
  2. import com.demo.spring.service.UserService;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. public class App {
  6. public static void main(String[] args) {
  7. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
  8. UserService userService = (UserService) ac.getBean("userService");
  9. userService.test();
  10. }
  11. }

运行结果

  1. UserService Test...
  2. UserDao Test...
  3. AccountDao Test...

(3)Bean 对象和常用对象作为参数

Java 代码

  1. package com.demo.spring.service;
  2. import com.demo.spring.dao.AccountDao;
  3. import com.demo.spring.dao.UserDao;
  4. public class UserService {
  5. private UserDao userDao; // JavaBean 对象
  6. private AccountDao accountDao;
  7. private String uname; // 字符串类型
  8. public UserService(UserDao userDao, AccountDao accountDao, String uname) {
  9. this.userDao = userDao;
  10. this.accountDao = accountDao;
  11. this.uname = uname;
  12. }
  13. public void test(){
  14. System.out.println("UserService Test...");
  15. userDao.test();
  16. accountDao.test();
  17. System.out.println("uname:" + uname);
  18. }
  19. public UserService(){}
  20. }

Spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!--
  7. IOC通过构造器注入:
  8. 通过constructor-arg标签进行注入
  9. name: 属 性 名 称
  10. ref:指定bean标签的id属性值
  11. value:基本类型 常用对象的值
  12. index:构造器中参数的下标,从0开始-->
  13. <bean id="userDao" class="com.demo.spring.dao.UserDao" ></bean>
  14. <bean id="accountDao" class="com.demo.spring.dao.AccountDao" ></bean>
  15. <bean id="userService" class="com.demo.spring.service.UserService">
  16. <constructor-arg name="userDao" ref="userDao"></constructor-arg>
  17. <constructor-arg name="accountDao" ref="accountDao"></constructor-arg>
  18. <constructor-arg name="uname" value="admin"></constructor-arg>
  19. </bean>
  20. </beans>

App.java

  1. package com.demo.spring;
  2. import com.demo.spring.service.UserService;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. public class App {
  6. public static void main(String[] args) {
  7. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
  8. UserService userService = (UserService) ac.getBean("userService");
  9. userService.test();
  10. }
  11. }

运行结果

  1. UserService Test...
  2. UserDao Test...
  3. AccountDao Test...
  4. unameadmin

(4)循环依赖问题

循环问题产生的原因:Bean 通过构造器注入,之间彼此相互依赖对方导致 bean 无法实例化

Java 代码

  1. package com.demo.spring.service;
  2. public class AccountService {
  3. private RoleService roleService;
  4. public AccountService(RoleService roleService) {
  5. this.roleService = roleService;
  6. }
  7. public void test(){
  8. System.out.println("AccountService Test...");
  9. }
  10. }
  1. package com.demo.spring.service;
  2. public class RoleService {
  3. private AccountService accountService;
  4. public RoleService(AccountService accountService) {
  5. this.accountService = accountService;
  6. }
  7. public void test(){
  8. System.out.println("RoleService Test...");
  9. }
  10. }

spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!--
  7. 如果多个bean对象中互相注入,则会出现循环依赖的问题
  8. 可以通过set方法注入解决
  9. -->
  10. <bean id="accountService" class="com.demo.spring.service.AccountService">
  11. <constructor-arg name="roleService" ref="roleService"/>
  12. </bean>
  13. <bean id="roleService" class="com.demo.spring.service.RoleService">
  14. <constructor-arg name="accountService" ref="accountService"/>
  15. </bean>
  16. </beans>

App.java

  1. package com.demo.spring;
  2. import com.demo.spring.service.AccountService;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. public class App {
  6. public static void main(String[] args) {
  7. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
  8. AccountService userService = (AccountService) ac.getBean("accountService");
  9. userService.test();
  10. }
  11. }

运行结果

  1. 四月 06, 2021 10:04:35 下午 org.springframework.context.support.AbstractApplicationContext refresh
  2. 警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'accountService' defined in class path resource [spring.xml]: Cannot resolve reference to bean 'roleService' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'roleService' defined in class path resource [spring.xml]: Cannot resolve reference to bean 'accountService' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'accountService': Requested bean is currently in creation: Is there an unresolvable circular reference?
  3. Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'accountService' defined in class path resource [spring.xml]: Cannot resolve reference to bean 'roleService' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'roleService' defined in class path resource [spring.xml]: Cannot resolve reference to bean 'accountService' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'accountService': Requested bean is currently in creation: Is there an unresolvable circular reference?

(5)如何解决:将构造器注入改为 set 方法注入

Java 代码

  1. package com.demo.spring.service;
  2. public class AccountService {
  3. private RoleService roleService;
  4. //public AccountService(RoleService roleService) {
  5. // this.roleService = roleService;
  6. //}
  7. public void setRoleService(RoleService roleService) {
  8. this.roleService = roleService; }
  9. public void test(){
  10. System.out.println("AccountService Test...");
  11. }
  12. }
  1. package com.demo.spring.service;
  2. public class RoleService {
  3. private AccountService accountService;
  4. //public RoleService(AccountService accountService) {
  5. // this.accountService = accountService;
  6. //}
  7. public void setAccountService(AccountService accountService) {
  8. this.accountService = accountService; }
  9. public void test(){
  10. System.out.println("RoleService Test...");
  11. }
  12. }

spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!--
  7. 如果多个bean对象中互相注入,则会出现循环依赖的问题
  8. 可以通过set方法注入解决
  9. -->
  10. <!--<bean id="accountService" class="com.demo.spring.service.AccountService">-->
  11. <!--<constructor-arg name="roleService" ref="roleService"/>-->
  12. <!--</bean>-->
  13. <!--<bean id="roleService" class="com.demo.spring.service.RoleService">-->
  14. <!--<constructor-arg name="accountService" ref="accountService"/>-->
  15. <!--</bean>-->
  16. <!--修改为set方法注入-->
  17. <bean id="accountService" class="com.demo.spring.service.AccountService">
  18. <property name="roleService" ref="roleService"/>
  19. </bean>
  20. <bean id="roleService" class="com.demo.spring.service.RoleService">
  21. <property name="accountService" ref="accountService"/>
  22. </bean>
  23. </beans>

App.java

  1. package com.demo.spring;
  2. import com.demo.spring.service.AccountService;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. public class App {
  6. public static void main(String[] args) {
  7. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
  8. AccountService service = (AccountService) ac.getBean("accountService");
  9. service.test();
  10. }
  11. }

运行结果

  1. AccountService Test...

3.静态工厂注入

(1)定义工厂类

  1. package com.demo.spring.dao;
  2. public class TypeDao {
  3. }
  1. package com.demo.spring.factory;
  2. import com.demo.spring.dao.TypeDao;
  3. /**
  4. * 定义工厂类
  5. */
  6. public class InstanceFactory {
  7. public TypeDao createTypeDao()
  8. {
  9. return new TypeDao();
  10. }
  11. }
  1. package com.demo.spring.service;
  2. import com.demo.spring.dao.TypeDao;
  3. public class TypeService {
  4. private TypeDao typeDao;
  5. public void setTypeDao(TypeDao typeDao) {
  6. this.typeDao = typeDao;
  7. }
  8. public void test() {
  9. System.out.println("TypeService Test...");
  10. }
  11. }

(2)spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <bean id="typeService" class="com.xxxx.service.TypeService">
  7. <property name="typeDao" ref="typeDao"/>
  8. </bean>
  9. <!--
  10. 实例化工厂注入:
  11. 实例化工厂注入也是借助set方法注入,只是被注入的bean对象的实例化是通过实例化工厂实例
  12. 化的
  13. -->
  14. <bean id="instanceFactory" class="com.demo.spring.factory.InstanceFactory">
  15. </bean>
  16. <bean id="typeDao" factory-bean="instanceFactory" factory-method="createTypeDao">
  17. </bean>
  18. </beans>

重点掌握 set 注入和构造器注入,工厂方式了解即可。实际开发中基本使用 set 方式注入 bean

注入方式的选择

开发项目中 set 方式注入首选

使用构造注入可以在构建对象的同时一并完成依赖关系的建⽴,对象一建⽴则所有的一切也就准备好了,但如果要建⽴的对象关系很多,使用构造器注入会在构建函数上留下一⻓串的参数,且不易记忆,这时使用 Set 注入会是个不错的选择。

使用Set注入可以有明确的名称,可以了解注入的对象会是什么,像 setXXX()这样的名称会比记忆 Constructor 上某个参数的位置代表某个对象更好。

p 名称空间的使用

spring2.5 以后,为了简化 setter 方法属性注入,引用 p名称空间的概念,可以将⼦元素,简化为元素
属性配置。

1.属性字段提供 set 方法

  1. package com.demo.spring.service;
  2. import com.demo.spring.dao.UserDao;
  3. public class UserService {
  4. // 业务对象UserDao set注入(提供set方法)
  5. private UserDao userDao;
  6. public void setUserDao(UserDao userDao) {
  7. this.userDao = userDao;
  8. }
  9. // 常用对象String set注入(提供set方法)
  10. private String host;
  11. public void setHost(String host) {
  12. this.host = host;
  13. }
  14. public void test(){
  15. System.out.println("UserService test...");
  16. System.out.println("host:"+host);
  17. }
  18. }

2.在配置文件 spring.xml 引入 p 名称空间

  1. xmlns:p="http://www.springframework.org/schema/p"
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:p="http://www.springframework.org/schema/p"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. https://www.springframework.org/schema/beans/spring-beans.xsd">
  7. <bean id="userDao" class="com.demo.spring.dao.UserDao"></bean>
  8. <!--
  9. p:属性名:="xxx" 引入常量值
  10. p:属性名-ref:="xxx" 引入其他Bean对象的id属性值
  11. -->
  12. <bean id="userService" class="com.demo.spring.service.UserService"
  13. p:userDao-ref="userDao"
  14. p:host="127.0.0.1" />
  15. </beans>

3.App

  1. package com.demo.spring;
  2. import com.demo.spring.service.UserService;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. public class App {
  6. public static void main(String[] args) {
  7. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
  8. UserService service = (UserService) ac.getBean("userService");
  9. service.test();
  10. }
  11. }

运行结果

  1. UserService test...
  2. host:127.0.0.1

二.Spring IOC 自动装配(注入)

注解方式注入 Bean

对于 bean 的注入,除了使用 xml 配置以外,可以使用注解配置。注解的配置,可以简化配置文件,
提⾼开发的速度,使程序看上去更简洁。对于注解的解释,Spring 对于注解有专门的解释器,对定义的
注解进行解析,实现对应 bean 对象的注入。通过反射技术实现。

准备环境

(1)修改配置文件 spring.xml

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:context="http://www.springframework.org/schema/context"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd
  6. http://www.springframework.org/schema/context
  7. http://www.springframework.org/schema/context/spring-context.xsd">

(2)开启自动化注入

  1. <!--开启自动化装配(注入)-->
  2. <context:annotation-config />
  3. <bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
  4. <bean id="userService" class="com.xxxx.service.UserService"></bean>

(3)公共类

  1. package com.demo.spring.dao;
  2. public class UserDao {
  3. public void test(){
  4. System.out.println("UserDao Test...");
  5. }
  6. }

加载类 main 方法

  1. package com.demo.spring;
  2. import com.demo.spring.service.UserService;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. public class App {
  6. public static void main(String[] args) {
  7. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
  8. UserService service = (UserService) ac.getBean("userService");
  9. service.test();
  10. }
  11. }

(4)给注入的 bean 对象添加注解

@Resource 注解

@Resource 注解实现自动注入(反射)
● 默认根据属性字段名称查找对应的 bean 对象 (属性字段的名称与bean标签的id属性值相等)
● 如果属性字段名称未找到,则会通过类型(Class 类型)查找
● 属性可以提供 set 方法,也可以不提供 set 方法
● 注解可以声明在属性级别 或 set 方法级别
● 可以设置 name 属性,name 属性值必须与 bean 标签的 id 属性值一致;如果设置了 name 属性值,就只会按照 name 属性值查找 bean 对象
● 当注入接⼝时,如果接口只有一个实现则正常实例化;如果接⼝存在多个实现,则需要使用 name 属性指定需要被实例化的 bean 对象

代码示例

(1)默认根据属性字段名称查找对应的 bean 对象

(属性字段的名称与 bean 标签的 id 属性值相等)

  1. package com.demo.spring.service;
  2. import com.demo.spring.dao.UserDao;
  3. import javax.annotation.Resource;
  4. /**
  5. * @Resource注解实现自动注入(反射)
  6. * 默认根据属性字段名称查找对应的bean对象 (属性字段的名称与 bean 标签的 id 属性值相等)
  7. */
  8. public class UserService {
  9. @Resource
  10. private UserDao userDao; // 属性字段的名称与bean标签的id属性值相等
  11. public void setUserDao(UserDao userDao) {
  12. this.userDao = userDao;
  13. }
  14. public void test() {
  15. // 调用UserDao的方法
  16. userDao.test();
  17. }
  18. }

App main 方法运行结果

  1. UserDao Test...

(2)如果属性字段名称未找到,则会通过类型(Class 类型)查找

  1. /**
  2. * @Resource注解实现自动注入(反射)
  3. * 如果属性字段名称未找到,则会通过类型(Class类型)查找
  4. */
  5. public class UserService {
  6. @Resource
  7. private UserDao ud; // 当在配置文件中属性字段名(ud)未找到,则会查找对应的 class(UserDao类型)
  8. public void setUd(UserDao ud) {
  9. this.ud = ud;
  10. }
  11. public void test() {
  12. // 调用UserDao的方法
  13. ud.test();
  14. }
  15. }

App main 方法运行结果

  1. UserDao Test...

(3)属性可以提供 set 方法,也可以不提供 set 方法

  1. /**
  2. * @Resource注解实现自动注入(反射)
  3. * 属性可以提供set方法,也可以不提供set方法
  4. */
  5. public class UserService {
  6. @Resource
  7. private UserDao userDao; // 不提供 set 方法
  8. public void test() {
  9. // 调用 UserDao 的方法
  10. userDao.test();
  11. }
  12. }

App main 方法运行结果

  1. UserDao Test...

(4)注解可以声明在属性级别或 set 方法级别

  1. /**
  2. * @Resource注解实现自动注入(反射)
  3. * 注解可以声明在属性级别 或 set方法级别
  4. */
  5. public class UserService {
  6. private UserDao userDao;
  7. @Resource // 注解也可设置在set方法上
  8. public void setUserDao(UserDao userDao) {
  9. this.userDao = userDao;
  10. }
  11. public void test() {
  12. // 调用UserDao的方法
  13. userDao.test();
  14. }
  15. }

App main 方法运行结果

  1. UserDao Test...

(5)可以设置 name 属性

name 属性值必须与 bean 标签的 id 属性值一致;如果设置了 name 属性值,就只会按照 name 属性值查找 bean 对象

  1. /**
  2. * @Resource注解实现自动注入(反射)
  3. * 可以设置name属性,name属性值必须与bean的id属性值一致;
  4. * 如果设置了name属性值,就只会按照name属性值查找bean对象
  5. */
  6. public class UserService {
  7. @Resource(name = "userDao") // name属性值与配置文件中bean标签的id属性值一致
  8. private UserDao ud;
  9. public void test() {
  10. // 调用UserDao的方法
  11. ud.test();
  12. }
  13. }

App main 方法运行结果

  1. UserDao Test...

注入接口

当注入接口时,如果接口只有一个实现则正常实例化;

如果接口存在多个实现,则需要使用 name 属性指定需要被实例化的 bean 对象

定义接口类 IUserDao.java

  1. package com.demo.spring.idao;
  2. /**
  3. * 定义接口类
  4. */
  5. public interface IUserDao
  6. {
  7. void test();
  8. }

定义接口实现类 UserDao01.java

  1. package com.demo.spring.dao;
  2. import com.demo.spring.idao.IUserDao;
  3. public class UserDao01 implements IUserDao {
  4. @Override
  5. public void test(){
  6. System.out.println("UserDao01 Test...");
  7. }
  8. }

定义接口实现类 UserDao02.java

  1. package com.demo.spring.dao;
  2. import com.demo.spring.idao.IUserDao;
  3. public class UserDao02 implements IUserDao {
  4. @Override
  5. public void test(){
  6. System.out.println("UserDao02 Test...");
  7. }
  8. }

XML 配置文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. https://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context.xsd">
  9. <!--开启自动化装配(注入)-->
  10. <context:annotation-config />
  11. <bean id="userService" class="com.demo.spring.service.UserService"></bean>
  12. <bean id="userDao01" class="com.demo.spring.dao.UserDao01"></bean>
  13. <bean id="userDao02" class="com.demo.spring.dao.UserDao02"></bean>
  14. </beans>

使用注解 UserService.java

  1. package com.demo.spring.service;
  2. import com.demo.spring.idao.IUserDao;
  3. import javax.annotation.Resource;
  4. /**
  5. * @Resource注解实现自动注入(反射)
  6. * 当注入接口时,如果接口只有一个实现则正常实例化;
  7. * 如果接口存在多个实现,则需要使用 name 属性指定需要被实例化的 bean 对象
  8. */
  9. public class UserService {
  10. @Resource(name = "userDao01") // name 属性值与其中一个实现类的 bean 标签的 id 属性值一致
  11. private IUserDao iUserDao; // 注入接口(接口存在多个实现)
  12. public void test() {
  13. iUserDao.test();
  14. }
  15. }

App main 方法运行结果

  1. UserDao01 Test...

@Autowired 注解

@Autowired注解实现自动化注入:
● 默认通过类型(Class类型)查找bean对象 与属性字段的名称无关
● 属性可以提供 set 方法,也可以不提供 set 方法
● 注解可以声明在属性级别或 set 方法级别
● 可以添加 @Qualifier 结合使用,通过 value 属性值查找 bean 对象(value 属性值必须要设置,且值要与 bean 标签的 id 属性值对应)

(1)默认通过类型(Class类型)查找 bean 对象与属性字段的名称无关

  1. package com.demo.spring.service;
  2. import com.demo.spring.dao.UserDao;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. /**
  5. * @Autowired注解实现自动化注入
  6. * 默认通过类型(Class类型)查找bean对象 与属性字段的名称无关
  7. */
  8. public class UserService {
  9. @Autowired
  10. private UserDao userDao; // 默认通过类型(Class类型)查找bean对象与属性字段的名称无关
  11. public void setUserDao(UserDao userDao) {
  12. this.userDao = userDao;
  13. }
  14. public void test() {
  15. // 调用UserDao的方法
  16. userDao.test();
  17. }
  18. }

App main 方法运行结果

  1. UserDao Test...

(2)属性可以提供 set 方法,也可以不提供 set 方法

  1. package com.demo.spring.service;
  2. import com.demo.spring.dao.UserDao;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. /**
  5. * @Autowired注解实现自动化注入
  6. * 属性可以提供set方法,也可以不提供set方法
  7. */
  8. public class UserService {
  9. @Autowired
  10. private UserDao userDao; // 不提供set方法
  11. public void test() {
  12. // 调用UserDao的方法
  13. userDao.test();
  14. }
  15. }

App main 方法运行结果

  1. UserDao Test...

(3)注解可以声明在属性级别或 set 方法级别

  1. package com.demo.spring.service;
  2. import com.demo.spring.dao.UserDao;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. /**
  5. * @Autowired注解实现自动化注入
  6. * 注解可以声明在属性级别 或 set方法级别
  7. */
  8. public class UserService {
  9. private UserDao userDao;
  10. @Autowired// 注解可以声明在set方法级别
  11. public void setUserDao(UserDao userDao) {
  12. this.userDao = userDao;
  13. }
  14. public void test() {
  15. // 调用UserDao的方法
  16. userDao.test();
  17. }
  18. }

App main 方法运行结果

  1. UserDao Test...

(4)可以添加 @Qualifier 结合使用

通过 value 属性值查找 bean 对象(value 属性值必须要设置,且值要与 bean 标签的 id 属性值对应)

  1. package com.demo.spring.service;
  2. import com.demo.spring.dao.UserDao;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.beans.factory.annotation.Qualifier;
  5. /**
  6. * @Autowired注解实现自动化注入
  7. * 可以添加 @Qualifier 结合使用,通过 value 属性值查找 bean 对象
  8. value 属性值必须要设置,且值要与 bean 标签的 id 属性值对应
  9. */
  10. public class UserService {
  11. @Autowired
  12. @Qualifier(value="userDao") // value 属性值必须要设置,且值要与 bean 标签的 id 属性值对应
  13. private UserDao userDao;
  14. public void test() {
  15. userDao.test();
  16. }
  17. }

App main 方法运行结果

  1. UserDao Test...

推荐使用 @Resource 注解是属于 J2EE 的,减少了与 Spring 的耦合。

Spring IOC 扫描器

实际的开发中,bean 的数量非常多,采用手动配置 bean 的方式已无法满足生产需要,Spring 这时候同样提供了扫描的方式,对扫描到的 bean 对象统一进行管理,简化开发配置,提高开发效率。

SpringIOC 扫描器的配置

  1. Spring IOC 扫描器
  2. 作用:bean 对象统一进行管理,简化开发配置,提高开发效率
  3. 1、设置自动化扫描的范围
  4. 如果 bean 对象未在指定包范围,即使声明了注解,也无法实例化
  5. 2、使用指定的注解(声明在类级别)
  6. bean 对象的 id 属性默认是 类的首字母小写
  7. Dao层:@Repository
  8. Service层:@Service
  9. Controller层:@Controller
  10. 任意类:@Component
  11. 注:开发过程中建议按照指定规则声明注解

(1)设置自动化扫描范围

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. https://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context.xsd">
  9. <!-- 设置自动化扫描的范围 -->
  10. <context:component-scan base-package="com.demo.spring"/>
  11. </beans>

(2)使用特定的注解

@Repository(Dao层)

  1. @Repository
  2. public class ResourceDao {
  3. public void test() {
  4. System.out.println("ResourceDao...");
  5. }
  6. }

@Service(Service层 )

  1. @Service
  2. public class ResourceService {
  3. @Resource
  4. private ResourceDao resourceDao; // service层注入dao层的bean对象
  5. public void test() {
  6. System.out.println("ResourceService...");
  7. resourceDao.test();
  8. }
  9. }

@Controller(Controller 层 )

  1. @Controller
  2. public class ResourceController {
  3. @Autowired
  4. private ResourceService resourceService; // Controller层注入service层的 bean对象
  5. public void test() {
  6. System.out.println("ResourceController...");
  7. resourceService.test();
  8. }
  9. }

@Component(任意层)

  1. @Component
  2. public class PropertyUtils {
  3. public void test(){
  4. System.out.println("PropertyUtils...");
  5. }
  6. }

Spring 模拟用户登录流程

一.Dao层(查询用户记录)

1.定义 JavaBean User.java

  1. package com.demo.spring.po;
  2. /** *
  3. * User 用户实体类
  4. *
  5. **/
  6. public class User {
  7. private String userName; // 用户名称
  8. private String userPwd; // 用户密码
  9. public String getUserName() {
  10. return userName;
  11. }
  12. public void setUserName(String userName) {
  13. this.userName = userName;
  14. }
  15. public String getUserPwd() {
  16. return userPwd;
  17. }
  18. public void setUserPwd(String userPwd) {
  19. this.userPwd = userPwd;
  20. }
  21. }

2.编写 Dao 层 UserDao.java

  1. package com.demo.spring.dao;
  2. import com.demo.spring.po.User;
  3. import org.springframework.stereotype.Repository;
  4. @Repository
  5. public class UserDao {
  6. private final String USERNAME = "admin";
  7. private final String USERPWD = "admin";
  8. /** * 通过用户名称查询用户对象
  9. * * @param userName
  10. * * @return
  11. */
  12. public User queryUserByUserName(String userName){
  13. User user = null;
  14. // 判断用户名称是否正确
  15. if(!USERNAME.equals(userName)){
  16. // 如果不正确,返回null
  17. return null;
  18. } // 如果正确,将用户名称和密码设置到user对象中
  19. user = new User();
  20. user.setUserName(USERNAME);
  21. user.setUserPwd(USERPWD);
  22. return user;
  23. }
  24. }

二.编写 Service 层 UserService.java

  1. package com.demo.spring.model;
  2. public class MessageModel {
  3. Integer resultCode;
  4. String resultMsg;
  5. public void setResultCode(Integer resultCode){
  6. this.resultCode = resultCode;
  7. }
  8. public Integer getResultCode(){
  9. return resultCode;
  10. }
  11. public void setResultMsg(String resultMsg){
  12. this.resultMsg = resultMsg;
  13. }
  14. public String getResultMsg(){
  15. return resultMsg;
  16. }
  17. }
  1. package com.demo.spring.service;
  2. import com.demo.spring.dao.UserDao;
  3. import com.demo.spring.model.MessageModel;
  4. import com.demo.spring.po.User;
  5. import org.springframework.stereotype.Service;
  6. import javax.annotation.Resource;
  7. /**
  8. * @Autowired注解实现自动化注入
  9. * 可以添加 @Qualifier 结合使用,通过 value 属性值查找 bean 对象
  10. value 属性值必须要设置,且值要与 bean 标签的 id 属性值对应
  11. */
  12. @Service
  13. public class UserService {
  14. @Resource
  15. private UserDao userDao;
  16. /** * 验证用户登录
  17. * @param userName
  18. * @param userPwd
  19. * @return
  20. */
  21. public MessageModel userLoginCheck(String userName, String userPwd){
  22. // 定义业务处理返回消息模型
  23. MessageModel messageModel = new MessageModel();
  24. // 判断用户名称是否非空
  25. if(null == userName || "".equals(userName.trim())){
  26. messageModel.setResultCode(0);
  27. messageModel.setResultMsg("用户名不能为空!");
  28. return messageModel;
  29. }
  30. // 判断用户密码是否为空
  31. if(null == userPwd || "".equals(userPwd.trim())){
  32. messageModel.setResultCode(0);
  33. messageModel.setResultMsg("密码不能为空!");
  34. return messageModel;
  35. }
  36. // 通过用户名称查询用户对象
  37. User user = userDao.queryUserByUserName(userName);
  38. // 判断用户对象是否为空
  39. if(null == user){
  40. messageModel.setResultCode(0);
  41. messageModel.setResultMsg("该用户不存在!");
  42. return messageModel;
  43. }
  44. // 如果用户对象不为空,判断密码是否正确
  45. if(!user.getUserPwd().equals(userPwd)){
  46. messageModel.setResultCode(0 );
  47. messageModel.setResultMsg("用户密码不正确!");
  48. return messageModel;
  49. }
  50. // 登录成功
  51. messageModel.setResultCode(200);
  52. messageModel.setResultMsg("登录成功!");
  53. return messageModel;
  54. }
  55. }

三.Controller层(接收请求)

  1. package com.demo.spring.controller;
  2. import com.demo.spring.model.MessageModel;
  3. import com.demo.spring.service.UserService;
  4. import org.springframework.stereotype.Controller;
  5. import javax.annotation.Resource;
  6. @Controller
  7. public class UserController {
  8. @Resource
  9. private UserService userService;
  10. /** * 用户登录
  11. * @param userName
  12. * @param userPwd
  13. * @return
  14. */
  15. public MessageModel login(String userName, String userPwd){
  16. // 调用Dao层判断用户登录操作,返回结果
  17. MessageModel messageModel = userService.userLoginCheck(userName, userPwd);
  18. return messageModel;
  19. }
  20. }

四.Controller层(接收请求)

  1. package com.demo.spring;
  2. import com.demo.spring.controller.UserController;
  3. import com.demo.spring.model.MessageModel;
  4. import org.springframework.context.ApplicationContext;
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;
  6. public class App {
  7. public static void main(String[] args) {
  8. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
  9. // 得到UserController实例化对象
  10. UserController userController = (UserController) ac.getBean("userController");
  11. // 传入参数调用UserController的方法,返回封装类
  12. MessageModel messageModel= userController.login("admin", "admin");
  13. System.out.println("状态码:" + messageModel.getResultCode().toString() + ",提示信息 :" + messageModel.getResultMsg());
  14. }
  15. }

运行结果

  1. 状态码:200,提示信息 :登录成功!

Bean 的作用域与生命周期

Bean 的作用域

默认情况下,我们从 Spring 容器中拿到的对象均是单例的,对于 bean 的作用域类型如下

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 层业务对象即是无状态对象。线程安全的。

2.prototype 作用域

通过 scope=”prototype” 设置 bean 的类型 ,每次向 Spring 容器请求获取 Bean 都返回一个全新的 Bean,相对于 “singleton” 来说就是不缓存 Bean,每次都是一个根据 Bean 定义创建的全新 Bean。

3.Web 应用中的作用域

1.request 作用域表示每个请求需要容器创建一个全新 Bean。比如提交表单的数据必须是对每次请求新建一个 Bean 来保持这些表单数据,请求结束释放这些数据。

2.session 作用域 表示每个会话需要容器创建一个全新 Bean。比如对于每个用户一般会有一个会话,该用户的用户 信息需要存储到会话中,此时可以将该 Bean 作用域配置为 session 级别。

3.globalSession 作用域类似于 session 作用域,其用于 portlet(Portlet是基于 Java 的 Web 组件,由 Portlet 容器管理,并由 容器处理请求,生产动态内容)环境的 web 应用。如果在非 portlet 环境将视为 session 作用域。

配置方式和基本的作用域相同,只是必须要有 web 环境支持,并配置相应的容器监听器或拦截器从而能应用这些作用域,目前先熟悉概念,后续集成 web 时讲解具体使用,大家只需要知道有这些作用域就可以了。

Bean 的生命周期

对比已经学过的 servlet 生命周期(容器启动装载并实例化 servlet 类,初始化 servlet,调用 service 方法,销毁 servlet)。

同样对于 Spring 容器管理的 bean 也存在生命周期的概念。

在 Spring 中,Bean 的生命周期包括 Bean 的定义、初始化、使用和销毁 4 个阶段。

1.Bean 的定义

在 Spring 中,通常是通过配置文档的方式来定义 Bean 的。

在一个配置文档中,可以定义多个 Bean。

2.Bean 的初始化

默认在 IOC 容器加载时,实例化对象。

Spring bean 初始化有两种方式:

方式一:在配置文档中通过指定 init-method 属性来完成。

  1. public class RoleService {
  2. // 定义初始化时需要被调用的方法
  3. public void init() {
  4. System.out.println("RoleService init...");
  5. }
  6. }
  1. <!-- 通过init-method属性指定方法 -->
  2. <bean id="roleService" class="com.demo.spring.service.RoleService" init-method="init"></bean>

方式二: 实现 org.springframework.beans.factory.InitializingBean 接口。

  1. public class RoleService implements InitializingBean {
  2. @Override
  3. public void afterPropertiesSet() throws Exception {
  4. System.out.println("RoleService init...");
  5. }
  6. }
  1. <bean id="roleService" class="com.demo.spring.service.RoleService" ></bean>

Bean 对象实例化过程是在 Spring 容器初始化时被实例化的,但也不是不可改变的,可以通过 lazyinit=”true” 属性延迟 bean 对象的初始化操作,此时再调用 getBean 方法时才会进行 bean 的初始化操作。

3.Bean 的使用

方式一 :使用 BeanFactory

  1. // 得到Spring的上下文环境
  2. BeanFactory factory = new ClassPathXmlApplicationContext("spring.xml");
  3. RoleService roleService = (RoleService) factory.getBean("roleService");

方式二:使用 ApplicationContext

  1. // 得到Spring的上下文环境
  2. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
  3. RoleService roleService = (RoleService) ac.getBean("roleService");

4.Bean 的销毁

实现销毁方式(Spring 容器会维护 bean 对象的管理,可以指定 bean 对象的销毁所要执行的方法)。

步骤一:实现销毁方式(Spring 容器会维护 bean 对象的管理,可以指定 bean 对象的销毁所要执行的方法)

  1. <bean id="roleService" class="com.demo.spring.service.RoleService" destroymethod="destroy">
  2. </bean>

步骤二:通过 AbstractApplicationContext 对象,调用其 close 方法实现 bean 的销毁过程

  1. AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
  2. ctx.close();
  1. IOC/DI-控制反转和依赖注人
  2. 将对象实例化的创建过程转交给外部容器(IOC 容器充当工厂角色)去负责;
  3. 属性赋值的操作;