020_IOC
[toc]
学习视频地址:https://www.bilibili.com/video/BV1WE411d7Dv?share_source=copy_web
官网:https://spring.io/
官网:https://spring.io/projects/spring-framework#learn
代码:git@gitee.com:wl3pbzhyq/spring-study.git
Spring框架文档:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core
IOC理论推导
搭建环境,添加spring-webmvc依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.qing</groupId> <artifactId>spring-study</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.8</version> </dependency> </dependencies> </project>
传统业务层调用DAO层:想要使用新的UserDao实现类都需要改源码
package com.qing.service; import com.qing.dao.UserDao; import com.qing.dao.UserDaoImpl; import com.qing.dao.UserDaoMysqlImpl; import com.qing.dao.UserDaoOracleImpl; public class UserServiceImpl implements UserService { // private UserDao userDao = new UserDaoImpl(); // private UserDao userDao = new UserDaoMysqlImpl(); private UserDao userDao = new UserDaoOracleImpl(); public void getUser() { userDao.getUser(); } }
import com.qing.service.UserService; import com.qing.service.UserServiceImpl; import org.junit.jupiter.api.Test; public class MyTest { @Test public void test1() { UserService userService = new UserServiceImpl(); userService.getUser(); } }
使用set方法优化:注入动态实现值
package com.qing.service; import com.qing.dao.UserDao; import com.qing.dao.UserDaoImpl; import com.qing.dao.UserDaoMysqlImpl; import com.qing.dao.UserDaoOracleImpl; public class UserServiceImpl implements UserService { /* 使用set方法优化:注入动态实现值 */ private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void getUser() { userDao.getUser(); } }
import com.qing.dao.UserDaoMysqlImpl; import com.qing.service.UserService; import com.qing.service.UserServiceImpl; import org.junit.jupiter.api.Test; public class MyTest { @Test public void test2() { UserService userService = new UserServiceImpl(); ((UserServiceImpl) userService).setUserDao(new UserDaoMysqlImpl()); userService.getUser(); } }
上面两个代码的演化
- 上面的代码:用户的需求可能会影响我们的代码,我们需要根据用户的需求修改源代码。如果程序代码量十分大,修改一次的成本代价十分昂贵
- 上面的代码:程序是主动创建对象的,修改需求需要修改业务层代码
- 下面的代码:使用set方法注入实现类后,程序不再具有主动性,而是变成了被动的接受对象
- 这种思想,从本质上解决了问题,程序员不用再去管理对象的创建了
- 系统的耦合性大大降低,可以更加的专注于业务的实现上
- 这就是IOC的原型
IOC的本质
HelloSpring
创建实体类
package com.qing.pojo; import lombok.Data; @Data public class Hello { private String str; }
基于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"> <!--使用Spring来创建对象,在Spring这些都称为bean--> <bean id="hell0" class="com.qing.pojo.Hello"> <property name="str" value="Spring"/> </bean> </beans>
测试
import com.qing.pojo.Hello; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test01() { // 获取spring的上下文对象 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); // 获取spring创建的对象 Hello hello = (Hello) context.getBean("hello"); System.out.println(hello.toString()); } }
只需要修改配置文件,就可以调用不同的实现
<?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"> <!--使用Spring来创建对象,在Spring这些都称为bean--> <bean id="hello" class="com.qing.pojo.Hello"> <property name="str" value="Spring"/> </bean> <bean id="userDaoImpl" class="com.qing.dao.UserDaoImpl"/> <bean id="mysqlImpl" class="com.qing.dao.UserDaoMysqlImpl"/> <bean id="oracleImpl" class="com.qing.dao.UserDaoOracleImpl"/> <bean id="userServiceImpl" class="com.qing.service.UserServiceImpl"> <!-- ref : 引用spring容器中创建好的对象 val : 具体的值,基本数据类型和字符串 --> <property name="userDao" ref="userDaoImpl"/> </bean> </beans>
import com.qing.pojo.Hello; import com.qing.service.UserService; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test02() { // 获取spring的上下文对象 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); // 获取spring创建的对象 UserService userServiceImpl = (UserService) context.getBean("userServiceImpl"); userServiceImpl.getUser(); } }
<?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"> <!--使用Spring来创建对象,在Spring这些都称为bean--> <bean id="hello" class="com.qing.pojo.Hello"> <property name="str" value="Spring"/> </bean> <bean id="userDaoImpl" class="com.qing.dao.UserDaoImpl"/> <bean id="mysqlImpl" class="com.qing.dao.UserDaoMysqlImpl"/> <bean id="oracleImpl" class="com.qing.dao.UserDaoOracleImpl"/> <bean id="userServiceImpl" class="com.qing.service.UserServiceImpl"> <!-- ref : 引用spring容器中创建好的对象 val : 具体的值,基本数据类型和字符串 --> <property name="userDao" ref="mysqlImpl"/> </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="user01" class="com.qing.pojo.User01"/> </beans>
package com.qing.pojo; public class User01 { private String name; public User01() { System.out.println("无参构造"); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
import com.qing.pojo.User01; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test01() { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); } }
创建application上下文,创建后配置文件中管理的bean,点击图标spring图标,就可以跳转到配置文件
加载配置文件时,spring容器就创建了对象,而不是在调用对象时创建
import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test10() { System.out.println("加载配置文件前"); ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); System.out.println("加载配置文件后"); } }
两次获取的对象是同一个,spring容器只创建一次对象
import com.qing.pojo.User01; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test11() { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); User01 user01 = (User01) context.getBean("user01"); User01 user02 = (User01) context.getBean("user01"); System.out.println(user01 == user02); } }
使用有参构造创建对象的三种方式
下标赋值
<?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="user01" class="com.qing.pojo.User01"/> <!--第一种:下标赋值--> <bean id="user02" class="com.qing.pojo.User02"> <constructor-arg index="0" value="下标赋值"/> </bean> </beans>
import com.qing.pojo.User01; import com.qing.pojo.User02; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test12() { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); User02 user02 = (User02) context.getBean("user02"); System.out.println(user02.getName()); } }
类型赋值,不建议使用
<?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="user01" class="com.qing.pojo.User01"/> <!--第一种:下标赋值--> <bean id="user02" class="com.qing.pojo.User02"> <constructor-arg index="0" value="下标赋值"/> </bean> <!--第二章:类型赋值,不建议使用,多个同种类型时,按照顺序赋值--> <bean id="user03" class="com.qing.pojo.User03"> <constructor-arg type="java.lang.String" value="类型赋值2"/> <constructor-arg type="java.lang.String" value="类型赋值"/> </bean> </beans>
import com.qing.pojo.User01; import com.qing.pojo.User02; import com.qing.pojo.User03; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test13() { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); User03 user = (User03) context.getBean("user03"); System.out.println(user.getName()); System.out.println(user.getName2()); } }
参数名赋值,常用
<?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="user01" class="com.qing.pojo.User01"/> <!--第一种:下标赋值--> <bean id="user02" class="com.qing.pojo.User02"> <constructor-arg index="0" value="下标赋值"/> </bean> <!--第二种:类型赋值,不建议使用,多个同种类型时,按照顺序赋值--> <bean id="user03" class="com.qing.pojo.User03"> <constructor-arg type="java.lang.String" value="类型赋值2"/> <constructor-arg type="java.lang.String" value="类型赋值"/> </bean> <!--第三种:名称赋值--> <bean id="user04" class="com.qing.pojo.User04"> <constructor-arg name="name" value="名称赋值"/> </bean> </beans>
import com.qing.pojo.User01; import com.qing.pojo.User02; import com.qing.pojo.User03; import com.qing.pojo.User04; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test14() { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); User04 user = (User04) context.getBean("user04"); System.out.println(user.getName()); } }
Spring配置说明
别名:可以通过别名获取对象,原名称也可以使用
<?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="user01" class="com.qing.pojo.User01"/> <!--别名--> <alias name="user01" alias="user"/> </beans>
import com.qing.pojo.User01; import com.qing.pojo.User02; import com.qing.pojo.User03; import com.qing.pojo.User04; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test15() { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); User01 user01 = (User01) context.getBean("user01"); System.out.println(user01); User01 user02 = (User01) context.getBean("user"); System.out.println(user02); } }
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"> <!-- id : bean的唯一标识符,用来获取对象 class : bean对象所对应的全限定名:包名+类名 name : 也是别名,而且可以取多个别名,可以用不同的符号分割,常用分割符为逗号 --> <bean id="user05" class="com.qing.pojo.User05" name="u1,u2 u3;u4"/> </beans>
import com.qing.pojo.*; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test16() { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); System.out.println(context.getBean("user05")); System.out.println(context.getBean("u1")); System.out.println(context.getBean("u2")); System.out.println(context.getBean("u3")); System.out.println(context.getBean("u4")); } }
import:导入合并其他配置文件
一般用于团队开发使用,可以将多个配置文件,导入合并为一个
多个人合作开发,各自把各自的类注册到各自的配置文件,所有的配置文件合并到一个总的配置文件,使用时,可以直接使用总的配置文件
<?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="beans.xml"/> <import resource="bean1.xml"/> <import resource="bean2.xml"/> </beans>
import com.qing.pojo.*; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test17() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); } }
依赖注入-set注入
参考:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core
依赖注入
- 依赖:bean对象的创建依赖于容器
- 注入:bean对象的属性,由容器来注入
复杂实体准备
package com.qing.pojo; import java.util.*; public class Student { private String name; private Address address; private String[] books; private List<String> hobbys; private Map<String, String> card; private Set<String> gaems; private String wife; private Properties info; }
<?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="address" class="com.qing.pojo.Address"/> <bean id="student" class="com.qing.pojo.Student"> <!--普通值注入 value--> <property name="name" value="张三丰"/> <!--bean注入 ref--> <property name="address" ref="address"/> <!--数组注入 array--> <property name="books"> <array> <value>红楼梦</value> <value>西游记</value> <value>水浒传</value> </array> </property> <!--list注入 list--> <property name="hobbys"> <list> <value>听古筝</value> <value>听琵琶</value> <value>听古琴</value> </list> </property> <!--set注入 set--> <property name="gaems"> <set> <value>仙剑奇侠传四</value> <value>仙剑奇侠传五</value> </set> </property> <!--map注入 map--> <property name="card"> <map> <entry key="身份证" value="14"/> <entry key="驾驶证" value="白马"/> </map> </property> <!--null--> <property name="wife"> <null/> </property> <!--Properties--> <property name="info"> <props> <prop key="username">root</prop> <prop key="password">123456</prop> </props> </property> </bean> </beans>
测试
import com.qing.pojo.Student; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test01() { ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); Student student = (Student) context.getBean("student"); System.out.println(student.toString()); } }
依赖注入-拓展注入
参考:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core
p命名空间注入,可以直接注入属性的值,通过set注入
导入xml约束 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="user" class="com.qing.pojo.User" p:username="root" p:password="123456"/> </beans>
import com.qing.pojo.Student; import com.qing.pojo.User; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test04() { ApplicationContext context = new ClassPathXmlApplicationContext("bean-p.xml"); User user = context.getBean("user",User.class); System.out.println(user.toString()); } }
c命名空间注入,可以直接注入属性的值,通过构造器注入
导入xml约束 xmlns:c="http://www.springframework.org/schema/c"
<?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:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="user" class="com.qing.pojo.User" c:username="root" c:password="123456"/> </beans>
import com.qing.pojo.Student; import com.qing.pojo.User; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test05() { ApplicationContext context = new ClassPathXmlApplicationContext("bean-c.xml"); User user = context.getBean("user",User.class); System.out.println(user.toString()); } }
Bean的作用域
参考:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core
默认单例,也可以显式声明 scope="singleton"
<bean id="accountService" class="com.something.DefaultAccountService"/> <!-- the following is equivalent, though redundant (singleton scope is the default) --> <bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>
测试
<?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="user" class="com.qing.pojo.User" scope="singleton"> <property name="username" value="张三丰"/> <property name="password" value="123456"/> </bean> </beans>
import com.qing.pojo.Student; import com.qing.pojo.User; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test02() { ApplicationContext context = new ClassPathXmlApplicationContext("single.xml"); User user = context.getBean("user",User.class); User user1 = context.getBean("user",User.class); System.out.println(user == user1); } }
原型 scope="prototype"
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
测试
<?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="user" class="com.qing.pojo.User" scope="prototype"> <property name="username" value="张三丰"/> <property name="password" value="123456"/> </bean> </beans>
import com.qing.pojo.Student; import com.qing.pojo.User; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test03() { ApplicationContext context = new ClassPathXmlApplicationContext("prototype.xml"); User user = context.getBean("user",User.class); User user1 = context.getBean("user",User.class); System.out.println(user == user1); } }
request、session、application只在web开发中使用
- 【设计模式】IOC模式
- Spring之IOC快速入门(一)
- Spring入门IOC(一)
- [Spring3.x] 第 3 章 IOC 容器概述
- L2-020. 功夫传人 BFS
- Spring中IoC和DI的理解
- Android学习进阶和IoC
- IOC-Castle Windsor映射
- Spring IOC 的资源定位
- IOC、Spring的IOC
- 在IoC容器中装配Bean
- L2-020. 功夫传人
- Castle IOC FOR MVC 使用方法
- 舌尖上的IoC
- 简单使用 Mvc 内置的 Ioc
- 巧用App_Start文件夹启动Ninject-IOC容器
- IOC的底层过程
- Spring中的IOC
- 精通android体系架构、mvc、常见的设计模式、控制反转(ioc)
- 通过注解方式配置Spring实现Ioc