国庆中秋特辑系列文章:
国庆中秋特辑(八)Spring Boot项目如何使用JPA
国庆中秋特辑(七)java软件工程师常见20道编程面试题
国庆中秋特辑(六)大学生常见30道宝藏编程面试题
国庆中秋特辑(五)MySQL如何性能调优?下篇
国庆中秋特辑(四)MySQL如何性能调优?上篇
国庆中秋特辑(三)使用生成对抗网络(GAN)生成具有节日氛围的画作,深度学习框架 TensorFlow 和 Keras 来实现
国庆中秋特辑(二)浪漫祝福方式 使用生成对抗网络(GAN)生成具有节日氛围的画作
国庆中秋特辑(一)浪漫祝福方式 用循环神经网络(RNN)或长短时记忆网络(LSTM)生成祝福诗词
Spring IOC(Inversion of Control,控制反转)是 Spring 框架的核心特性之一,它通过解耦和依赖注入的方式简化了应用的组件开发和维护。在 Spring 框架中,有两个主要的 IOC 容器实现:一个是基于 XML 配置文件的 BeanFactory,另一个是基于 Java 类的 ApplicationContext。
一、工作原理
这里我们以一个简单的案例来分析 Spring IOC 的工作原理。假设我们有一个简单的 Java 程序,需要用到一个数据持久层(DataA***ess)和一个业务层(Service)。
首先,我们需要创建一个 Spring 配置文件(如:applicationContext.xml),在这个文件中,我们将 DataA***ess 和 Service 作为 Bean 定义:
<bean id="dataA***ess" class="***.example.DataA***essImpl"/>
<bean id="service" class="***.example.ServiceImpl" property="dataA***ess">
<property name="dataA***ess" ref="dataA***ess"/>
</bean>
在这个配置文件中,我们定义了两个 Bean:一个是 DataA***ess 类型的 Bean,另一个是 Service 类型的 Bean。Service Bean 中的 dataA***ess 属性通过 ref 属性指定为 DataA***ess Bean。
接下来,我们需要在 Java 程序中创建一个 Spring 的 IOC 容器,并从中获取 DataA***ess 和 Service Bean:
import ***.example.DataA***ess;
import ***.example.Service;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
DataA***ess dataA***ess = (DataA***ess) context.getBean("dataA***ess");
Service service = (Service) context.getBean("service");
// 使用 Service 进行业务操作
service.doSomething();
}
}
在这个 Java 程序中,我们首先创建了一个 Spring 的 IOC 容器(ApplicationContext),然后通过 getBean 方法获取了 DataA***ess 和 Service Bean。注意,由于 Service Bean 的 dataA***ess 属性是通过 ref 属性指定为 DataA***ess Bean,所以在获取 Service Bean 时,Spring 会自动将 DataA***ess Bean 注入到 Service Bean 中。
现在,我们可以通过 Service 类的 doSomething 方法来调用 DataA***ess 类的相关方法进行数据持久操作。这个过程就是 Spring IOC 的工作原理。Spring IOC 容器负责管理 Bean 的创建和管理,以及 Bean 之间的依赖关系,我们只需要关注业务逻辑的实现即可。
总结一下,Spring IOC 的核心思想是:不再由对象自己创建和管理它所依赖的对象,而是由外部(如 Spring 容器)负责注入依赖对象。这样可以大大简化对象的创建和管理,提高代码的可维护性和可扩展性。
二、具体分析
- 资源加载:Spring IOC 容器中的资源加载主要采用了模板设计模式和抽象工厂设计模式。在创建实例的托管和创建过程中,Spring 根据 XML 配置文件创建 Resource 对象,该对象中包含了 BeanDefinition 的信息。
// Resource 加载
public Resource getResourceByPath(String path) {
if (path.startsWith("/")) {
path = path.substring(1);
}
Resource[] resources = getResources();
for (Resource resource : resources) {
if (resource.getPath().equals(path)) {
return resource;
}
}
return null;
}
- BeanDefinition 的管理:Spring IOC 容器中的 BeanDefinition 是一个重要的组成部分,它用于描述 Bean 的定义,包括 Bean 的名称、类名、属性等信息。BeanDefinition 的管理主要通过 BeanDefinitionRegistry 和 BeanDefinitionReader 两个类实现。
// BeanDefinitionReader 读取 BeanDefinition
public void readBeanDefinitions(Resource resource) throws BeansException, IOException {
if (!resource.exists()) {
return;
}
try (InputStream reader = resource.getInputStream()) {
while (reader.markSupported()) {
int marker = reader.mark();
if (marker == XMLBeanDefinitionReader.ROOT_ELEMENT_START_MARKER) {
// 创建 BeanDefinitionReader 对象
BeanDefinitionReader beanDefinitionReader = new BeanDefinitionReader(this);
// 开始解析 XML 文件中的 BeanDefinition
beanDefinitionReader.parse(reader);
} else if (marker == XMLBeanDefinitionReader.ROOT_ELEMENT_END_MARKER) {
// 解析结束
break;
}
}
}
}
- Bean 的创建和管理:Spring IOC 容器中的 Bean 创建和管理主要通过 BeanFactory 类实现。BeanFactory 类包含了创建 Bean、获取 Bean、删除 Bean 等方法,它是 Spring IOC 容器的核心部分。
// BeanFactory 创建 Bean
public Object getBean(String name) throws BeansException {
// 根据 Bean 名称获取 BeanDefinition
BeanDefinition beanDefinition = getBeanDefinition(name);
// 如果 BeanDefinition 不存在,抛出异常
if (beanDefinition == null) {
throw new NoSuchBeanDefinitionException(name);
}
// 创建 Bean
Object bean = createBean(name, beanDefinition);
// 返回 Bean
return bean;
}
- 依赖注入:Spring IOC 容器中的依赖注入主要通过 DependencyAutowire 和 PropertyAutowire 两个类实现。DependencyAutowire 类用于自动注入依赖,而 PropertyAutowire 类用于自动注入属性。
// DependencyAutowire 注入依赖
public void setDependency(String propertyName, @Qualifier @Nullable String[] qualifiedClassNames) {
// 获取 BeanDefinition
BeanDefinition beanDefinition = getBeanDefinition(propertyName);
// 如果 BeanDefinition 不存在,抛出异常
if (beanDefinition == null) {
throw new NoSuchBeanDefinitionException(propertyName);
}
// 获取依赖的 Bean
@Qualifier("'" + beanDefinition.getBeanClassName() + "'")
@Autowired
Object dependency = getBeanFactory().getBean(propertyName, Object.class);
// 设置依赖
setter.setValue(this, dependency);
}
- 生命周期管理:Spring IOC 容器中的生命周期管理主要通过 Lifecycle 和 LifecycleCallback 两个接口实现。Lifecycle 接口定义了 Bean 的生命周期方法,如 start、stop 等;LifecycleCallback 接口则是一个回调接口,用于在 Bean 的生命周期方法执行前后执行特定的逻辑。
// Lifecycle 接口
public interface Lifecycle {
void start() throws BeansException;
void stop() throws BeansException;
boolean isStarted();
boolean isStopped();
void destroy() throws BeansException;
}
三、核心功能分析
由于 Spring IOC 核心代码较长,无法在这里全部展示。但我可以简要介绍一下 Spring IOC 的核心部分,并提供部分关键代码示例。
- BeanFactory 的创建:
BeanFactory 是 Spring IOC 容器的基本实现,它负责管理 Bean 的创建和管理。创建过程主要包括以下几个步骤:
- 读取 Spring 配置文件(如 applicationContext.xml),解析其中的 Bean 定义;
- 创建一个 BeanDefinitionRegistry,用于存储解析后的 BeanDefinition;
- 创建一个 BeanFactoryInstance,用于封装 BeanDefinitionRegistry 和其他 BeanFactory 的实例;
- 调用 BeanFactoryInstance 的 getObjectForBeanName 方法,根据 BeanName 获取对应的 Bean 定义;
- 通过 BeanDefinition 的 getBean 方法创建 Bean 实例;
- 将 Bean 实例添加到 BeanFactory 的 singletonObjects 中,以 BeanName 为键。
以下是创建 BeanFactory 的示例代码:
public class BeanFactoryImpl implements BeanFactory {
//... 省略其他代码...
@Override
protected void createBeanFactory(String name, BeanDefinitionRegistry registry) throws BeansException {
// 创建并初始化一个 DefaultListableBeanFactory 实例
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.setBeanDefinitionRegistry(registry);
beanFactory.setResourceA***ess(new ClassPathResource(name, getClassLoader()));
beanFactory.setEnvironment(this.environment);
beanFactory.setApplicationContextName(name);
beanFactory.setParentBeanFactory(this);
beanFactory.setSingletonObjects(new ConcurrentHashMap<String, Object>());
beanFactory.setDefaultSingletonBeanName(name);
beanFactory.registerBeanDefinition(new RootBeanDefinition(beanFactory, name));
}
}
- Bean 的生命周期:
Bean 的生命周期主要包括以下几个阶段:
- 实例化:根据 BeanDefinition 创建 Bean 实例;
- 属性填充:将 BeanDefinition 中的属性值设置到 Bean 实例上;
- 初始化:调用 Bean 的初始化方法,进行相关设置;
- 依赖注入:将 Bean 的依赖关系注入到 Bean 实例上;
- 销毁:当 Bean 没有引用时,调用 Bean 的 destroy 方法进行销毁。
以下是 Bean 生命周期的示例代码:
public class BeanFactoryImpl implements BeanFactory {
//... 省略其他代码...
@Override
protected Object createBean(String name, BeanDefinition beanDefinition, Object[] args) throws BeansException {
// 根据 BeanDefinition 创建 Bean 实例
Object bean = beanDefinition.getBean();
// 属性填充
for (PropertyValue propertyValue : beanDefinition.getPropertyValues()) {
bean = propertyValue.resolve(bean);
}
// 初始化
bean = beanDefinition.initialize(bean);
// 依赖注入
if (bean instanceof ConfigurableBeanFactory) {
((ConfigurableBeanFactory) bean).mergeBeanDefinitions(beanDefinition.getResourceDescription());
}
// 将 Bean 添加到 singletonObjects 中,以 BeanName 为键
synchronized (this.singletonObjects) {
this.singletonObjects.put(name, bean);
}
return bean;
}
}
- 依赖注入:
Spring IOC 容器通过依赖注入(Dependency Injection,DI)的方式将 Bean 的依赖关系注入到 Bean 实例上。依赖注入主要有两种方式:构造器注入和 setter 方法注入。
以下是依赖注入的示例代码:
public class BeanFactoryImpl implements BeanFactory {
//... 省略其他代码...
@Override
protected Object createBean(String name, BeanDefinition beanDefinition, Object[] args) throws BeansException {
//... 省略其他代码...
// 依赖注入
if (bean instanceof ConfigurableBeanFactory) {
((ConfigurableBeanFactory) bean).mergeBeanDefinitions(beanDefinition.getResourceDescription());
}
//... 省略其他代码...
}
}
以上是 Spring IOC 核心代码的简要分析和示例。要了解更多关于 Spring IOC 的详细信息,建议参考 Spring 官方文档和相关教程。