Spring Master's Road 11 - BeanDefinition Decryption: The cornerstone of building and managing Spring Beans

  BeanDefinitionIt is Springa very important concept in the world. It contains all the information required Springfor container creation and configuration . BeanUnderstanding the inner workings BeanDefinitioncan help us develop deeper mastery.Spring

1. Explore BeanDefinition

First, let's have BeanDefinitionan overall understanding of .

1.1 Interpretation of BeanDefinition in official documents

The official documentation is a very important resource   for understanding Springthe concepts and components of the framework . SpringAbout BeanDefinition, the official document is as follows:

  BeanDefinitionContains a large amount of configuration information that can guide Springhow to create Bean, including Beanconstructor parameters, attribute values, initialization methods, static factory method names, etc. In addition, the child BeanDefinitioncan BeanDefinitioninherit configuration information from the parent, and can also overwrite or add new configuration information. This design pattern effectively reduces redundant configuration information and makes the configuration more concise.

Next, let’s understand better through a concrete example BeanDefinition.

Consider a simple Javaclass, Person:

public class Person {
    
    
    private String name;
    private int age;

    public Person() {
    
    }

    public Person(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    // getters and setters
}

We can define a type using XMLconfiguration or configuration , and the configuration information will be encapsulated in .JavaPersonBeanBeanBeanDefinition

In XMLa configuration, one Person Beanmight be defined as follows:

<bean id="person" class="com.example.Person">
    <constructor-arg name="name" value="John"/>
    <constructor-arg name="age" value="25"/>
</bean>

Here, BeanDefinitionthe information includes classthe names and values ​​of properties (fully qualified class names) and constructor parameters.

In Javathe configuration, we can define one like this Person Bean:

@Configuration
public class AppConfig {
    
    
    @Bean
    public Person person() {
    
    
        return new Person("John", 25);
    }
}

  In this example, BeanDefinitionthe information includes classproperties (fully qualified class names) and constructor parameters. We can get this fully qualified class name through the method BeanDefinition.getBeanClassName()

1.2 Analysis of key methods of BeanDefinition

BeanDefinitionAll meta-information defined by the interface Beanmainly includes the following methods:

  • get/setBeanClassName() - get/set Beanthe class name
  • get/setScope() - get/set Beanthe scope
  • isSingleton() / isPrototype() - Determine whether it is singleton/prototype scope
  • get/setInitMethodName() - Get/set the initialization method name
  • get/setDestroyMethodName() - Get/set the destruction method name
  • get/setLazyInit() - Get/set whether to delay initialization
  • get/setDependsOn() - Get/set dependenciesBean
  • get/setPropertyValues() - Get/set property values
  • get/setAutowireCandidate() - Gets/sets whether autowire can be wired
  • get/setPrimary() - Gets/sets whether autowiring is preferredBean

  Due to BeanDefinitionthe length of the source code, not all of it is posted here, you can check it out by yourself. BeanDefinitionIt also implements AttributeAccessoran interface through which custom metadata can be added. Examples will be AttributeAccessorused in the following sections.

  As you can see from the above, BeanDefinitionit is the metadata object Springused to describe in the framework . This metadata contains some basic information about, including the following aspects:BeanBean

  • Bean's class information : This is Beanthe fully qualified class name, that is, Beanthe specific type after instantiation.

  • Bean attribute information : including Beanthe scope of (is it a singleton or a prototype), whether it is main Bean( primary), description information, etc.

  • Bean's behavioral characteristics : for example, Beanwhether it supports lazy loading, whether it can be a candidate for autowiring, and Beanits initialization and destruction methods, etc.

  • The relationship between Bean and other Beans : For example, Beanwhat else does this depend on Bean, and Beanwhether this has a parent Bean.

  • Bean configuration information : This includes Beanthe constructor parameters, property values, etc.

1.3 Practical application of some methods of BeanDefinition

  Next, a detailed code example is used to illustrate BeanDefinitionthe use of each method in the interface, and the actual meaning of these methods is explained with actual code examples. Below, I'll BeanDefinitionprovide code examples for a few important aspects.

The entire code is as follows:

First, here is our Javaconfiguration class and Personthe class definition:

package com.example.demo.configuration;

import com.example.demo.bean.Person;
import org.springframework.context.annotation.*;

@Configuration
public class AppConfig {
    
    

    @Bean(initMethod = "init", destroyMethod = "cleanup")
    @Scope("singleton")
    @Lazy
    @Primary
    @Description("A bean for person")
    public Person person() {
    
    
        return new Person("John", 25);
    }
}
package com.example.demo.bean;

public class Person {
    
    
    private String name;
    private int age;

    public Person(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    // getters and setters

    public void init() {
    
    
        System.out.println("Initializing Person bean");
    }

    public void cleanup() {
    
    
        System.out.println("Cleaning up Person bean");
    }
}

Here's how to BeanDefinitionget each attribute:

package com.example.demo;

import com.example.demo.configuration.AppConfig;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Arrays;

public class DemoApplication {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        String personBeanName = "person";
        BeanDefinition personBeanDefinition = context.getBeanFactory().getBeanDefinition(personBeanName);

        // 获取Bean的类信息
        System.out.println("Bean Class Name: " + context.getBean(personBeanName).getClass().getName());

        // 获取Bean的属性
        System.out.println("Scope: " + personBeanDefinition.getScope());
        System.out.println("Is primary: " + personBeanDefinition.isPrimary());
        System.out.println("Description: " + personBeanDefinition.getDescription());

        // 获取Bean的行为特征
        System.out.println("Is lazy init: " + personBeanDefinition.isLazyInit());
        System.out.println("Init method: " + personBeanDefinition.getInitMethodName());
        System.out.println("Destroy method: " + personBeanDefinition.getDestroyMethodName());

        // 获取Bean的关系
        System.out.println("Parent bean name: " + personBeanDefinition.getParentName());
        System.out.println("Depends on: " + Arrays.toString(personBeanDefinition.getDependsOn()));

        // 获取Bean的配置属性
        System.out.println("Constructor argument values: " + personBeanDefinition.getConstructorArgumentValues());
        System.out.println("Property values: " + personBeanDefinition.getPropertyValues());
    }
}

operation result:

Insert image description here

  This example contains BeanDefinitionmost of the methods and shows what they do. Please note that in this example, the return results of some methods such as getDependsOn(), getParentName(), getConstructorArgumentValues(), getPropertyValues()may not show any substance, because we person Beando not set these values. If these values ​​are set in the actual application, these methods will return the corresponding results.

1.4 BeanDefinition deep information structure sorting

In Spring, BeanDefinitionthe following main information is included:

  • Class : This is the fully qualified class name. SpringUse this information to create Beaninstances via reflection. For example, com.example.demo.bean.Bookwhen Springit needs to create Book beanan instance of , it will create Bookan instance of the class through reflection based on this class name.

  • Name : This is Beanthe name of . In applications, we usually use this name to get Beaninstances of . For example, we might have a named "bookService", Beanand we can context.getBean("bookService")get Beanan instance of this via .

  • Scope : This defines Beanthe scope of , e.g. singletonor prototype. If scopeyes singleton, then Springthe container will create only one Beaninstance and return this instance on each request. If scopeyes prototype, then the container will create a new instance every Beantime it is requested .SpringBean

  • Constructor arguments : These are Beanthe constructor arguments used to instantiate . For example, if we have a Bookclass whose constructor requires a Stringparameter of type title, then we can BeanDefinitionset in constructor argumentsto provide this parameter.

  • Properties : These are Beanthe property values ​​that need to be injected into . For example, we might have a Bookclass that has a titleproperty that we can BeanDefinitionset in propertiesto provide the value of this property. These values ​​can also be injected in configuration files or classes via <property>tags or annotations.@Value

  • Autowiring Mode : This is the mode of automatic wiring. If set to byType, then Springthe container will autowire Beanthe property, which will look for a matching property type in the container Beanand inject it. If set to byName, the container will look for a container with a name that matches the property name Beanand inject it. There is also an option constructor, which refers to Beanautomatically wiping dependencies through the parameter types of the constructor.

  • Lazy Initialization : If set to true, Beanwill be created on first request rather than when app starts. This can make your app launch faster, but may Beanintroduce some latency on the first request.

  • Initialization Method and Destroy Method : These are Beanthe initialization and destruction methods of . For example, we may have a BookServiceclass that has an initinitialization method named and a cleanupdestruction method named. We can BeanDefinitionset these two methods in , then Springthe container will Beancall initthe method after creating and the method Beanbefore destroying cleanup.

  • Dependency beans : These are Beanthe dependencies of . For example, we might have a BookService Bean, which depends on a BookRepository Bean, then we can set in the BookService, then the container will be created first before creating .BeanDefinitiondependency beans"bookRepository"BookService BeanSpringBookRepository Bean

  The above is BeanDefinitionthe main information contained in , which will tell Springhow the container is created and configured Bean. Different BeanDefinitionimplementations may have more configuration information. For example, RootBeanDefinition, ChildBeanDefinition, GenericBeanDefinitionetc. are all BeanDefinitionconcrete implementation classes of the interface, and they may contain more configuration options.

2. Analysis of BeanDefinition construction system

  Let's first clarify BeanDefinitionthe roles. BeanDefinitionIt is Springthe core component of . It defines beanconfiguration information, including class name, scope, constructor parameters, attribute values, etc. Let's take a look at BeanDefinitionwhat Springthe design looks like.

Through this IDEAwe can get the following inheritance relationship diagram:

Insert image description here

While there are many interfaces, abstract classes, and extensions, we only need to focus on the key ones.

2.1 Types of BeanDefinition and their applications

In Spring, a beanconfiguration information is BeanDefinitionsaved by objects. According to beandifferent sources and methods of configuration, BeanDefinitionit is divided into many types. We will select a few of them to explain.

  • RootBeanDefinition : When we XMLdefine one in the configuration file bean, an object will be created Springfor this object. This object contains all the information used for creation, such as class name, attribute values, etc. For example:beanRootBeanDefinitionbeanbean
<bean id="exampleBean" class="com.example.ExampleBean">
    <property name="stringProperty" value="stringValue"/>
</bean>

  This XMLconfiguration defines a named "exampleBean", beanits class is "com.example.ExampleBean", and there is an "stringProperty"attribute value named is "stringValue". When Springthis configuration is read, an object is created RootBeanDefinitionto save all the configuration information of this bean.

  Summary: When XMLyou define one in a file bean, Springan instance will be created RootBeanDefinition, and this instance will save all configuration information, such as class name, attribute values, etc.

  • ChildBeanDefinition : Can be used when we need one to beaninherit the configuration of another . For example:beanChildBeanDefinition
<bean id="parentBean" class="com.example.ParentBean">
    <property name="stringProperty" value="stringValue"/>
</bean>

<bean id="childBean" parent="parentBean">
    <property name="anotherStringProperty" value="anotherStringValue"/>
</bean>

  In this XMLconfiguration, all configurations "childBean"are inherited "parentBean"and a new attribute is added "anotherStringProperty". When Springthis configuration is read, an object will be "parentBean"created first RootBeanDefinition, and then "childBean"an ChildBeanDefinitionobject will be created, which this object will "parentBean"reference BeanDefinition.

  Summary: If you have one beanand want to create a new one bean, which beanneeds to inherit beanall the original configuration, but also needs to add or modify some configuration information, an instance Springwill be created .ChildBeanDefinition

  • GenericBeanDefinition : This is a generic BeanDefinitionand can be converted to RootBeanDefinitionor as needed ChildBeanDefinition. For example, using annotations in a configuration class @Beandefines a bean:
@Configuration
public class AppConfig {
    
    
    @Bean
    public MyComponent myComponent() {
    
    
        return new MyComponent();
    }
}

  In this code, we define a class "myComponent"called . When this configuration class is parsed, an object is created for the method. This object will hold the method's name (which is also its name), its return type, and any required constructor parameters or properties. In this example, we haven't defined any parameters or properties, so the object only contains basic information. This object can then be used by the container for generated instances.bean"MyComponent"SpringmyComponent()GenericBeanDefinitionGenericBeanDefinitionbeanGenericBeanDefinitionGenericBeanDefinitionSpringbean

  Summary: When you define one using annotations Javain a configuration class , an instance is created .@BeanbeanSpringGenericBeanDefinition

  • AnnotatedBeanDefinition@Component : When we use annotations (such as , @Service, @Repositoryetc.) to define in code bean, an instance of the interface Springwill be created . AnnotatedBeanDefinitionFor example:
@Component("myComponent")
public class MyComponent {
    
    
    // some fields and methods
}

  In this code, we define a class "myComponent"named bean, and its class is "MyComponent", and there is an annotation on this class @Component. When Springthis class is parsed, an object is created AnnotatedBeanDefinition. This AnnotatedBeanDefinitionobject will save the class name (which is also beanthe name), the type of the class, and all annotation information on the class. In this example, AnnotatedBeanDefinitionthe instance will contain @Componentthe annotation and all its metadata. This AnnotatedBeanDefinitioninstance can then be used by Springthe container to generate beaninstances, and the annotation information Springstored in it can also be used AnnotatedBeanDefinitionfor further processing, such as AOPproxying, transaction management, etc.

@ComponentSummary: When you use annotations (such as , @Service,, @Repositoryetc.)   on a class to define one bean, Springan instance that implements AnnotatedBeanDefinitionthe interface will be created, such as AnnotatedGenericBeanDefinitionor ScannedGenericBeanDefinition. This instance will save the class name, class type, and all annotation information on the class.

  GenericBeanDefinitionAnnotatedBeanDefinitionThe main difference between and is that AnnotatedBeanDefinitionthe annotation information on the class is saved, while GenericBeanDefinitionnot. This enables Springthese annotations to be read and processed at runtime, providing richer functionality.

  In most cases, we don't need to care Springwhich beanone is created BeanDefinition. SpringThese are automatically managed BeanDefinitionand created and configured based on their type and the information they contain bean.

2.2 Analysis of the principles of generating BeanDefinition

  This BeanDefinitionobject is read and generated Springby various implementation classes during the startup process .BeanDefinitionReader

SpringThere are three main ways to create it   in BeanDefinition:

  • XML configuration method :

First, we XMLdefine one in the file bean:

<bean id="bookService" class="com.example.demo.service.BookService">
    <property name="bookRepository" ref="bookRepository"/>
</bean>

<bean id="bookRepository" class="com.example.demo.repository.BookRepository"/>

  In this case, when Springstarted, XmlBeanDefinitionReaderthe file will be read XML, the elements in it will be parsed , and an object will be created <bean>for each element .<bean>BeanDefinition

A simple description is: XmlBeanDefinitionReaderreading XMLthe file, parsing <bean>the elements and generating them BeanDefinition.

  • Annotation configuration method :

We use annotations such as @Component, @Service, @Repositoryand so on to define the class bean, for example:

@Repository
public class BookRepository {
    
    
    // ... repository methods
}

@Service
public class BookService {
    
    
    private final BookRepository bookRepository;
    
    public BookService(BookRepository bookRepository) {
    
    
        this.bookRepository = bookRepository;
    }
    
    // ... service methods
}

  In this case, when Springstarted, ClassPathBeanDefinitionScannerthe specified package path will be scanned to find all classes with specific annotations and BeanDefinitionobjects will be created for these classes. What is generated in this way BeanDefinitionis usually ScannedGenericBeanDefinitionof type.

  The simple description is: scan ClassPathBeanDefinitionScannerthe annotated classes under the specified package path and generate them BeanDefinition.

  • Java configuration method :

We use @Configurationand @Beanannotations to define configuration classes and bean, for example:

@Configuration
public class AppConfig {
    
    

    @Bean
    public BookRepository bookRepository() {
    
    
        return new BookRepository();
    }

    @Bean
    public BookService bookService(BookRepository bookRepository) {
    
    
        return new BookService(bookRepository);
    }
}

  In this case, when Springstartup, ConfigurationClassPostProcessorthese configuration classes will be processed and handed over ConfigurationClassParserto be parsed. For each @Beanmethod marked with in the configuration class, an BeanDefinitionobject will be created. What is generated in this way BeanDefinitionis usually ConfigurationClassBeanDefinitionof type.

  The simple description is: process ConfigurationClassPostProcessorthe marked class, parse the methods and generate @Configurationthem .@BeanBeanDefinition

  In general, no matter we choose XMLconfiguration, annotation configuration or Javaconfiguration method, Springthese configurations will be parsed at startup and corresponding BeanDefinitionobjects will be generated to guide Springthe container on how to create and manage Beaninstances.

  These contents may be abstract and complex, but for beginners, you only need to understand: BeanDefinitionIt is an object Springused to store Beanconfiguration information. It is generated Springby reading the configuration during the startup process BeanDefinitionReader. The specific generation method depends on the configuration used. method ( XML, annotation or Javaconfiguration), as for the specific implementation principle, we will learn more about it later.

2.3 AttributeAccessor in practice: a powerful tool for attribute manipulation

  AttributeAccessoris Springan important interface in the framework that provides a flexible way to attach additional metadata to Springcore components. SpringMany important classes included in BeanDefinitionComponents implement AttributeAccessorinterfaces so that additional properties of these components can be added and obtained dynamically. A significant benefit of this is that developers can flexibly manage additional information for these components without changing the original class definition.

Let's take a look at an example. The entire code is as follows:

BookCreate an object first

class Book {
    
    
    private String title;
    private String author;

    public Book() {
    
    }

    public Book(String title, String author) {
    
    
        this.title = title;
        this.author = author;
    }

    // getter 和 setter 省略...
}

Main program:

package com.example.demo;

import com.example.demo.bean.Book;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

public class DemoApplication {
    
    

    public static void main(String[] args) {
    
    
        // 创建一个BeanDefinition, BeanDefinition是AttributeAccessor的子接口
        BeanDefinition bd = new RootBeanDefinition(Book.class);

        // 设置属性
        bd.setAttribute("bookAttr", "a value");

        // 检查和获取属性
        if(bd.hasAttribute("bookAttr")) {
    
    
            System.out.println("bookAttr: " + bd.getAttribute("bookAttr"));

            // 移除属性
            bd.removeAttribute("bookAttr");
            System.out.println("bookAttr: " + bd.getAttribute("bookAttr"));
        }
    }
}

  In this example, we create an RootBeanDefinitioninstance to describe how to create an Bookinstance of a class. RootBeanDefinitionYes BeanDefinition, it BeanDefinitionimplements AttributeAccessorthe interface, so RootBeanDefinitionit inherits AttributeAccessorthe method.

Some people may wonder, Book does not have the member variable bookAttr. How is it assigned a value?

  In Springthe framework, AttributeAccessorinterfaces define methods for attaching, getting, and removing RootBeanDefinitionmetadata associated with an object (for example), rather than manipulating Bookfields on the object (for example) itself.

  So, when RootBeanDefinitionyou call setAttribute("bookAttr", "a value")a method on an instance, you are not actually Booksetting a bookAttrfield named on the instance. Instead, RootBeanDefinitiona metadata is attached to the instance, with the key being "bookAttr"and the value being "a value".

  On subsequent uses getAttribute("bookAttr")of the method, it will return the previously set metadata value "a value"instead of trying to access the Bookclass's bookAttrfields ( Bookwhich actually don't have bookAttrfields).

  Simply put, this metadata is attached to RootBeanDefinitionthe object, not to the instance RootBeanDefinitiondescribed by the object Book.

operation result:

Insert image description here

Summarize:

  BeanDefinitionAttributeAccessorIt is an important class that implements the interface. BeanDefinitionThe object is the data structure Springused by the framework to store beanconfiguration information. When we use annotations such as @Bean, @Scope, and to define a in the configuration class , an object will be created for this and the metadata of these annotations will be attached to this object.@LazybeanSpringbeanBeanDefinitionBeanDefinition

  When Springthe container needs to create an instance later bean, it will look at this BeanDefinitionobject and create and manage the instance according to the metadata (such as scopeinitialization lazy, initialization and destruction methods, etc.) bean. These metadata are not directly attached to beanthe instance, but are stored in BeanDefinitionobjects and Springmanaged and used by the container.

  So, when we get mainfrom and print its properties in the method , we are actually looking at the internal data structures used by the framework to manage the , rather than looking directly at the state of the instance itself.ApplicationContextBeanDefinitionSpringbeanbean

  The benefit of this approach is that it decouples this additional metadata from beanthe instance itself, allowing beanthe flexibility to change it without modifying the class, and allowing the data to be shared between different threads in AttributeAccessorthe same process. JVMThis is why we can change the scope, whether it is lazy loading, etc. by modifying the configuration file or annotations beanwithout modifying beanthe class definition.

3. BeanDefinition review and summary

  As we dive deeper into Springthe framework, we've learned BeanDefinitionabout Springa very critical concept. BeanDefinitionIts main responsibility is to serve as a data object that stores detailed information about how to create, initialize, and configure a specific Beaninstance.

In particular, BeanDefinitionit contains the following main information:

  • Fully qualified class name for the container to Springcreate instances via reflection Bean.
  • The name and alias of the bean , used to reference and find it in the application Bean.
  • The scope of a bean , such as singleton or prototype, determines Springhow Beanthe life cycle of the instance is managed.
  • Constructor parameters and property values , used for instantiation Beanand dependency injection.
  • Autowiring mode , indicating Springhow to automatically inject dependencies.
  • Initialization and destruction methods let you know how to execute custom logic Springat specific moments in the life cycle.Bean
  • Bean dependencies , telling which ones need to be created before Springcreating the current one .BeanBean

  No matter which configuration method we use ( XML, annotation or Javaconfiguration), Springthese configurations will be parsed at startup and then the corresponding BeanDefinitionobjects will be generated. These BeanDefinitionobjects are like Springrecipes inside the container, telling Springthe container how to create and configure each object Bean.


Welcome to the one-click triple connection~

If you have any questions, please leave a message, let's discuss and learn together

----------------------Talk is cheap, show me the code----- ------------------

Guess you like

Origin blog.csdn.net/qq_34115899/article/details/131881680