JavaRush /Java 博客 /Random-ZH /Spring框架。介绍
Marchello
第 20 级
Санкт-Петербург

Spring框架。介绍

已在 Random-ZH 群组中发布
你好!当 JavaRush 管理部门正在努力提高新水平时,我想开始撰写一系列有关 Spring 框架的培训文章。是的,我知道互联网上已经有很多关于这个主题的材料,但是,正如实践所示,它们都处于 Hello World 级别。我不想谈论如何正确放置注释,而是谈论它在“幕后”如何工作。本文面向那些已经以某种方式使用过该框架并熟悉基本概念的人。 Spring框架。 简介 - 1

初始化上下文。

那么让我们从基础开始吧。在我看来,最重要的一点是了解上下文是如何设置的以及 beans 是如何初始化的。如您所知,在Spring开始工作之前,需要对其进行配置。在远古时代,这是使用 xml 文件完成的(在某些项目中,主要是旧项目,他们至今仍在这样做)。这是此类配置文件的一个小示例:
<?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-3.0.xsd">

   <bean id="helloWorld" class="ru.javarush.HelloWorld">
       <property name="message" value="Hello World!"/>
   </bean>

</beans>
总的来说,这足以创建几个控制器并启动一个启动程序(这不会启动)。但是这个配置将如何让 Spring 工作呢?这就是事情变得有趣的地方。为了让 Spring 能够理解我们的配置,有一个XmlBeanDefinitionReader. 这是一个内部 Spring 组件,它扫描(解析)xml 并根据我们在那里编写的内容创建BeanDefinitionxml 。BeanDefinition是一个存储有关 bean 信息的对象。这包括:应该从哪个类(bean)创建;范围; 是否安装了延迟初始化;是否有必要在此 bean 之前初始化另一个以及 xml 中描述的其他属性。所有收到的BeanDefinition都会添加到 中HashMap,其中标识符是 bean 的名称(由您设置或由 Spring 分配)和BeanDefinition对象本身。一切都创建完成后BeanDefinition,一个新的英雄出现在舞台上—— BeanFactory。该对象迭代HashMap’es BeanDefinition,基于它们创建 bean 并将它们放入 IoC 容器中。这里有一个细微差别,事实上,当应用程序启动时,IoC 容器将包含具有 Singleton 范围的 bean(默认设置),而其余的 bean 在需要时创建(原型、请求、会话)。现在扯个小题外话,让我们来认识一下另一个角色。

来认识一下 BeanPostProcessor。(BPP)

Bean 后处理器事实上,bean 不一定是应用程序的业务逻辑类。bean 也称为基础设施 bean。简而言之,基础设施 bean 是一个配置业务逻辑 bean 的类(是的,bean 太多了)。我将在下面告诉您更多相关信息,但为了让您更清楚 BPP 的具体配置,我将举一个示例。大家都熟悉这个摘要吗@Autowired?因此,您AutowiredAnnotationBeanPostProcessor有责任确保所有类都相互嵌入。 乌克维意思

让我们回到BeanFactory

现在了解了 BPP,您需要澄清的是,在迭代HashMap' 时,BeanDefinition首先创建所有 ' 并单独放置(不在 IoC 容器中)BeanPostProcessor。此后,我们的业务逻辑的常规 bean 被创建,放入 IoC 容器中,并且它们的配置开始使用单独的延迟 BPP。事情就是这样的,每个 BPP 有 2 个方法:
postProcessorBeforeInitialization(Object bean, String beanName);
postProcessorAfterInitialization(Object bean, String beanName);
遍历我们的垃圾箱两次。第一次调用该方法postProcessorBeforeInitialization,第二次调用该方法postProcessorAfterInitialization。当然,问题是为什么需要两种方法,让我解释一下。事实是,为了处理一些注释(例如@Transactional),我们的 bean 被替换为代理类。要理解为什么要这样做,您需要知道它是如何工作的@Transactional,这就是它的工作原理。您需要向标有此注释的方法添加几行代码。怎么做?没错,通过创建一个代理类,在其中将必要的代码添加到所需的方法中。现在想象一下这种情况,我们有一个类:
class A {
    @Autowired
    private SomeClass someClass;

    @Transactional
    public void method() {
        // модификатор доступа обязательно public
    }
}
该类有 2 个注释@Autowired@Transactional. 两个注释都由不同的 BPP 处理。如果它首先起作用AutowiredBPP,那么一切都会好起来,但如果没有,那么我们就会遇到这个问题。事实是,当创建代理类时,所有元信息都会丢失。换句话说,@Autowired代理类中不会有关于注释的信息,因此AutowiredBPP它将不起作用,这意味着我们的字段someClass将具有值null,这很可能会导致 NPE。还值得知道的是,在方法调用之间,postProcessorBeforeInitializationpostProcessorAfterInitialization调用-method init(如果有)。这基本上是第二个构造函数,但不同的是,此时我们所有的依赖项都已经嵌入到类中,我们可以从init- 方法访问它们。因此,再次介绍上下文初始化算法:
  1. XmlBeanDefinitionReader扫描我们的 xml 配置文件。
  2. 创建BeanDefinition并将它们放入HashMap.
  3. BeanFactory和由此HashMap分别将所有的相加BeanPostProcessor
  4. 从 's创建BeanDefinitionbean 并将它们放入 IoC 容器中。
  5. 这里 BPP 使用 2 种方法来配置这些 bean。
  6. 准备好。
其实就这些了,如果你喜欢这篇文章,以及是否值得继续写这样的教程,就写吧。
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION