Spring IOC概念
控制反转(Inversion of
Control):这是一种设计原则,用于降低代码之间的耦合度。在传统的编程模式中,对象之间的依赖关系是由对象自身创建和维护的。而在控制反转模式下,对象的创建和依赖关系的维护被交给了外部的容器或框架来管理。在Spring框架中,IOC容器负责对象的创建、配置和组装,实现了依赖注入(Dependency
Injection, DI),从而提高了代码的可重用性和可维护性。
Spring DI概念
Spring 依赖注入(Dependency Injection,简称DI)是实现控制反转(Inversion of Control,IoC)的一种技术手段。依赖注入的核心思想是将组件之间的依赖关系交由外部容器(如Spring IoC容器)在运行时动态注入,而不是在组件内部直接创建或查找依赖对象。这样做的主要好处是降低了组件之间的耦合度,提高了代码的可重用性和可维护性。
依赖注入的主要概念包括:
依赖(Dependency):组件所依赖的对象或资源,例如,一个用户服务(UserService)可能依赖于一个用户存储库(UserRepository)来访问数据库。
注入(Injection):容器将依赖对象传递给需要它的组件的过程。注入可以通过构造器、Setter方法或字段赋值的方式进行。
组件(Component):在Spring中,通常指的是被Spring IoC容器管理的Java类实例。这些组件可以是服务、数据访问对象、控制器等。
Bean:在Spring IoC容器中,组件通常被称为Beans。Spring容器负责创建、配置和管理这些Bean的生命周期。
配置元数据(Configuration Metadata):定义了Bean如何被创建和它们的依赖关系。这可以是XML配置文件、注解或Java配置类。
自动装配(Autowiring):Spring容器可以自动解析和注入Bean的依赖关系。Spring支持通过类型(byType)、名称(byName)或构造器参数(constructor)来自动装配。
依赖注入的实现方式:
构造器注入:通过构造器参数来注入依赖,这种方式是强制性的,因为构造器总是会被调用。
Setter方法注入:通过Setter方法注入依赖,这种方式是可选的,因为可以设置默认值或留空。
注解注入:使用@Autowired注解来指示Spring容器自动注入依赖。Spring还提供了@Qualifier注解来解决同名Bean的歧义问题。
字段注入:直接在字段上使用@Autowired注解,Spring容器会直接在字段上注入依赖,这种方式不推荐使用,因为它破坏了字段的封装性。
依赖注入的优点:
降低耦合度:组件不直接依赖于具体的依赖实现,而是依赖于接口或抽象类,使得代码更加模块化。
提高代码的可测试性:可以轻松地替换依赖项,进行单元测试。
增强代码的可维护性:当依赖项的实现发生变化时,不需要修改组件代码,只需调整配置。
促进重用:相同的组件可以在不同的应用上下文中重用,只需不同的配置即可。
Spring IOC的使用
spring中IOC的五个核心包
将五个核心报引入编码工具
新建实体类User并添加三个属性
package com.weavernorth.ceshi.entry;
public class User {
private int userid;
private String account;
private String password;
public int getUserid() {
return userid;
}
public void setUserid(int userid) {
this.userid = userid;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"userid=" + userid +
", account='" + account + '\'' +
", password='" + password + '\'' +
'}';
}
}
新建spring配置文件applicationContext.xml,配置文件中输入bean约束。使用spring生成一个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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.weavernorth.ceshi.entry.User">
<property name="userid" value="123"/>
<property name="account" value="root"/>
<property name="password" value="123456"/>
</bean>
</beans>
创建测试类SpringTest.java
public class SpringTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Object user = applicationContext.getBean("user");
System.out.println(user);
}
}
Spring IOC实现原理
最初的设想,通过反射去创建对象并赋值,反射实现代码
/**
* 通过反射获取对象
*/
@Test
public void f02() throws Exception {
Class<?> name = Class.forName("com.weavernorth.ceshi.entry.User");
Object user = name.newInstance();
Method setUserid = name.getMethod("setUserid", int.class);
setUserid.invoke(user,101);
Method setAccount = name.getMethod("setAccount", String.class);
setAccount.invoke(user, "root");
Method setPassword = name.getMethod("setPassword", String.class);
setPassword.invoke(user, "123456");
System.out.println(user);
}
//输出
User{userid=101, account='root', password='123456'}
spring框架实现
此处开始就是spring的实现代码了
在AbstractApplicationContext.class中的refresh()方法下ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();加载了applicationContext.xml配置文件。
refresh()方法中 包含了整个Bean的生命周期
具体实现流程图
Spring IOC的运行时序图
在IOC中的DI的运行时序图