• Spring之IoC


    Spring的设计理念和整体架构

    一句话概括就是:Spring是一个轻量级的、非侵入式的控制反转(IOC)和面向切面(AOP)的框架。

    设计理念:
    1. 松散耦合: Spring鼓励开发者编写松散耦合的代码,通过依赖注入和接口抽象等方式来减少组件之间的紧耦合性。这有助于提高代码的可维护性和可测试性。

    2. 依赖注入(DI): Spring的核心特性之一是依赖注入,它允许开发者将对象之间的依赖关系通过配置文件或注解来声明,而不是在代码中硬编码依赖。这使得代码更加灵活和可配置。

    3. 面向切面编程(AOP): Spring支持AOP,允许开发者定义切面和通知,以实现横切关注点的重用,如日志记录、事务管理等。

    4. 声明式事务管理: Spring提供了声明式事务管理的支持,允许将事务配置为注解或XML配置,从而简化了事务管理的实现。

    5. 模块化: Spring框架被分为多个模块,每个模块提供特定的功能,如Spring核心容器、数据访问/集成、Web开发等。这种模块化的设计使得开发者可以根据需要引入特定的功能。

    6. 轻量级容器: Spring框架本身是非常轻量级的,不需要依赖大量外部库。它提供了自己的容器,用于管理应用程序中的对象。

    主要模块:

    Spring分模块存在,除了最核心的Spring Core Container(Beans、Core、Context和SpEl)之外,其他都是可选的。

    七大主要模块:
    1. Spring Core:Spring 核⼼,它是框架最基础的部分,提供 IOC 和依赖注⼊ DI 特性。

    2. Spring Context:Spring 上下⽂容器,它是 BeanFactory 功能加强的⼀个⼦接⼝。

    3. Spring Web:它提供 Web 应⽤开发的⽀持。

    4. Spring MVC:它针对 Web 应⽤中 MVC 思想的实现。

    5. Spring DAO:提供对 JDBC 抽象层,简化了 JDBC 编码,同时,编码更具有健壮性。

    6. Spring ORM:它⽀持⽤于流⾏的 ORM 框架的整合,⽐如:Spring + Hibernate、Spring + iBatis、Spring + JDO 的整合等。

    7. Spring AOP:即⾯向切⾯编程,它提供了与 AOP 联盟兼容的编程实现。

    整体架构:

    Spring框架的整体架构是分层的,各个层次的功能被组织成不同的模块,如下所示:

    1. 核心容器(Core Container): 核心容器包括BeansCoreContextExpression Language模块,用于提供基本的IoC和DI功能。

    2. 数据访问/集成(Data Access/Integration): 这些模块包括JDBCORMJMSTransactions等,用于处理数据访问和集成外部系统。

    3. Web层(Web): Spring提供了多个Web开发相关的模块,如WebWeb-MVCWeb-Socket等,用于构建Web应用程序。

    4. AOP和Instrumentation(Aspect-Oriented Programming): 这些模块包括AOPAspectsInstrumentation等,用于支持AOP编程和性能监控。

    5. 消息(Messaging): 这些模块包括JMSAMQP等,用于处理消息传递。

    6. 测试(Testing): Spring提供了Test模块,用于编写和运行单元测试和集成测试。

    Spring IoC 

    IoC的基础概念

    IoC(Inversion of Control): IoC是一种设计原则,它反转了传统的控制流。在传统的编程中,应用程序通常负责控制对象的创建和生命周期。而在IoC中,控制权被反转,应用程序不再负责直接创建和管理对象,而是将这些职责委托给一个容器或框架。这个容器负责实例化、组装和管理对象,使得应用程序的组件更加解耦、可维护和可扩展。举个简单的例子,从前要什么自己创建,现在要什么,spring容器给。

    DI(Dependency Injection): DI是IoC的一种实现方式,它是IoC的一种具体形式。DI指的是通过将对象的依赖关系注入到对象中,而不是由对象自己创建或查找依赖关系。这可以通过构造函数注入、方法注入或属性注入来实现。DI的目的是降低组件之间的耦合性,使它们更容易被替换、测试和维护。关于DI最简单的例子就是Setter了。

    IoC的设计与实现

    Spring Ioc容器的设计中,可以看到两个主要的容器系列:简单容器BeanFactory和高级容器ApplicationContext。

    简单容器BeanFactory

    简单模拟下BeadFactory演示IoC的设计:

    1. 创建配置文件,包含BeanDefinition的信息。

      user:com.elaine.myspring.ioc.beanfactory.bean.User
    2. 创建一个BeanDefinition类,定义bean的属性。

      public class BeanDefinition {
          private String beanName;
      ​
          private Class beanClass;
      ​
          public String getBeanName() {
              return beanName;
          }
      ​
          public void setBeanName(String beanName) {
              this.beanName = beanName;
          }
      ​
          public Class getBeanClass() {
              return beanClass;
          }
      ​
          public void setBeanClass(Class beanClass) {
              this.beanClass = beanClass;
          }
      }
    3. 创建资源加载器ResourceLoader,用来加载配置文件中的配置。

      /**
       * 载入配置文件,通过BeanDefinition解析加载
       */
      public class ResourceLoader {
          public static Map getResource() {
              Map beanDefinitionMap = new HashMap<>(16);
              Properties properties = new Properties();
              try {
                  InputStream inputStream = ResourceLoader.class.getResourceAsStream("/beans.properties");
                  properties.load(inputStream);
                  // 迭代遍历配置文件
                  Iterator iterator = properties.stringPropertyNames().iterator();
                  while (iterator.hasNext()) {
                      String key = iterator.next();
                      String className = properties.getProperty(key);
                      BeanDefinition beanDefinition = new BeanDefinition();
                      beanDefinition.setBeanName(key);
                      Class clazz = Class.forName(className);
                      beanDefinition.setBeanClass(clazz);
                      // 加载资源
                      beanDefinitionMap.put(key, beanDefinition);
                  }
                  inputStream.close();
              } catch (IOException e) {
                  e.printStackTrace();
              } catch (ClassNotFoundException e) {
                  e.printStackTrace();
              }
              return beanDefinitionMap;
          }
      }
      ​
    4. 创建对象注册器BeanRegister,注册bean到container中。

      public class BeanRegister {
          // 假设所有对象都是单例的,用一个单例map缓存
          private Map singletonMap = new HashMap<>();
      ​
          /**
           * 获取单例bean
           * @param beanName
           * @return
           */
          public Object getSingletonBean(String beanName) {
              return singletonMap.get(beanName);
          }
      ​
          /**
           * 注册单例bean
           * @param beanName
           * @param bean
           */
          public void registerSingletonBean(String beanName, Object bean) {
              if(singletonMap.containsKey(beanName)) {
                  return;
              }
              singletonMap.put(beanName, bean);
          }
      }
    5. 创建对象工厂BeanFactory,初始化需要完成资源的加载,对象注册器的创建。

      public class BeanFactory {
          private BeanRegister beanRegister;
      ​
          private Map map = new HashMap<>();
      ​
          public BeanFactory(){
              // 创建bean注册器
              beanRegister = new BeanRegister();
              // 加载资源
              this.map = new ResourceLoader().getResource();
          }
      ​
          /**
           * 获取bean
           * @param beanName
           * @return
           */
          public Object getBean(String beanName) {
              Object bean = beanRegister.getSingletonBean(beanName);
              if (bean != null) {
                  return bean;
              }
              return createBean(map.get(beanName));
          }
      ​
          /**
           * 创建bean
           * @param beanDefinition
           * @return
           */
          private Object createBean(BeanDefinition beanDefinition) {
              try {
                  Object bean = beanDefinition.getBeanClass().newInstance();
                  beanRegister.registerSingletonBean(beanDefinition.getBeanName(), bean);
                  return bean;
              } catch (InstantiationException e) {
                  e.printStackTrace();
              } catch (IllegalAccessException e) {
                  e.printStackTrace();
              }
              return null;
          }
      }
    6. 测试验证。

      public class TestUser {
          @Test
          public void beanFactory() {
              BeanFactory beanFactory = new BeanFactory();
      ​
              // 第一次获取,通过反射
              User user = (User) beanFactory.getBean("user");
              user.sayHello();
      ​
              // 第二次获取,通过缓存
              User user1 = (User) beanFactory.getBean("user");
              user.sayHello();
      ​
              // 所有对象都是单例的前提下,是同一个对象
              System.out.println(user1 == user);
          }
      }
    高级容器ApplicationContext
    • ApplicationContext继承自BeanFactory,拥有更多的功能和特性,包括国际化、事件传播、资源访问等。

    • 和BeanFactory的延迟加载不同,ApplicationContext会在容器启动时就实例化和初始化所有的bean。

    • 支持更丰富的配置方式,包括XML配置、注解、java配置等,并且支持自动扫描并注册bean。

    ApplicationContext通过读取xml配置的形式获取bean:

    public class MySpringApplication {
        public static void main(String[] args) {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
            Product product = (Product) applicationContext.getBean("product");
            System.out.println(product.getId());
        }
    }
    IoC容器工作过程

    Spring 的 IOC 容器⼯作的过程,其实可以划分为两个阶段:容器启动阶段和Bean实例化阶段。

  • 相关阅读:
    【宋红康 MySQL数据库 】【高级篇】【19】多版本并发控制MVCC
    万字总结——JavaScript简单入门【值得收藏】
    什么是恶意代码?
    Vue2+Vue3基础入门到实战项目全套教程的学习笔记
    车载音频系统外置功放+主机联调实验
    使用Jenkins进行持续集成与部署
    中国人民大学与加拿大女王大学金融硕士项目——花会沿路盛开,我们未来的路也是
    AI:76-基于机器学习的智能城市交通管理
    diffuser踩坑记录
    文件对象的常用方法和属性
  • 原文地址:https://blog.csdn.net/Elaine2391/article/details/133779639