Every little adds up! Spring source code has reached the fifth chapter

Before looking at the source code, it is essential that you should know the basic usage of Spring by default. If you are not familiar with the basic usage of Spring, you can take a look at the free introductory video posted by Songo on the B website: www.bilibili.com/video/BV1Wv… .

The EntityResolver is a Spring source code that addresses XML file validation issues.

BeanDefinition: BeanDefinition: BeanDefinition: BeanDefinition: BeanDefinition: BeanDefinition: BeanDefinition: BeanDefinition: BeanDefinition: BeanDefinition

This is the fifth Spring source read-through, and reading the previous articles in this series will help you understand it better:

  1. Spring source code interpretation plan
  2. Spring source code first open whole! How is the configuration file loaded?
  3. Spring source code second bomb! XML file parsing process
  4. Spring source code third bullet! What the hell is EntityResolver?

1.BeanDefinition

In the Spring container, we commonly use Bean by Bean, and BeanDefinition is the definition of a Bean by name.

In fact, the Bean properties that we configure in the XML file are not only object related, but the Spring container has to deal with the Bean lifecycle, destruction, initialization, and so on. The operations we define about the Bean’s life cycle, destruction, initialization, and so on must always be carried by an object, and that object is the BeanDefinition.

The various attributes defined in XML are first loaded onto the BeanDefinition, and then a Bean is generated from the BeanDefinition. In this sense, the BeanDefinition and Bean relationship is somewhat similar to the class-object relationship.

To understand BeanDefinition, let’s start with the inheritance of BeanDefinition.

BeanDefinition is an interface that inherits from the BeanMetadataElement and AttributeAccessor interfaces.

  • BeanMetadataElement: This interface has only one method, getSource, which returns the Bean’s origin.
  • AttributeAccessor: This interface mainly specifies a way to ask for metadata for any object.

Let’s look at AttributeAccessor:

public interface AttributeAccessor {
	void setAttribute(String name, @Nullable Object value);
	@Nullable
	Object getAttribute(String name);
	@Nullable
	Object removeAttribute(String name);
	boolean hasAttribute(String name);
	String[] attributeNames();
}
Copy the code

The metadata access interface is defined, implemented as AttributeAccessorSupport, and the data is stored using LinkedHashMap.

These are the two interfaces that BeanDefinition inherits. Let’s take a look at the BeanDefinition interface:

public interface BeanDefinition extends AttributeAccessor.BeanMetadataElement {
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
	int ROLE_APPLICATION = 0;
	int ROLE_SUPPORT = 1;
	int ROLE_INFRASTRUCTURE = 2;
	void setParentName(@Nullable String parentName);
	@Nullable
	String getParentName(a);
	void setBeanClassName(@Nullable String beanClassName);
	@Nullable
	String getBeanClassName(a);
	void setScope(@Nullable String scope);
	@Nullable
	String getScope(a);
	void setLazyInit(boolean lazyInit);
	boolean isLazyInit(a);
	void setDependsOn(@Nullable String... dependsOn);
	@Nullable
	String[] getDependsOn();
	void setAutowireCandidate(boolean autowireCandidate);
	boolean isAutowireCandidate(a);
	void setPrimary(boolean primary);
	boolean isPrimary(a);
	void setFactoryBeanName(@Nullable String factoryBeanName);
	@Nullable
	String getFactoryBeanName(a);
	void setFactoryMethodName(@Nullable String factoryMethodName);
	@Nullable
	String getFactoryMethodName(a);
	ConstructorArgumentValues getConstructorArgumentValues(a);
	default boolean hasConstructorArgumentValues(a) {
		return! getConstructorArgumentValues().isEmpty(); }MutablePropertyValues getPropertyValues(a);
	default boolean hasPropertyValues(a) {
		return! getPropertyValues().isEmpty(); }void setInitMethodName(@Nullable String initMethodName);
	@Nullable
	String getInitMethodName(a);
	void setDestroyMethodName(@Nullable String destroyMethodName);
	@Nullable
	String getDestroyMethodName(a);
	void setRole(int role);
	int getRole(a);
	void setDescription(@Nullable String description);
	@Nullable
	String getDescription(a);
	ResolvableType getResolvableType(a);
	boolean isSingleton(a);
	boolean isPrototype(a);
	boolean isAbstract(a);
	@Nullable
	String getResourceDescription(a);
	@Nullable
	BeanDefinition getOriginatingBeanDefinition(a);
}
Copy the code

There are a lot of methods in BeanDefinition, but they’re pretty straightforward to understand when combined with our usual configuration in XML:

  1. The first two variables are defined to describe whether the Bean is a singleton, followed by the setScope/getScope methods that modify/retrieve the scope property.
  2. ROLE_xxx describes the role of a Bean. ROLE_APPLICATION indicates that the Bean is user-defined. ROLE_SUPPORT indicates that this Bean is a supporting part of some complex configuration; ROLE_INFRASTRUCTURE indicates that this is an internal Spring Bean that can be modified via setRole/getRole.
  3. SetParentName/getParentName used to configure the name of the parent, and this may be some friend use less, this corresponds to the XML<bean parent="">Configuration.
  4. SetBeanClassName/getBeanClassName is the configuration of the Bean Class, the full path of the corresponding XML<bean class="">Configuration.
  5. SetLazyInit /isLazyInit configates/gets whether the Bean is lazily loaded, which corresponds to XML<bean lazy-init="">Configuration.
  6. SetDependsOn getDependsOn configuration/Bean dependent objects, the corresponding in XML<bean depends-on="">Configuration.
  7. SetAutowireCandidate isAutowireCandidate configuration/get Bean is automatic assembly, the corresponding to the XML<bean autowire-candidate="">Configuration.
  8. SetPrimary /isPrimary configures/gets whether the current Bean is the preferred Bean, as in XML<bean primary="">Configuration.
  9. SetFactoryBeanName getFactoryBeanName configuration/get FactoryBean name, corresponding in XML<bean factory-bean="">Configuration factory-bean Configuration factory-bean configuration factory-bean configurationwww.bilibili.com/video/BV1Wv….
  10. SetFactoryMethodName/getFactoryMethodName and a paired, corresponding in XML<bean factory-method="">Configuration is not described here.
  11. GetConstructorArgumentValues return the Bean constructor parameter values.
  12. HasConstructorArgumentValues judgment on whether a null object.
  13. GetPropertyValues is a collection of common properties that get.
  14. HasPropertyValues determines whether the previous entry is an empty object.
  15. SetInitMethodName/setDestroyMethodName configuration Bean initialization method, method of destruction.
  16. SetDescription/getDescription configuration/return the description of the Bean.
  17. Is the isSingleton Bean a singleton?
  18. IsPrototype Bean is a prototype.
  19. IsAbstract Bean isAbstract.
  20. GetResourceDescription returns the resource description that defines the Bean.
  21. GetOriginatingBeanDefinition if the current BeanDefinition is a proxy object, the method can be used to return to the original BeanDefinition.

So this is the definition of a BeanDefinition and what the method init means.

2. BeanDefinition implementation class

The above is just the definition of the BeanDefinition interface. BeanDefinition also has many implementation classes, so let’s take a look.

Let’s start with an inheritance diagram:

With so many implementation classes, it’s a little confusing, but once you figure out what each interface and class does, it’s easy.

2.1 AbstractBeanDefinition

AbstractBeanDefinition AbstractBeanDefinition is an abstract class that provides properties based on the interface defined in BeanDefinition and implements some of the methods defined in BeanDefinition. AbstractBeanDefinition defines a set of get/set methods without providing corresponding properties. AbstractBeanDefinition defines all properties.

The rest of the implementation classes are basically based on AbstractBeanDefinition.

2.2 RootBeanDefinition

This is a common implementation class that corresponds to the generic element tag.

2.3 ChildBeanDefinition

You can have a child BeanDefinition definition that has the ability to inherit configuration from its parent BeanDefinition.

2.4 GenericBeanDefinition

GenericBeanDefinition is a new BeanDefinition implementation class added since Spring2.5. GenericBeanDefinition can dynamically set the parent Bean and has both RootBeanDefinition and ChildBeanDefinition functions.

2.5 AnnotatedBeanDefinition

Represents the annotation type BeanDefinition, with the ability to get annotation metadata and method metadata.

2.6 AnnotatedGenericBeanDefinition

Using the @ Configuration annotation tag Configuration class will be resolved as a AnnotatedGenericBeanDefinition.

Practice 3.

So much for the theory, let’s go through a few lines of code to see if what we said is true.

Add the spring-context dependency to the project as follows:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.6. RELEASE</version>
</dependency>
Copy the code

Then create a User class like this:

public class User {
    private String username;
    private String address;

    @Override
    public String toString(a) {
        return "User{" +
                "username='" + username + '\' ' +
                ", address='" + address + '\' ' +
                '} ';
    }

    public String getUsername(a) {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress(a) {
        return address;
    }

    public void setAddress(String address) {
        this.address = address; }}Copy the code

Let’s first verify the RootBeanDefinition. We manually define a RootBeanDefinition ourselves and register it in the Spring container.

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("username"."javaboy");
pvs.add("address"."www.javaboy.org");
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(User.class, null, pvs);
ctx.registerBeanDefinition("user",rootBeanDefinition);
ctx.refresh();
User bean = ctx.getBean(User.class);
System.out.println(bean);
Copy the code

MutablePropertyValues is an object that defines properties one by one. When we construct a RootBeanDefinition, we pass in the class name and the property collection, and finally register the RootBeanDefinition in the container. The container does the rest, and then we can get the User object from the container.

The final output is as follows:

User{username='javaboy', address='www.javaboy.org'}
Copy the code

As you can see from this example, the various attributes we define in XML are parsed into BeanDefinition, registered into the Spring container, and finally retrieved from the Bean we need.

ChildBeanDefinition has the ability to inherit data from the parent Bean. Let’s see how this is used.

Username = ‘address’; username = ‘address’; username = ‘address’; nickname = ‘nickname’;

public class Person {
    private String username;
    private String address;
    private String nickname;

    @Override
    public String toString(a) {
        return "Person{" +
                "username='" + username + '\' ' +
                ", address='" + address + '\' ' +
                ", nickname='" + nickname + '\' ' +
                '} ';
    }

    public String getUsername(a) {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress(a) {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getNickname(a) {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname; }}Copy the code

ChildBeanDefinition:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("username"."javaboy");
pvs.add("address"."www.javaboy.org");
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(User.class, null, pvs);
ctx.registerBeanDefinition("user",rootBeanDefinition);
ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition("user");
childBeanDefinition.setBeanClass(Person.class);
childBeanDefinition.getPropertyValues().add("nickname"."A little Rain in the South");
ctx.registerBeanDefinition("person", childBeanDefinition);
ctx.refresh();
User user = ctx.getBean(User.class);
Person person = ctx.getBean(Person.class);
System.out.println("user = " + user);
System.out.println("person = " + person);
Copy the code

First define RootBeanDefinition and register it with the Spring container, and then define ChildBeanDefinition, which inherits existing property values from RootBeanDefinition.

Finally, we get the User and Person from the Spring container and print them as follows:

user = User{username='javaboy', address='www.javaboy.org'}
person = Person{username='javaboy', address='www.javaboy.org', nickname='A little Rain in the South'}
Copy the code

As you can see, Person does inherit the attribute values of User.

RootBeanDefinition and ChildBeanDefinition can both be replaced by GenericBeanDefinition with the same effect as follows:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("username"."javaboy");
pvs.add("address"."www.javaboy.org");
GenericBeanDefinition rootBeanDefinition = new GenericBeanDefinition();
rootBeanDefinition.setBeanClass(User.class);
rootBeanDefinition.setPropertyValues(pvs);
ctx.registerBeanDefinition("user",rootBeanDefinition);
GenericBeanDefinition childBeanDefinition = new GenericBeanDefinition();
childBeanDefinition.setParentName("user");
childBeanDefinition.setBeanClass(Person.class);
childBeanDefinition.getPropertyValues().add("nickname"."A little Rain in the South");
ctx.registerBeanDefinition("person", childBeanDefinition);
ctx.refresh();
User user = ctx.getBean(User.class);
Person person = ctx.getBean(Person.class);
System.out.println("user = " + user);
System.out.println("person = " + person);
Copy the code

The running results are as follows:

user = User{username='javaboy', address='www.javaboy.org'}
person = Person{username='javaboy', address='www.javaboy.org', nickname='A little Rain in the South'}
Copy the code

As you can see, this is the same as before.

In our previous article in this series (the first Spring source! How is the configuration file loaded? GenericBeanDefinition is also used by default, as follows:

Now Spring after the Boot is widely popular, Java Configuration to use more and more, to @ Configuration annotation tag Configuration class will be resolved as AnnotatedGenericBeanDefinition; To @ Bean Bean will be parsed as ConfigurationClassBeanDefinition annotation mark.

Let’s create a new MyConfig config class as follows:

@Configuration
public class MyConfig {
    @Bean
    User user(a) {
        return newUser(); }}Copy the code

View the obtained BeanDefinition results as follows:

While other @ Service, @ Controller, @ the Repository and @ Component annotation markers such as beans will be identified as ScannedGenericBeanDefinition. I will not demonstrate this one, friends can test oh.

4. Summary

Today I’m going to introduce you to the BeanDefinition of Spring. Through the above principle and case, I believe you have understood that the Bean we configure through XML or Java annotations, the thing we define will first be parsed into BeanDefinition, and then through BeanDefinition to generate the Bean we need.

In the next article, we’ll look at exactly how this BeanDefinition is generated from an XML file.

Well, if you feel that you have gained something, remember to click on songge