JavaRush /Java Blog /Random EN /spring framework. Introduction
Marchello
Level 20
Санкт-Петербург

spring framework. Introduction

Published in the Random EN group
Hello! While the JavaRush administration is working on new levels, I want to start a series of training articles on the Spring Framework. Yes, I know that there is already a lot of material on this topic on the Internet, but, as practice shows, they are all at the Hello World level. I want to talk not about how to correctly place annotations, but about how it all works “under the hood”. The article is intended for those who have already worked with this framework in one way or another and are familiar with the basic concepts. Spring Framework.  Introduction - 1

Initializing the context.

So let's start with the basics. In my opinion, one of the most important points is to understand how context is set up and beans are initialized. As you know, before Spring starts working, it needs to be configured. In antediluvian times, this was done using xml files (on some projects, mainly old ones, they continue to do this to this day). Here is a small example of such a configuration file:

<?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>
By and large, this is enough to create a couple of controllers and launch a startup (which will not take off). But how will this configuration make Spring work? And here's where things get interesting. In order for our configuration to be understood by Spring, there is a XmlBeanDefinitionReader. BeanDefinitionThis is an internal Spring component that scans (parses) xml and creates 's based on what we wrote there . BeanDefinitionis an object that stores information about the bean. This includes: from which class it (the bean) should be created; scope; whether lazy initialization is installed; Is it necessary to initialize before this bean another and other properties that are described in xml. All received BeanDefinition's are added to HashMap, in which the identifier is the name of the bean (set by you or assigned by Spring) and BeanDefinitionthe object itself. After everything BeanDefinitionis created, a new hero appears on the stage - BeanFactory. This object iterates over HashMap’es BeanDefinition, creates beans based on them and puts them into an IoC container. There is a nuance here, in fact, when the application starts, the IoC container will contain beans that have a Singleton scope (set by default), while the rest are created when they are needed (prototype, request, session). And now a small digression, let's get acquainted with another character.

Meet BeanPostProcessor. (BPP)

bean post processorThe fact is that a bean is not necessarily a class of business logic for your application. A bean is also called an infrastructure bean. In short, an infrastructure bean is a class that configures your business logic beans (yes, too many beans). I will tell you more about it below, but to make it a little clearer what exactly BPP configures, I will give an example. Is everyone familiar with the summary @Autowired? So, you AutowiredAnnotationBeanPostProcessorare responsible for ensuring that all your classes are embedded in each other. uknowimean

Let's go back to BeanFactory

Knowing now about BPP, you need to clarify that when iterating over HashMap's, BeanDefinitionall 's are first created and placed separately (not in the IoC container) BeanPostProcessor. After this, regular beans of our business logic are created, put into an IoC container, and their configuration begins using separately deferred BPPs. And this is how it happens, each BPP has 2 methods:

postProcessorBeforeInitialization(Object bean, String beanName);
postProcessorAfterInitialization(Object bean, String beanName);
Iterates through our bins twice. The first time the method is called postProcessorBeforeInitialization, and the second time the method is called postProcessorAfterInitialization. Surely the question has arisen as to why two methods are needed, let me explain. The fact is that to process some annotations (such as @Transactional, for example), our bean is replaced by a proxy class. To understand why this is done, you need to know how it works @Transactional, and this is how it works. You need to add a couple more lines of code to the method marked with this annotation on the fly. How to do it? That's right, by creating a proxy class, inside which the necessary code will be added to the required method. Now imagine this situation, we have a class:

class A {
    @Autowired
    private SomeClass someClass;

    @Transactional
    public void method() {
        // модификатор доступа обязательно public
    }
}
This class has 2 annotations @Autowiredand @Transactional. Both annotations are processed by different BPPs. If it works first AutowiredBPP, then everything will be fine, but if not, then we will encounter this problem. The fact is that when the proxy class is created, all meta information is lost. In other words, there will be no information about the annotation @Autowiredin the proxy class, and therefore AutowiredBPPit will not work, which means our field someClasswill have the value null, which will most likely lead to an NPE. It is also worth knowing that between method calls, the -method postProcessorBeforeInitializationis postProcessorAfterInitializationcalled init, if there is one. This is basically the second constructor, but the difference is that at this moment all our dependencies are already embedded in the class and we can access them from initthe -method. So, once again the context initialization algorithm:
  1. XmlBeanDefinitionReaderscans our xml configuration file.
  2. Creates BeanDefinition's and puts them in HashMap.
  3. Comes BeanFactoryand from this HashMapseparately adds up all the BeanPostProcessor's.
  4. Creates BeanDefinitionbeans from 's and places them in an IoC container.
  5. Here BPPs come and configure these beans using 2 methods.
  6. Ready.
Actually, that’s all, write if you liked the article and whether it’s worth continuing to write such tutorials.
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION