Spring实战 | Spring IOC不能说的秘密?

国庆中秋特辑系列文章:

国庆中秋特辑(八)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 容器)负责注入依赖对象。这样可以大大简化对象的创建和管理,提高代码的可维护性和可扩展性。

二、具体分析

  1. 资源加载: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;  
}
  1. 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;  
           }  
       }  
   }  
}
  1. 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;  
}
  1. 依赖注入: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);  
}
  1. 生命周期管理: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 的核心部分,并提供部分关键代码示例。

  1. 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));  
   }  
}
  1. 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;  
   }  
}
  1. 依赖注入:
    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 官方文档和相关教程。

转载请说明出处内容投诉
CSS教程_站长资源网 » Spring实战 | Spring IOC不能说的秘密?

发表评论

欢迎 访客 发表评论

一个令你着迷的主题!

查看演示 官网购买