您的位置:首页 > 其它

020_IOC

2021-08-16 00:42 666 查看

[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开发中使用

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: