Spring--IOC基于XML管理bean
创始人
2024-01-20 20:29:46

IOC容器

IOC思想

IOC:Inversion of Control 即反转控制

  1. 获取资源的传统方式
    自己做饭:买菜、洗菜、择菜、改刀、炒菜,全过程参与,费时费力,必须清楚了解资源创建整个过程中的全部细节且熟练掌握。
    在应用程序中的组件需要获取资源时,传统的方式是组件主动的从容器中获取所需要的资源,在这样的模式下开发人员往往需要知道在具体容器中特定资源的获取方式,增加了学习成本,同时降低了开发效率。

  2. 反转控制方式获取资源
    点外卖:下单、等、吃,省时省力,不必关心资源创建过程的所有细节。
    反转控制的思想完全颠覆了应用程序组件获取资源的传统方式:反转了资源的获取方向--------改由容器主动的将资源推送给需要的组件,开发人员不需要知道容路是如何创建资源对象的,只需要提供接收资源的方式即可,极大的降低了学习成本,提高了开发的效率。这种行为也称为查找的被动开式。

  3. DI
    Dl: Dependency Injection,翻译过来是依赖注入。
    DI是IOC 的另一种表述方式:即组件以一些预先定义好的方式(例如:setter 方法)接受来自于容器的资源注入。相对于IOC而言,这种表述更直接。

所以结论是:IOC就是一种反转控制的思想,而DI是对IOC的一种具体实现

IOC容器在Spring中的实现

Spring的IOC容器就是IOC思想的一个落地的产品的实现。IOC容器中管理的组件也叫bean,在创建bean之前,首先需要创建IOC容器。Spring提供了IOC容器的两种实现方式

BeanFactory

这是IOC容器的基本实现,是Spring内部使用的接口,面向Spring本身,不提供给开发人员使用

ApplicationContext

BeanFactory的子接口,提供了更多高级特性。面向Spring的使用者,几乎所有场合都使用ApplicationContext而不是底层的BeanFactory

ApplicationContext的主要实现类

在这里插入图片描述

类型名简介
ClassPathXmlApplicationContext通过读取类路径下的XML格式的配置文件创建IOC容器对象
FileSystemXmlApplicationContext通过文件系统路径读取XML格式的配置文件创建IOC容器对象
ConfigurableApplicationContextApplicationContext的子接口,包含一些拓展方法refresh()和close(),让ApplicationContext具有启动、关闭和刷新上下文的能力
WebApplicationContext专门为web应用准备,基于web环境创建IOC容器对象,并将对象引入存入ServletContext域中

基于XML管理bean

实验一:入门案例

  1. 创建Maven Module
  2. 引入依赖
    pom.xml
    
org.springframeworkspring-context5.3.1
junitjunit4.13.2test
  1. 创建HelloWorld
package com.bijing.spring.pojo;/*** @author 毕晶* @date 2022/11/11 14:50*/
public class HelloWorld {public void sayHello(){System.out.println("hello,spring");}
}
  1. 创建Spring的配置文件
    在这里插入图片描述

  2. 在Spring的配置文件中配置bean
    application.xml





  1. 创建测试类测试
package com.bijing.spring.test;import com.bijing.spring.pojo.HelloWorld;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** @author 毕晶* @date 2022/11/11 14:56*/
public class HelloWorldTest {@Testpublic void testHelloWorld(){//获取IOC容器ApplicationContext ioc = new ClassPathXmlApplicationContext("application.xml");//获取IOC容器中的beanHelloWorld helloworld = (HelloWorld) ioc.getBean("helloworld");helloworld.sayHello();}
}

实验二:获取bean

  1. 方式一:根据id获取
  2. 方式二:根据类型获取
  3. 方式三:根据id和类型
  4. 注意:注意:根据类型获取bean时,要求IOC中有且只有一个类型匹配的bean;若没有一个类型匹配的bean,也会抛出异常
  5. 拓展

如果组件类实现了接口,根据接口类型可以获取bean吗
可以,前提是bean唯一

        //此时Student实现了Person接口,组件类是Student,所以编译类型是Person,运行类型是StudentPerson person = ioc.getBean(Person.class);System.out.println(person.getClass());//class com.bijing.spring.pojo.Student

如果一个接口有多个实现类,这些实现类都配置了bean,根据接口类型可以获取bean吗
不行,因为bean不唯一
此时,因为Person的实现类有多个,不知道用哪个实现类的bean
7. 结论
根据类型来获取bean时,在满足bean唯一的前提下,其实只是看:对象instanceof指定的类型 的返回结果,只要是true就可以认为和类型匹配,就能够获取到。即通过bean的类型,bean所继承的类的类型,bean所实现的接口类型都可以获取bean

实验三:依赖注入之setter注入

  1. 创建学生类Student
  2. 配置bean时为属性赋值
    
  1. 测试
    @Testpublic void testDI() {//获取IOC容器ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-ioc.xml");//获取beanStudent studentTwo = ioc.getBean("studentTwo", Student.class);System.out.println(studentTwo);}

实验四:依赖注入之构造器注入

  1. 在Student类中添加有参构造器
  2. 配置bean
    
  1. 测试
        Student studentThree = ioc.getBean("studentThree", Student.class);System.out.println(studentThree);

实验五:特殊值处理

  1. 字面量赋值
什么是字面量?
int a=10;
声明一个变量a,初始化为10,此时a就不代表字母a了,而是作为一个变量的名字。当我们引用a的时候,我们实际拿到的值是10
如果a是带引号的:'a',那么它现在不是一个变量,它就是代表a这个字母,这就是字面量。
  1. null值
    
  1. xml实体
    
  1. CDATA节
    ]]>

实验六:为类类型属性赋值

  1. 创建班级类Clazz
package com.bijing.spring.pojo;/*** @author 毕晶* @date 2022/11/11 19:27*/
public class Clazz {private Integer cid;private String cname;public Clazz(Integer cid, String cname) {this.cid = cid;this.cname = cname;}public Clazz() {}public Integer getCid() {return cid;}public void setCid(Integer cid) {this.cid = cid;}public String getCname() {return cname;}public void setCname(String cname) {this.cname = cname;}@Overridepublic String toString() {return "Clazz{" +"cid=" + cid +", cname='" + cname + '\'' +'}';}
}
  1. 修改Student类
package com.bijing.spring.pojo;/*** @author 毕晶* @date 2022/11/11 15:09*/
public class Student implements Person {private Integer sid;private String sname;private Integer age;private String gender;private Clazz clazz;public Student() {}public Student(Integer sid, String sname, Integer age, String gender) {this.sid = sid;this.sname = sname;this.age = age;this.gender = gender;}public Integer getSid() {return sid;}public void setSid(Integer sid) {this.sid = sid;}public String getSname() {return sname;}public void setSname(String sname) {this.sname = sname;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public Clazz getClazz() {return clazz;}public void setClazz(Clazz clazz) {this.clazz = clazz;}@Overridepublic String toString() {return "Student{" +"sid=" + sid +", sname='" + sname + '\'' +", age=" + age +", gender='" + gender + '\'' +", clazz=" + clazz +'}';}
}
  1. 方式一:引用外部已声明的bean
    
  1. 方式二:内部bean

  1. 方式三:级联属性赋值
    

实验七:为数组类型属性赋值

  1. 修改Student类
package com.bijing.spring.pojo;import java.util.Arrays;/*** @author 毕晶* @date 2022/11/11 15:09*/
public class Student implements Person {private Integer sid;private String sname;private Integer age;private String gender;private String[] hobby;private Clazz clazz;public Student() {}public Student(Integer sid, String sname, Integer age, String gender) {this.sid = sid;this.sname = sname;this.age = age;this.gender = gender;}public Integer getSid() {return sid;}public void setSid(Integer sid) {this.sid = sid;}public String getSname() {return sname;}public void setSname(String sname) {this.sname = sname;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public Clazz getClazz() {return clazz;}public void setClazz(Clazz clazz) {this.clazz = clazz;}public String[] getHobby() {return hobby;}public void setHobby(String[] hobby) {this.hobby = hobby;}@Overridepublic String toString() {return "Student{" +"sid=" + sid +", sname='" + sname + '\'' +", age=" + age +", gender='" + gender + '\'' +", hobby=" + Arrays.toString(hobby) +", clazz=" + clazz +'}';}
}
  1. 配置bean
        抽烟喝酒烫头蹦迪

实验八:为集合类型属性赋值

  1. 为List集合类型的属性赋值
    通过list标签

通过util:list
需要导入util约束

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"

  1. 为Map集合类型的属性赋值
//Student增加下面属性private Map teacherMap;
 抽烟喝酒烫头蹦迪
  1. 引用集合类型的bean
    引入util约束,使用util: list、util: map标签,具体使用见上面

实验九:p命名空间

引入约束p,应该是指property

       xmlns:p="http://www.springframework.org/schema/p"

实验十:引入外部属性文件

jdbc为例

  1. 加入依赖
    pom.xml
      mysqlmysql-connector-java8.0.30com.alibabadruid1.0.31
  1. 创建外部属性文件
    jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimeZone=UTC"
jdbc.username=root
jdbc.password=root1234
  1. 引入属性文件
    引入约束context
       xmlns:context="http://www.springframework.org/schema/context"
    
  1. 配置bean
    
  1. 测试
public class DataSourceTest {@Testpublic void testDataSource() throws SQLException {ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-datasource.xml");DruidDataSource datasource = ioc.getBean("datasource", DruidDataSource.class);DruidPooledConnection connection = datasource.getConnection();System.out.println(connection);}
}

实验十一:bean的作用域

  1. 概念
    在Spring中可以通过配置bean标签的scope来指定bean的作用域范围,各取值含义参如下表
取值含义创建对象的时机
singleton(默认)在IOC容器中,这个bean对象始终为单例IOC容器初始化
prototype这个bean在IOC容器中有多个实例获取bean时

如果在WebApplicationContext环境下还有另外两个作用域(但不常用)

取值含义
request在一个请求范围内有效
session在一次会话范围内有效
  1. 创建类Student
    就是之前使用的Student类
  2. 配置bean
  
  1. 测试
    @Testpublic void testScope() {ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-scope.xml");Student student1 = ioc.getBean("student", Student.class);Student student2 = ioc.getBean("student", Student.class);System.out.println(student1 == student2);//true说明是单例模式创建的student,是同一个对象}

实验十二:bean的生命周期

  1. 具体的生命周期过程
  • bean对象创建(调用无参构造器)
  • 给bean对象设置属性
  • bean对象初始化之前操作(由bean的后置处理器负责)
  • bean对象初始化(需在配置bean时指定初始化方法)
  • bean对象初始化之后操作(由bean的后置处理器负责)
  • bean对象就绪可以使用
  • bean对象的销毁(需要在配置bean的时候指定销毁方法)
  • IOC容器关闭
  1. 创建类User
package com.bijing.spring.pojo;/*** @author 毕晶* @date 2022/11/11 22:31*/
public class User {private Integer id;private String username;private String password;private Integer age;public User() {System.out.println("生命周期1:实例化");}public User(Integer id, String username, String password, Integer age) {this.id = id;this.username = username;this.password = password;this.age = age;}public Integer getId() {return id;}public void setId(Integer id) {System.out.println("生命周期2:依赖注入");this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +", age=" + age +'}';}public void initMethod() {System.out.println("生命周期3:初始化");}public void destroyMethod() {System.out.println("生命周期4:销毁");}
}
  1. 配置bean



  1. 测试
package com.bijing.spring.test;import com.bijing.spring.pojo.User;
import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** @author 毕晶* @date 2022/11/11 22:43*/
public class LifeCycleTest {/*** 1.实例化* 2.依赖注入* 3.初始化 要通过bean标签的init-method属性指定方法* 4.IOC容器关闭时销毁 要通过bean标签的destroy-method属性指定方法*      * 注意:* 若bean的作用域是单例时,生命周期的前三个步骤会在获取IOC容器时执行* 若bean的作用域是多例时,生命周期的前三个步骤会在获取bean时执行,销毁步骤不由ioc控制了*/@Testpublic void testLifeCycle() {//ConfigurableApplicationContext是ApplicationContext的子接口,其中拓展了刷新和关闭容器的方法//注意:1.如果是bean对象是单例模式获取的,则生命周期前三个步骤已经完成,即ioc容器创建的时候bean对象就已经创建并完成了初始化//    2.如果是多例,destroy步骤不由ioc来控制了,即ioc.close()时销毁方法不执行ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");User user = ioc.getBean(User.class);System.out.println(user);//ApplicationContext没有close方法ioc.close();}
}
  1. bean的后置处理器
    bean的后置处理器会在生命周期的初始化前后添加额外的操作,需要实现BeanPostProcessor接口,且配置到IOC容器中,需要注意的是,bean后置处理器不是单独针对某—个bean生效,而是 针对IOC容器中所有bean都会执行

创建bean的后置处理器

package com.bijing.spring.pojo.com.bijing.spring.process;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;/*** @author 毕晶* @date 2022/11/12 10:17*/
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {//此方法在bean的生命周期初始化之前执行System.out.println("此方法在bean的生命周期初始化之前执行");return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {//此方法在bean的生命周期初始化之后执行System.out.println("此方法在bean的生命周期初始化之后执行");return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}
}

配置bean的后置处理器

    

实验十三:FactoryBean

  1. 简介
    Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean,这两种Bean都被容器管理,但工厂Bean跟普通Bean不同,其返回的对象不是指定类的一个实例,其返回的是该FactoryBean的getObject方法所返回的对象。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。

  2. 创建类UserFactoryBean

package com.bijing.spring.factory;import com.bijing.spring.pojo.User;
import org.springframework.beans.factory.FactoryBean;/*** @author 毕晶* @date 2022/11/12 10:35*/
public class UserFactoryBean implements FactoryBean {@Overridepublic User getObject() throws Exception {return new User();}@Overridepublic Class getObjectType() {return User.class;}
}
  1. 配置bean
    
  1. 测试
public class FactoryBeanTest {@Testpublic void testFactoryBean() {ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-factory.xml");User user = ioc.getBean(User.class);System.out.println(user);}
}

实验十四:基于xml的自动装配

自动装配:
根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型或者接口类型属性赋值

  1. 场景模拟
    创建UserController
public class UserController {private UserService userService;//UserService会变动,不要直接写死,使用set和get方法有利于改动public UserService getUserService() {return userService;}public void setUserService(UserService userService) {this.userService = userService;}public void saveUser() {userService.saveUser();}
}
  1. 配置bean



  1. 测试
package com.bijing.spring.test;import com.bijing.spring.controller.UserController;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** @author 毕晶* @date 2022/11/12 17:13*/
public class AutowireByXmlTest {/*** 自动装配:* 根据指定的策略,在IOC容器中匹配某个bean,自动为bean中的类类型的属性或者接口类型属性赋值* 可以通过bean标签中autowire属性设置自动装配的策略* 自动装配策略:* #no,default表示不装配,即bean 中的属性不会自动匹配某个bean为属性赋值,此时属性使用默认值* #byType:根据要赋值的属性的类型,在IOC容器中匹配某个bean,为属性赋值* 注意:1.若通过类型没有找到任何一个类型匹配的bean,此时不匹配,属性使用默认值* 2.若通过类型找到了多个类型匹配的bean,此时会抛出异常:* 总结:当使用byType实现自动装配时,IOC容器中有且只有一个类型匹配的bean能够为属性赋值* #byName:将要赋值的属性的属性名作为bean的id在IOC容器中匹配某个bean为属性赋值* 当类型匹配的bean有多个时,此时可以使用byName实现自动装配*/@Testpublic void testAutowireByXml() {ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-autowire-xml.xml");UserController userController = ioc.getBean(UserController.class);userController.saveUser();}
}

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
毛笔是谁发明的 目前发现最早的... 毛笔人人都见过,现在很多中国人家里还会有那么一两枝,读小学的时候往往还都练过几天的描红,众多家长将自...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
人世界上最大的生殖器 世界最大... 1. 卡图马人——女人可随意强暴男人的民族2. 卡拉莫贾人——禁止女人穿裤子的奇特民族3. 哈扎比人...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...