Spring源码中几个核心类

149 阅读5分钟

在上一篇博文《一文带你构建Spring源码》中,我们完成了Spring源码编译。今天,一起来看看源码中一些重要的类(或接口),了解Spring中如何进行封装,为之后学习打好基础。

一 BeanDefinition接口

1.1 功能简介

BeanDefinition是Spring中定义Bean配置元信息的接口,是Spring IoC容器管理的核心数据结构之一,用于保存Bean的配置和属性,如Bean的类名、作用域、生命周期回调、依赖关系等。这些信息在Spring容器启动时,根据xml配置信息或注解生成,包括:

  • beanClassName:Bean的class类名称
  • scope:表示Bean作用域,单例或原型等
  • lazyInit:是否是懒加载
  • initMethodName、destroyMethodName:Bean初始化方法、销毁方法
  • dependsOn:所依赖的bean名称集
  • factoryBeanName:工厂bean名称
  • ......

BeanDefinition有3个主要实现:

  • GenericBeanDefinition:从 Spring2.5 以后新加的实现,可以动态设置父 Bean,同时兼具 RootBeanDefinition 和 ChildBeanDefinition 的功能;
  • AnnotatedGenericBeanDefinition:与注解相关的BeanDefinition,拥有获取注解元数据和方法元数据的能力;
  • ScannedGenericBeanDefinition:使用 ASM ClassReader 解析“类”文件本身所得到的Bean定义, 如使用@Component 等注解标记的 Bean。

1.2 声明式Bean定义

声明式Bean定义如xml、@Component(或@Service、@Controller)、@Bean等,都会被解析成一个BeanDefinition对象,保存到Spring容器中。

如定义一个User类。

package com.xiakexing.entity;

public class User {

	private String name;
	private int age;

	public User() {
	}

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


	public void setName(String name) {
		this.name = name;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "User{" +
				"name='" + name + ''' +
				", age=" + age +
				'}';
	}
}

先使用xml定义一个Bean,如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xmlns:context="http://www.springframework.org/schema/context"
		xsi:schemaLocation="http://www.springframework.org/schema/beans
	   https://www.springframework.org/schema/beans/spring-beans.xsd
	   http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

  <bean id="adminUser" class="com.xiakexing.entity.User" scope="singleton">
		<property name="name" value="Tom"/>
		<property name="age" value="23"/>
	</bean>
</beans>
import com.xiakexing.entity.User;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        User adminUser = context.getBean("adminUser", User.class);
        System.out.println(adminUser);
    }
}

或者使用注解来定义Bean。

@Bean(name = "user")
@Scope("singleton")
@Lazy
@Primary
@Description("A bean for person")
public User user() {
    return new User("John", 25);
}

1.3 编程式Bean定义

我们可以编程式创建BeanDefinition,注册到Spring容器中,从而创建Bean。

package com.xiakexing;

import com.xiakexing.entity.User;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

		AbstractBeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
		definition.setBeanClass(User.class);
        // 设置属性
		ConstructorArgumentValues values = new ConstructorArgumentValues();
		values.addIndexedArgumentValue(0, "Tom");
		values.addIndexedArgumentValue(1, 29);
		definition.setConstructorArgumentValues(values);
		definition.setScope("singleton");
		context.registerBeanDefinition("user", definition);
		System.out.println(context.getBean("user"));
	}
}

二 BeanDefinitionReader接口

BeanDefinitionReader是一个用于读取和解析Spring配置文件(如XML文件或基于注解的配置)以生成BeanDefinition对象的组件。

BeanDefinitionReader的常见实现:

  1. XmlBeanDefinitionReader:用于读取XML配置文件中<bean>标签,并将其转换为BeanDefinition对象。
  2. AnnotatedBeanDefinitionReader:用于读取基于注解的配置。它扫描类路径下的类,解析类上的注解(如@Component@Service等),并将这些类转换为BeanDefinition对象。
package com.xiakexing.entity;

import org.springframework.context.annotation.Description;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;

@Scope("singleton")
@Lazy
@Primary
@Description("dog")
public class Dog {

	public void test() {
		System.out.println("wang wang");
	}
}
import com.xiakexing.entity.Dog;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
		context.refresh();
        
		AnnotatedBeanDefinitionReader definitionReader = new AnnotatedBeanDefinitionReader(context);
		// Dog.class解析为BeanDefinition
		definitionReader.register(Dog.class);
		Dog dog = context.getBean("dog", Dog.class);
		dog.test();
	}
}

三 BeanFactory接口

BeanFactory表示Bean工厂,负责创建Bean,并提供获取Bean的API。

源码中有注释如下:

The root interface for accessing a Spring bean container.

This is the basic client view of a bean container; further interfaces such as ListableBeanFactory and org.springframework.beans.factory.config.ConfigurableBeanFactory are available for specific purposes.

翻译:BeanFactory是访问spring Bean容器的根接口,是容器的基本客户端视图,进一步接口如ListableBeanFactory和ConfigurableBeanFactory用于特定目的。

BeanFactory接口有一个非常重要的实现类:DefaultListableBeanFactory。

DefaultListableBeanFactory类实现了很多接口,拥有很多功能:

  1. AliasRegistry接口:支持Bean拥有别名;
  2. BeanDefinitionRegistry:可以从容器中注册、保存、移除、获取某个BeanDefinition;
  3. SingletonBeanRegistry:可以直接注册、获取某个单例Bean;
  4. ListableBeanFactory:在BeanFactory的基础上,增加了其他功能,可以获取所有BeanDefinition的beanNames,可以根据某个类型获取对应的beanNames等;
  5. HierarchicalBeanFactory:在BeanFactory的基础上,添加了获取父BeanFactory的功能;
  6. ConfigurableBeanFactory:在HierarchicalBeanFactory和SingletonBeanRegistry的基础上,添加了设置父BeanFactory、类加载器、设置Spring EL表达式解析器、设置类型转化服务,可以添加;BeanPostProcessor,可以合并BeanDefinition,可以销毁某个Bean等功能
  7. FactoryBeanRegistrySupport:支持了FactoryBean的功能;
  8. AutowireCapableBeanFactory:在BeanFactory的基础上,支持在创建Bean的过程中能对Bean进行自动装配。

四 ApplicationContext接口

ApplicationContext是BeanFactory的子接口,比BeanFactory功能更加强大。

  1. HierarchicalBeanFactory:拥有获取父BeanFactory的功能
  2. ListableBeanFactory:拥有获取beanNames的功能
  3. ResourcePatternResolver:资源加载器,可以一次性获取多个资源(文件资源等等)
  4. EnvironmentCapable:可以获取运行时环境(没有设置运行时环境功能)
  5. ApplicationEventPublisher:拥有发布事件的功能(没有添加事件监听器的功能)
  6. MessageSource:拥有国际化功能

ApplicationContext有两个比较重要的实现类:AnnotationConfigApplicationContext、ClassPathXmlApplicationContext。

4.1 AnnotationConfigApplicationContext

继承了GenericApplicationContext(实现了BeanDefinitionRegistry接口),拥有ApplicationContext的所有功能,还能够注册BeanDefinition。

4.2 ClassPathXmlApplicationContext

继承自AbstractApplicationContext,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition。

五 MetadataReader接口

类的类名、方法、类上注解等,这些都是类的元数据。 而MetadataReader用于读取示类的元数据,唯一实现类SimpleMetadataReader。

5.1 ClassMetadata接口

如下注释,不加载类时获取其元数据,如类名、继承体系、方法列表等。

Interface that defines abstract metadata of a specific class, in a form that does not require that class to be loaded yet.

翻译:一个接口,以一种不需要加载特定类的形式定义该类的抽象元数据。

继承系统如下

AnnotationMetadata接口是ClassMetadata的子接口,定义了类注释的抽象访问的接口。

5.2 一个示例

可通过SimpleMetadataReaderFactory类创建SimpleMetadataReader对象。

package com.xiakexing.service;

import org.springframework.stereotype.Component;

@Component
public class UserService {

    public void test() {
        System.out.println("hello spring");
    }
}
import java.io.IOException;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;

public class MetadataReaderTest {

    public static void main(String[] args) throws IOException {
        SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
        MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.xiakexing.service.UserService");
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        System.out.println(classMetadata.getClassName());
        System.out.println(classMetadata.isAbstract());

        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        for (String annotationType : annotationMetadata.getAnnotationTypes()) {
            System.out.println(annotationType);
        }
    }
}

5.3 ASM技术

SimpleMetadataReader去解析类元数据时,使用了ASM技术,不需要将类加载到JVM中。

ASM(Analyzing and Small World Methods)是一个强大的Java字节码操作库,它允许开发者以二进制形式读取、修改现有类,或动态生成新类。使用ClassReader类读取Java类的字节码。

试想一下,如果Spring只能将类加载进JVM中,创建Class对象后在获取类元数据,那么很多并不由Spring管理的类,或者应用中未使用的类,都会被无效的加载。