[Spring source code analysis] SpringIOC (1) - Bean and BeanDefinition

A global view of core interfaces and classes

Solve the key problem: turn the relationship between objects to use configuration to manage

  • Dependency Injection - Dependencies are managed in Spring's loC container

  • By wrapping objects in beans to manage objects and perform additional operations

Bean与BeanDefinition

Beans are first-class citizens of Spring:

  • The essence of Bean is a java object, but the life cycle of this object is managed by the container
  • There is no need to add any additional restrictions on the original java class in order to create a bean
  • The control method of java objects is reflected in the configuration

BeanDefinition is the definition of a bean

According to the configuration, the BeanDefinition used to describe the Bean is generated. The common attributes are as follows:

JDK uses java.lang.class to describe this object, and spring uses BeanDefinition to describe beans

  • scope scope( @Scope)
  • Lazy loading lazy-init( @Lazy): Determines whether the Bean instance is lazy loaded
  • preferred primary( @Primary): A bean set to true will be the preferred implementation class
    • When an interface corresponds to multiple implementation beans, the interface using this annotation will be implemented first
  • factory-bean and factory-method ( @Configurationand @Bean)

Demonstration of bean creation with no parameter constructor:
create an entity package in the project and create a User class

package com.wjw.entity;

public class User {
    
    

}

At this point, defining the corresponding bean in xml can be achieved by using the no-parameter construction method

<bean id="user1" class="com.wjw.entity.User" scope="singleton" lazy-init="true" primary="true"/>

Create a bean demo using a static factory:
create another static factory class

package com.wjw.entity.factory;

import com.wjw.entity.User;

public class StaticFactory {
    
    

   public static User getUser(){
    
    
      return new User();
   }
}

At this point, defining the corresponding bean in xml can use the static factory method to achieve

<!-- class的值不是写User对象的全路径,而是写静态工厂的全路径 -->
<!-- factory-method的值写要调用的方法 -->
<bean id="user2" class="com.wjw.entity.factory.StaticFactory" factory-method="getUser" scope="singleton"/>

Example of creating a bean using an instance factory:

package com.wjw.entity.factory;

import com.wjw.entity.User;

public class UserFactory {
    
    

   public User getUser(){
    
    
      return new User();
   }
}

由于方法不是静态的,所以不能直接调用,只能先创建一个工厂的对象,然后通过对象再进行调用

<!-- 需要先创建factoryBean对象,再通过factoryBean对象进行调用 -->
<bean id="userFactory" class="com.wjw.entity.factory.UserFactory"/>
<bean id="user3" factory-bean="userFactory" factory-method="getUser" scope="singleton" />

测试:

package com.wjw;

import com.wjw.controller.WelcomeController;
import com.wjw.entity.User;
import com.wjw.service.WelcomeService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.FileSystemXmlApplicationContext;

@Configuration
@ComponentScan("com.wjw")
public class Entrance {
    
    

   public static void main(String[] args) {
    
    
      System.out.println("Hello World!");
      String xmlPath = "F:\\Java\\spring-framework-5.2.0.RELEASE\\springdemo\\src\\main\\resources\\spring\\spring-config.xml";
      ApplicationContext applicationContext = new FileSystemXmlApplicationContext(xmlPath);
      WelcomeService welcomeService = (WelcomeService) applicationContext.getBean("welcomeService");
      welcomeService.sayHello("强大的spring框架");

      //得到无参构造函数创建的对象:
      User user1a = (User) applicationContext.getBean("user1");
      User user1b = (User) applicationContext.getBean("user1");
      //得到静态工厂创建的对象:
      User user2a = (User) applicationContext.getBean("user2");
      User user2c = (User) applicationContext.getBean("user2");
      //得到实例工厂创建的对象:
      User user3a = (User) applicationContext.getBean("user3");
      User user3b = (User) applicationContext.getBean("user3");


      System.out.println("无参构造函数创建的对象:" + user1a);
      System.out.println("无参构造函数创建的对象:" + user1b);
      System.out.println("静态工厂创建的对象:" + user2a);
      System.out.println("静态工厂创建的对象:" + user2c);
      System.out.println("实例工厂创建的对象:" + user3a);
      System.out.println("实例工厂创建的对象:" + user3b);
   }
}

请添加图片描述

容器初始化主要做的事情(主要脉络)

请添加图片描述

BeanDefinition源码

请添加图片描述
请添加图片描述
继承了两个接口,spring中充斥着大量接口,继承某个接口就意味着具有某一项功能。

  • AttributeAccessor定义了最基本的对任意对象元数据的修改或者获取方式,用在这里主要就是为了获取BeanDefinition的属性,并操作这些属性。

  • BeanMetadataElement主要定义了一个getSource方法,用于返回一个可配置的源对象,用在这里主要就是为了返回BeanDefinition对象本身。

  • AttributeAccessorSupportAttributeAccessor的实现类。

  • AbstractBeanDefinition是BeanDefinition实现类的基类,定义了一些初始化通用属性的构造函数,以及对应的getter和setter,还有一些操作的通用方法。基于AbstractBeanDefinition抽象类,spring实现了一些有特殊用途的BeanDefinition。

  • RootBeanDefinition可以单独作为BeanDefinition,也可以作为其他BeanDefinition的父类,但不能作为其他的子类。(通常用来在运行时接收多个BeanDefinition合并起来的信息,可以接收具有继承关系的多个BeanDefinition,承接他们合并在一起的除了parent属性以外的属性)。一般情况下,配置文件里的bean标签会被解析成为RootBeanDefinition,但spring2.5之后使用GenericBeanDefinition来代替了,但因为先前的根基,所以在合并BeanDefinition时还是会用RootBeanDefinition来接收。

请添加图片描述
ps:spring中的继承是通过设置parent属性来决定的,不是extends

  • ChildBeanDefinition 已经被取代了。
  • GenericBeanDefinition(bean文件配置属性定义类)除了具有BeanDefinition属性之外还有parent属性,方便程序运行时去设定parent BeanDefinition,不会报异常,是一种更好的方案。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324193964&siteId=291194637