Article directory
BeanDefinition
It is Spring
a very important concept in the world. It contains all the information required Spring
for container creation and configuration . Bean
Understanding the inner workings BeanDefinition
can help us develop deeper mastery.Spring
1. Explore BeanDefinition
First, let's have BeanDefinition
an overall understanding of .
1.1 Interpretation of BeanDefinition in official documents
The official documentation is a very important resource for understanding Spring
the concepts and components of the framework . Spring
About BeanDefinition
, the official document is as follows:
BeanDefinition
Contains a large amount of configuration information that can guide Spring
how to create Bean
, including Bean
constructor parameters, attribute values, initialization methods, static factory method names, etc. In addition, the child BeanDefinition
can BeanDefinition
inherit 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 Java
class, 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 XML
configuration or configuration , and the configuration information will be encapsulated in .Java
Person
Bean
Bean
BeanDefinition
In XML
a configuration, one Person Bean
might 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, BeanDefinition
the information includes class
the names and values of properties (fully qualified class names) and constructor parameters.
In Java
the 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, BeanDefinition
the information includes class
properties (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
BeanDefinition
All meta-information defined by the interface Bean
mainly includes the following methods:
- get/setBeanClassName() - get/set
Bean
the class name - get/setScope() - get/set
Bean
the 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 dependencies
Bean
- get/setPropertyValues() - Get/set property values
- get/setAutowireCandidate() - Gets/sets whether autowire can be wired
- get/setPrimary() - Gets/sets whether autowiring is preferred
Bean
Due to BeanDefinition
the length of the source code, not all of it is posted here, you can check it out by yourself. BeanDefinition
It also implements AttributeAccessor
an interface through which custom metadata can be added. Examples will be AttributeAccessor
used in the following sections.
As you can see from the above, BeanDefinition
it is the metadata object Spring
used to describe in the framework . This metadata contains some basic information about, including the following aspects:Bean
Bean
-
Bean's class information : This is
Bean
the fully qualified class name, that is,Bean
the specific type after instantiation. -
Bean attribute information : including
Bean
the scope of (is it a singleton or a prototype), whether it is mainBean
(primary
), description information, etc. -
Bean's behavioral characteristics : for example,
Bean
whether it supports lazy loading, whether it can be a candidate for autowiring, andBean
its initialization and destruction methods, etc. -
The relationship between Bean and other Beans : For example,
Bean
what else does this depend onBean
, andBean
whether this has a parentBean
. -
Bean configuration information : This includes
Bean
the constructor parameters, property values, etc.
1.3 Practical application of some methods of BeanDefinition
Next, a detailed code example is used to illustrate BeanDefinition
the use of each method in the interface, and the actual meaning of these methods is explained with actual code examples. Below, I'll BeanDefinition
provide code examples for a few important aspects.
The entire code is as follows:
First, here is our Java
configuration class and Person
the 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 BeanDefinition
get 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:
This example contains BeanDefinition
most 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 Bean
do 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
, BeanDefinition
the following main information is included:
-
Class : This is the fully qualified class name.
Spring
Use this information to createBean
instances via reflection. For example,com.example.demo.bean.Book
whenSpring
it needs to createBook bean
an instance of , it will createBook
an instance of the class through reflection based on this class name. -
Name : This is
Bean
the name of . In applications, we usually use this name to getBean
instances of . For example, we might have a named"bookService"
,Bean
and we cancontext.getBean("bookService")
getBean
an instance of this via . -
Scope : This defines
Bean
the scope of , e.g.singleton
orprototype
. Ifscope
yessingleton
, thenSpring
the container will create only oneBean
instance and return this instance on each request. Ifscope
yesprototype
, then the container will create a new instance everyBean
time it is requested .Spring
Bean
-
Constructor arguments : These are
Bean
the constructor arguments used to instantiate . For example, if we have aBook
class whose constructor requires aString
parameter of typetitle
, then we canBeanDefinition
set inconstructor arguments
to provide this parameter. -
Properties : These are
Bean
the property values that need to be injected into . For example, we might have aBook
class that has atitle
property that we canBeanDefinition
set inproperties
to 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
, thenSpring
the container will autowireBean
the property, which will look for a matching property type in the containerBean
and inject it. If set tobyName
, the container will look for a container with a name that matches the property nameBean
and inject it. There is also an optionconstructor
, which refers toBean
automatically wiping dependencies through the parameter types of the constructor. -
Lazy Initialization : If set to
true
,Bean
will be created on first request rather than when app starts. This can make your app launch faster, but mayBean
introduce some latency on the first request. -
Initialization Method and Destroy Method : These are
Bean
the initialization and destruction methods of . For example, we may have aBookService
class that has aninit
initialization method named and acleanup
destruction method named. We canBeanDefinition
set these two methods in , thenSpring
the container willBean
callinit
the method after creating and the methodBean
before destroyingcleanup
. -
Dependency beans : These are
Bean
the dependencies of . For example, we might have aBookService Bean
, which depends on aBookRepository Bean
, then we can set in theBookService
, then the container will be created first before creating .BeanDefinition
dependency beans
"bookRepository"
BookService Bean
Spring
BookRepository Bean
The above is BeanDefinition
the main information contained in , which will tell Spring
how the container is created and configured Bean
. Different BeanDefinition
implementations may have more configuration information. For example, RootBeanDefinition
, ChildBeanDefinition
, GenericBeanDefinition
etc. are all BeanDefinition
concrete implementation classes of the interface, and they may contain more configuration options.
2. Analysis of BeanDefinition construction system
Let's first clarify BeanDefinition
the roles. BeanDefinition
It is Spring
the core component of . It defines bean
configuration information, including class name, scope, constructor parameters, attribute values, etc. Let's take a look at BeanDefinition
what Spring
the design looks like.
Through this IDEA
we can get the following inheritance relationship diagram:
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 bean
configuration information is BeanDefinition
saved by objects. According to bean
different sources and methods of configuration, BeanDefinition
it is divided into many types. We will select a few of them to explain.
- RootBeanDefinition : When we
XML
define one in the configuration filebean
, an object will be createdSpring
for this object. This object contains all the information used for creation, such as class name, attribute values, etc. For example:bean
RootBeanDefinition
bean
bean
<bean id="exampleBean" class="com.example.ExampleBean">
<property name="stringProperty" value="stringValue"/>
</bean>
This XML
configuration defines a named "exampleBean"
, bean
its class is "com.example.ExampleBean"
, and there is an "stringProperty"
attribute value named is "stringValue"
. When Spring
this configuration is read, an object is created RootBeanDefinition
to save all the configuration information of this bean.
Summary: When XML
you define one in a file bean
, Spring
an 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
bean
inherit the configuration of another . For example:bean
ChildBeanDefinition
<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 XML
configuration, all configurations "childBean"
are inherited "parentBean"
and a new attribute is added "anotherStringProperty"
. When Spring
this configuration is read, an object will be "parentBean"
created first RootBeanDefinition
, and then "childBean"
an ChildBeanDefinition
object will be created, which this object will "parentBean"
reference BeanDefinition
.
Summary: If you have one bean
and want to create a new one bean
, which bean
needs to inherit bean
all the original configuration, but also needs to add or modify some configuration information, an instance Spring
will be created .ChildBeanDefinition
- GenericBeanDefinition : This is a generic
BeanDefinition
and can be converted toRootBeanDefinition
or as neededChildBeanDefinition
. For example, using annotations in a configuration class@Bean
defines abean
:
@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"
Spring
myComponent()
GenericBeanDefinition
GenericBeanDefinition
bean
GenericBeanDefinition
GenericBeanDefinition
Spring
bean
Summary: When you define one using annotations Java
in a configuration class , an instance is created .@Bean
bean
Spring
GenericBeanDefinition
- AnnotatedBeanDefinition
@Component
: When we use annotations (such as ,@Service
,@Repository
etc.) to define in codebean
, an instance of the interfaceSpring
will be created .AnnotatedBeanDefinition
For 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 Spring
this class is parsed, an object is created AnnotatedBeanDefinition
. This AnnotatedBeanDefinition
object will save the class name (which is also bean
the name), the type of the class, and all annotation information on the class. In this example, AnnotatedBeanDefinition
the instance will contain @Component
the annotation and all its metadata. This AnnotatedBeanDefinition
instance can then be used by Spring
the container to generate bean
instances, and the annotation information Spring
stored in it can also be used AnnotatedBeanDefinition
for further processing, such as AOP
proxying, transaction management, etc.
@Component
Summary: When you use annotations (such as , @Service
,, @Repository
etc.) on a class to define one bean
, Spring
an instance that implements AnnotatedBeanDefinition
the interface will be created, such as AnnotatedGenericBeanDefinition
or ScannedGenericBeanDefinition
. This instance will save the class name, class type, and all annotation information on the class.
GenericBeanDefinition
AnnotatedBeanDefinition
The main difference between and is that AnnotatedBeanDefinition
the annotation information on the class is saved, while GenericBeanDefinition
not. This enables Spring
these annotations to be read and processed at runtime, providing richer functionality.
In most cases, we don't need to care Spring
which bean
one is created BeanDefinition
. Spring
These are automatically managed BeanDefinition
and created and configured based on their type and the information they contain bean
.
2.2 Analysis of the principles of generating BeanDefinition
This BeanDefinition
object is read and generated Spring
by various implementation classes during the startup process .BeanDefinitionReader
Spring
There are three main ways to create it in BeanDefinition
:
- XML configuration method :
First, we XML
define 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 Spring
started, XmlBeanDefinitionReader
the 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: XmlBeanDefinitionReader
reading XML
the file, parsing <bean>
the elements and generating them BeanDefinition
.
- Annotation configuration method :
We use annotations such as @Component
, @Service
, @Repository
and 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 Spring
started, ClassPathBeanDefinitionScanner
the specified package path will be scanned to find all classes with specific annotations and BeanDefinition
objects will be created for these classes. What is generated in this way BeanDefinition
is usually ScannedGenericBeanDefinition
of type.
The simple description is: scan ClassPathBeanDefinitionScanner
the annotated classes under the specified package path and generate them BeanDefinition
.
- Java configuration method :
We use @Configuration
and @Bean
annotations 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 Spring
startup, ConfigurationClassPostProcessor
these configuration classes will be processed and handed over ConfigurationClassParser
to be parsed. For each @Bean
method marked with in the configuration class, an BeanDefinition
object will be created. What is generated in this way BeanDefinition
is usually ConfigurationClassBeanDefinition
of type.
The simple description is: process ConfigurationClassPostProcessor
the marked class, parse the methods and generate @Configuration
them .@Bean
BeanDefinition
In general, no matter we choose XML
configuration, annotation configuration or Java
configuration method, Spring
these configurations will be parsed at startup and corresponding BeanDefinition
objects will be generated to guide Spring
the container on how to create and manage Bean
instances.
These contents may be abstract and complex, but for beginners, you only need to understand: BeanDefinition
It is an object Spring
used to store Bean
configuration information. It is generated Spring
by reading the configuration during the startup process BeanDefinitionReader
. The specific generation method depends on the configuration used. method ( XML
, annotation or Java
configuration), as for the specific implementation principle, we will learn more about it later.
2.3 AttributeAccessor in practice: a powerful tool for attribute manipulation
AttributeAccessor
is Spring
an important interface in the framework that provides a flexible way to attach additional metadata to Spring
core components. Spring
Many important classes included in BeanDefinition
Components implement AttributeAccessor
interfaces 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:
Book
Create 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 RootBeanDefinition
instance to describe how to create an Book
instance of a class. RootBeanDefinition
Yes BeanDefinition
, it BeanDefinition
implements AttributeAccessor
the interface, so RootBeanDefinition
it inherits AttributeAccessor
the method.
Some people may wonder, Book does not have the member variable bookAttr. How is it assigned a value?
In Spring
the framework, AttributeAccessor
interfaces define methods for attaching, getting, and removing RootBeanDefinition
metadata associated with an object (for example), rather than manipulating Book
fields on the object (for example) itself.
So, when RootBeanDefinition
you call setAttribute("bookAttr", "a value")
a method on an instance, you are not actually Book
setting a bookAttr
field named on the instance. Instead, RootBeanDefinition
a 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 Book
class's bookAttr
fields ( Book
which actually don't have bookAttr
fields).
Simply put, this metadata is attached to RootBeanDefinition
the object, not to the instance RootBeanDefinition
described by the object Book
.
operation result:
Summarize:
BeanDefinition
AttributeAccessor
It is an important class that implements the interface. BeanDefinition
The object is the data structure Spring
used by the framework to store bean
configuration 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.@Lazy
bean
Spring
bean
BeanDefinition
BeanDefinition
When Spring
the container needs to create an instance later bean
, it will look at this BeanDefinition
object and create and manage the instance according to the metadata (such as scope
initialization lazy
, initialization and destruction methods, etc.) bean
. These metadata are not directly attached to bean
the instance, but are stored in BeanDefinition
objects and Spring
managed and used by the container.
So, when we get main
from 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.ApplicationContext
BeanDefinition
Spring
bean
bean
The benefit of this approach is that it decouples this additional metadata from bean
the instance itself, allowing bean
the flexibility to change it without modifying the class, and allowing the data to be shared between different threads in AttributeAccessor
the same process. JVM
This is why we can change the scope, whether it is lazy loading, etc. by modifying the configuration file or annotations bean
without modifying bean
the class definition.
3. BeanDefinition review and summary
As we dive deeper into Spring
the framework, we've learned BeanDefinition
about Spring
a very critical concept. BeanDefinition
Its main responsibility is to serve as a data object that stores detailed information about how to create, initialize, and configure a specific Bean
instance.
In particular, BeanDefinition
it contains the following main information:
- Fully qualified class name for the container to
Spring
create instances via reflectionBean
. - 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
Spring
howBean
the life cycle of the instance is managed. - Constructor parameters and property values , used for instantiation
Bean
and dependency injection. - Autowiring mode , indicating
Spring
how to automatically inject dependencies. - Initialization and destruction methods let you know how to execute custom logic
Spring
at specific moments in the life cycle.Bean
- Bean dependencies , telling which ones need to be created before
Spring
creating the current one .Bean
Bean
No matter which configuration method we use ( XML
, annotation or Java
configuration), Spring
these configurations will be parsed at startup and then the corresponding BeanDefinition
objects will be generated. These BeanDefinition
objects are like Spring
recipes inside the container, telling Spring
the 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----- ------------------