在上一篇博文《一文带你构建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的常见实现:
- XmlBeanDefinitionReader:用于读取XML配置文件中
<bean>标签,并将其转换为BeanDefinition对象。 - 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类实现了很多接口,拥有很多功能:
- AliasRegistry接口:支持Bean拥有别名;
- BeanDefinitionRegistry:可以从容器中注册、保存、移除、获取某个BeanDefinition;
- SingletonBeanRegistry:可以直接注册、获取某个单例Bean;
- ListableBeanFactory:在BeanFactory的基础上,增加了其他功能,可以获取所有BeanDefinition的beanNames,可以根据某个类型获取对应的beanNames等;
- HierarchicalBeanFactory:在BeanFactory的基础上,添加了获取父BeanFactory的功能;
- ConfigurableBeanFactory:在HierarchicalBeanFactory和SingletonBeanRegistry的基础上,添加了设置父BeanFactory、类加载器、设置Spring EL表达式解析器、设置类型转化服务,可以添加;BeanPostProcessor,可以合并BeanDefinition,可以销毁某个Bean等功能
- FactoryBeanRegistrySupport:支持了FactoryBean的功能;
- AutowireCapableBeanFactory:在BeanFactory的基础上,支持在创建Bean的过程中能对Bean进行自动装配。
四 ApplicationContext接口
ApplicationContext是BeanFactory的子接口,比BeanFactory功能更加强大。
- HierarchicalBeanFactory:拥有获取父BeanFactory的功能
- ListableBeanFactory:拥有获取beanNames的功能
- ResourcePatternResolver:资源加载器,可以一次性获取多个资源(文件资源等等)
- EnvironmentCapable:可以获取运行时环境(没有设置运行时环境功能)
- ApplicationEventPublisher:拥有发布事件的功能(没有添加事件监听器的功能)
- 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管理的类,或者应用中未使用的类,都会被无效的加载。