IOC目录
基于XML配置方式组件管理
1. 组件(Bean)信息声明配置(IoC)
2. 组件(Bean)依赖注入配置(DI)
3. IoC容器创建和使用
4. 组件(Bean)周期方法和作用域配置
4.1 组件周期方法配置
4.2 组件作用域配置
5. 基于XML方式整合三层架构组件
IOC前言
IoC/DI概念
IoC容器
IoC 容器,负责实例化、配置和组装 bean(组件)核心容器。容器通过读取配置元数据来获取有关实例化、配置和组装组件的指令。
IoC( of )控制反转
IoC 主要是针对对象的创建和调用控制而言的,也就是说,当应用程序需要使用一个对象时,不再是应用程序直接创建该对象,而是由 IoC 容器来创建和管理,即控制权由应用程序转移到 IoC 容器中,也就是“反转”了控制权。
这种方式基本上是通过依赖查找的方式来实现的,即 IoC 容器维护着构成应用程序的对象,并负责创建这些对象。
DI ( ) 依赖注入
DI 是指在组件之间传递依赖关系的过程中,将依赖关系在容器内部进行处理,这样就不必在应用程序代码中硬编码对象之间的依赖关系,实现了对象之间的解耦合。
在 中,DI 是通过 XML 配置文件或注解的方式实现的。它提供了三种形式的依赖注入:构造函数注入、 方法注入和接口注入。
基于XML配置方式组件管理1. 组件(Bean)信息声明配置(IoC)
通过定义XML配置文件,声明组件类信息,交给 的 IoC 容器进行组件管理。
IoC 容器管理一个或多个 bean,这些 bean 的作用是提供给容器的配置元数据创建的(例如,以 XML 定义的形式)。
导入相关依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.6</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.3.1</version>
</dependency>
</dependencies>
1、基于无参数构造函数
当通过构造函数方法创建一个 bean(组件对象) 时,所有普通类都可以由 使用并与之兼容。在默认情况下,我们需要一个默认(空)构造函数。
①组件类(.java)
package com.xiaof.ioc_01;
public class HappyComponent {
//默认包含无参数构造函数
public void doWork() {
System.out.println("HappyComponent.doWork");
}
}
②xml配置文件编写 (创建携带约束的xml配置文件)
编写xml配置文件(-bean-01.xml)
标签:通过配置bean标签告诉IOC容器需要创建对象的组件信息
<bean id="happyComponent1" class="com.xiaof.ioc_01.HappyComponent"/>
<bean id="happyComponent2" class="com.xiaof.ioc_01.HappyComponent"/>
2、基于静态工厂方法实例化
①组件类(.java)
package com.xiaof.ioc_01;
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() { // 静态方法
return clientService;
}
}
②xml配置文件(-bean-01.xml)
-: 指定静态工厂方法(该方法必须是方法)
<bean id="clientService"
class="com.xiaof.ioc_01.ClientService"
factorymethod="createInstance"/>
3、基于实例工厂方法实例化(非静态)
①组件类(.java)
package com.xiaof.ioc_01;
public class ClientServiceImpl {
}
r.java
package com.xiaof.ioc_01;
public class DefaultServiceLocator {
private static ClientServiceImpl clientService = new ClientServiceImpl();
public ClientServiceImpl createClientServiceInstance() {
return clientService;
}
}
②xml配置文件(-bean-01.xml)
-bean属性:指定当前容器中工厂Bean 的名称
<bean id="defaultServiceLocator"
class="com.xiaof.ioc_01.DefaultServiceLocator"/>
<bean id="clientService2"
factory-bean="defaultServiceLocator"
factory-method="createClientServiceInstance"/>
图解IoC配置流程
2. 组件(Bean)依赖注入配置(DI)
通过配置文件,实现IoC容器中Bean之间的引用(依赖注入DI配置)。
主要涉及注入场景:基于构造函数的依赖注入和基于 的依赖注入。
1、基于构造函数的依赖注入(单个构造参数)
基于构造函数的 DI 是通过容器调用具有多个参数的构造函数来完成的,每个参数表示一个依赖项。
①组件类(.java)
package com.xiaof.ioc_02;
public class UserDao {
}
.java
package com.xiaof.ioc_02;
public class UserService {
private UserDao userDao;
public UserService(UserDao userDao) {
this.userDao = userDao;
}
}
②xml配置文件(-02.xml)
:指定构造参数和对应的值
<bean id="userDao" class="com.xiaof.ioc_02.UserDao"/>
<bean id="userService" class="com.xiaof.ioc_02.UserService">
<constructor-arg ref="userDao"/>
</bean>
2、基于构造函数的依赖注入(多构造参数解析)
①组件类(.java)
package com.xiaof.ioc_02;
public class UserService {
private UserDao userDao;
private int age;
private String name;
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public UserService(int age , String name ,UserDao userDao) {
this.age = age;
this.name = name;
this.userDao = userDao;
}
}
②xml配置文件(-02.xml)
:指定构造参数和对应的值
<bean id="userService1" class="com.xiaof.ioc_02.UserService">
<constructor-arg value="18"/>
<constructor-arg value="张三"/>
<constructor-arg ref="userDao"/>
</bean>
<bean id="userService2" class="com.xiaof.ioc_02.UserService">
<constructor-arg index="1" value="张三"/>
<constructor-arg index="0" value="18"/>
<constructor-arg index="2" ref="userDao"/>
</bean>
<bean id="userService3" class="com.xiaof.ioc_02.UserService">
<constructor-arg name="age" value="18"/>
<constructor-arg name="name" value="张三"/>
<constructor-arg name="userDao" ref="userDao"/>
</bean>
3、基于方法依赖注入
①组件类(.java)
package com.xiaof.ioc_02;
public class MovieFinder {
}
.java
package com.xiaof.ioc_02;
public class SimpleMovieLister {
private MovieFinder movieFinder;
private String movieName;
public void setMovieFinder(MovieFinder movieFinder) { // setter方法
this.movieFinder = movieFinder;
}
public void setMovieName(String movieName){
this.movieName = movieName;
}
}
②xml配置文件(-02.xml)
:给方法对应的属性赋值
<bean id="movieFinder" class="com.xiaof.ioc_02.MovieFinder"/>
<bean id="simpleMovieLister" class="com.xiaof.ioc_02.SimpleMovieLister">
<property name="movieFinder" ref="movieFinder"/>
<property name="movieName" value="霸王别姬"/>
</bean>
3. IoC容器创建和使用
将配置文件中声明组件类信息进行实例化成Bean对象和形成Bean之间的引用关系,需要声明IoC容器对象,读取配置文件ioc控制反转,实例化组件和关系维护的过程都是在IoC容器中实现的。
在test目录下新建一个测试类.java
1、容器实例化
new (...)
public class SpringIoCTest {
/**
* 创建IOC容器并读取配置文件
* 接口:BeanFactory、ApplicationContext
* 实现类:可以直接通过构造函数实例化
* ClassPathXmlApplicationContext[推荐]
* FileSystemXmlApplicationContext
* AnnotationConfigApplicationContext
* WebApplicationContext
*/
@Test
public void createIoC(){
// 方式1:实例化并指定配置文件
// 参数:String...locations:传入一个或者多个配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-01.xml","spring-03.xml");
// 方式2:先实例化,再指定配置文件,最后刷新容器触发Bean实例化动作(springmvc源码和contextLoadListener源码方式]
// 参数:String...locations:传入一个或者多个配置文件
ClassPathXmlApplicationContext applicationContext1 = new ClassPathXmlApplicationContext();
applicationContext1.setConfigLocation("spring-03.xml"); // 设置配置文件
applicationContext1.refresh(); // 触发刷新配置
}
}
2、Bean对象读取
❝包
组件类
package com.xiaof.ioc_03;
public class HappyComponent implements A{
//默认包含无参数构造函数
public void doWork() {
System.out.println("HappyComponent.doWork");
}
}
接口A
package com.xiaof.ioc_03;
public interface A {
void doWork();
}
xml配置文件(-03.xml)
<bean id="happyComponent" class="com.xiaof.ioc_03.HappyComponent"/>
❞
public class SpringIoCTest {
/**
* 在IOC容器中获取组件Bean
*/
@Test
public void getBeanFromIoC(){
// 创建ioc容器对象
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
applicationContext.setConfigLocation("spring-03.xml");
applicationContext.refresh();
// 读取ioc容器的组件
// 方案1:直接根据beanId读取即可,返回值类型是Object,需要强转[不推荐]
HappyComponent happyComponent = (HappyComponent) applicationContext.getBean("happyComponent");
// 方案2:根据beanId,同时指定bean的类型Class
HappyComponent happyComponent1 = applicationContext.getBean("happyComponent",HappyComponent.class);
// 方案3:直接根据类型获取
// TODO:根据bean的类型获取,同一个类型,在ioc容器中只能用一个bean!
// HappyComponent happyComponent2 = applicationContext.getBean(HappyComponent.class);
// TODO:ioc的配置一定是实现类,但可以根据接口类型获取值 getBean(类型) instanceof ioc容器的类型 == true
A happyComponent2 = applicationContext.getBean(A.class);
happyComponent.doWork();
System.out.println(happyComponent == happyComponent1);
System.out.println(happyComponent1 == happyComponent2);
}
}
3、返回结果
4. 组件(Bean)周期方法和作用域配置
4.1 组件周期方法配置
在组件类中定义方法,当IoC容器实例化和销毁组件对象的时候进行调用ioc控制反转,这两个方法称为生命周期方法。类似于的init/方法,可以在周期方法完成初始化和释放资源等工作。