一、前言
这是我Spring专栏的第五篇文章: Spring中Bean的工作流程及一些重要类的概念 在之前我为大家讲解了以下内容:
二、Beandefinition
BeanDefinition表示Bean定义,BeanDefinition中存在很多属性用来描述一个Bean的特点。比如:
- class,表示Bean类型
- scope,表示Bean作用域,单例或原型等
- lazyInit:表示Bean是否是懒加载
- initMethodName:表示Bean初始化时要执行的方法
- destroyMethodName:表示Bean销毁时要执行的方法
- 等等
在Spring中, 我们经常使用以下三种方式来定义一个bean:
- @Bean
- @Component(@Service, @Controller)
- <bean/>
除了这三种声明式定义Bean之外, 我们还可以编程式定义Bean
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // 生成一个BeanDefinition对象,并设置beanClass为User.class,并注册到ApplicationContext中 AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition(); beanDefinition.setBeanClass(Juejin.class); context.registerBeanDefinition("juejin", beanDefinition); System.out.println(context.getBean("juejin")); 复制代码
我们还可以使用 BeanDefinition对 Bean的其他属性进行设置
beanDefinition.setScope("prototype"); // 设置作用域 beanDefinition.setInitMethodName("init"); // 设置初始化方法 beanDefinition.setLazyInit(true); // 设置懒加载 复制代码
最终, 通过声明式定义的 Bean都会被Spring解析成对应的 BeanDefinition对象, 并放入Spring容器中
三、BeanDefinition读取器
接下来主要讲解的是几种 BeanDefinition读取器(BeanDefinitionReader), 这几种读取器在Spring源码中使用的较多
AnnotatedBeandefinitionReader
可以直接把某个类转换为 BeanDefinition, 并且会解析该类上的注解
具体以懒加载注解 @Lazy为例, 可以跟着下面几张图进入源代码看一遍
通过下图第一个红框可以看到, 他创建了一个 BeanDefinition, 点进第二个红框的方法, 就可以进入具体的判断注解方法了
首先我们看到他做了一个方法重载, 具体是做什么的先忽略掉, 看第二个红框, 这里就是判断我们是否使用了懒加载
AnnotatedBeandefinitionReader 可以解析的注解有: @Lazy, @Scope, @Conditional, @Primary, @DependsOn, @Role, @Description
XmlBeanDefinitionReader
可以解析 <bean/> 标签, 通过标签定义一个 bean好像很少去使用了就不进源码看了
ClassPathBeanDefinitionScanner
ClassPathBeanDefinitionScanner 是扫描器, 可以扫描包路径也可以对扫描到的类进行解析
四、BeanFactory
简单的说: BeanFactory表示工厂, 主要负责创建 Bean的同时提供获取Bean的API, 而ApplicationContext是BeanFactory的一种, 在Spring源码中, ApplicationContext的源码如下
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver { ... } 复制代码
ApplicationContext具体实现的几个接口功能如图所示
强大的 DefaultListableBeanFactory
在 BeanFactory接口存在一个非常重要的实现类: DefaultListableBeanFactory, 也是非常核心的
通过 DefaultListableBeanFactory也可以来实现某个类, 具体代码如下所示
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition(); beanDefinition.setBeanClass(Juejin.class); beanFactory.registerBeanDefinition("juejin", beanDefinition); System.out.println(beanFactory.getBean("juejin")); 复制代码
下图是关于 DefaultListableBeanFactory具体实现的一些接口功能简介
文字版:
- AliasRegistry:支持别名功能,一个名字可以对应多个别名
- BeanDefinitionRegistry:可以注册、保存、移除、获取某个BeanDefinition
- BeanFactory:Bean工厂,可以根据某个bean的名字、或类型、或别名获取某个Bean对象
- SingletonBeanRegistry:可以直接注册、获取某个单例Bean
- SimpleAliasRegistry:它是一个类,实现了AliasRegistry接口中所定义的功能,支持别名功能
- ListableBeanFactory:在BeanFactory的基础上,增加了其他功能,可以获取所有BeanDefinition的beanNames,可以根据某个类型获取对应的beanNames,可以根据某个类型获取{类型:对应的Bean}的映射关系
- HierarchicalBeanFactory:在BeanFactory的基础上,添加了获取父BeanFactory的功能
- DefaultSingletonBeanRegistry:它是一个类,实现了SingletonBeanRegistry接口,拥有了直接注册、获取某个单例Bean的功能
- FactoryBeanRegistrySupport:支持了FactoryBean的功能
- AutowireCapableBeanFactory:是直接继承了BeanFactory,在BeanFactory的基础上,支持在创建Bean的过程中能对Bean进行自动装配
- DefaultListableBeanFactory:继承了AbstractAutowireCapableBeanFactory,实现了ConfigurableListableBeanFactory接口和BeanDefinitionRegistry接口,所以DefaultListableBeanFactory的功能很强大
- AbstractBeanFactory:实现了ConfigurableBeanFactory接口,继承了FactoryBeanRegistrySupport,这个BeanFactory的功能已经很全面了,但是不能自动装配和获取beanNames
- ConfigurableListableBeanFactory:继承了ListableBeanFactory、AutowireCapableBeanFactory、ConfigurableBeanFactory
- ConfigurableBeanFactory:在HierarchicalBeanFactory和SingletonBeanRegistry的基础上,添加了设置父BeanFactory、类加载器(表示可以指定某个类加载器进行类的加载)、设置Spring EL表达式解析器(表示该BeanFactory可以解析EL表达式)、设置类型转化服务(表示该BeanFactory可以进行类型转化)、可以添加BeanPostProcessor(表示该BeanFactory支持Bean的后置处理器),可以合并BeanDefinition,可以销毁某个Bean等等功能
- AbstractAutowireCapableBeanFactory:继承了AbstractBeanFactory,实现了AutowireCapableBeanFactory,拥有了自动装配的功能
五、ApplicationContext
BeanFactory我们一般称其为IOC容器, 而ApplicationContext我们称其为应用上下文
ApplicationContext是BeanFactory的子接口, 最主要的方法就是 getBean(String beanName), ApplicationContext除了提供 BeanFactory所支持的功能之外, ApplicationContext还增加了以下几个额外的功能(主要就是上面ApplicationContext接口展示的图片)
- 事件机制
- 国际化
- 同时加载多个配置文件
- 以声明式方式启动并创建Spring容器
- 默认初始化所有的Singleton
- 获取运行时环境变量
六、类型转换器
PropertyEditor
PropertyEditor 是JDK中提供的类型转化工具类, 下面是实现这个类的代码
public class StringToJuejinPropertyEditor extends PropertyEditorSupport implements PropertyEditor { @Override public void setAsText(String text) throws IllegalArgumentException { Juejin juejin = new Juejin(); juejin.setName(text); this.setValue(user); } } 复制代码
下面是测试代码
// 创建对象 StringToJuejinPropertyEditor propertyEditor = new StringToJuejinPropertyEditor(); // 调用方法 propertyEditor.setAsText("宁轩"); // 取出value Juejin value = (Juejin) propertyEditor.getValue(); // 打印 System.out.println(value);// 对象地址 复制代码
ConversionService
Spring中提供的类型转换服务, 实现代码如下:
public class StringToJuejinConverter implements ConditionalGenericConverter { // 自定义转化器使用场景 @Override public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { // String ==> Juejin.class return sourceType.getType().equals(String.class) && targetType.getType().equals(Juejin.class); } @Override public Set<ConvertiblePair> getConvertibleTypes() { return Collections.singleton(new ConvertiblePair(String.class, Juejin.class)); } @Override public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { Juejin juejin = new Juejin(); juejin.setName((String)source); return juejin; } } 复制代码
测试代码
DefaultConversionService conversionService = new DefaultConversionService(); conversionService.addConverter(new StringToUserConverter()); Juejin value = conversionService.convert("宁轩", Juejin.class); System.out.println(value); 复制代码
TypeConverter
Spring内部使用的类型转化类
SimpleTypeConverter typeConverter = new SimpleTypeConverter(); typeConverter.registerCustomEditor(Juejin.class, new StringToUserPropertyEditor()); Juejin value = typeConverter.convertIfNecessary("1", Juejin.class); System.out.println(value); 复制代码
七、OrderComparator
OrderComparator是Spring所提供的一种比较器, 可以根据 @Order注解来实现排序
八、SimpleMetadataReader
在Spring中需要去解析类的信息, 得到类的元数据, Spring对类的元数据做了抽象, 并提供了一些工具类
MetadataReader表示类的元数据读取器,默认实现类为SimpleMetadataReader
public class Test { public static void main(String[] args) throws IOException { SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory(); // 构造一个MetadataReader MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.ningxuan.demo.service.JuejinService"); // 得到一个ClassMetadata,并获取了类名 ClassMetadata classMetadata = metadataReader.getClassMetadata(); System.out.println(classMetadata.getClassName()); // 获取一个AnnotationMetadata,并获取类上的注解信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); for (String annotationType : annotationMetadata.getAnnotationTypes()) { System.out.println(annotationType); } } } 复制代码
MetadataReader表示类的元数据读取器,主要包含了一个AnnotationMetadata,功能有
- 获取类的名字、
- 获取父类的名字
- 获取所实现的所有接口名
- 获取所有内部类的名字
- 判断是不是抽象类
- 判断是不是接口
- 判断是不是一个注解
- 获取拥有某个注解的方法集合
- 获取类上添加的所有注解信息
- 获取类上添加的所有注解类型集合
需要注意的是,SimpleMetadataReader去解析类时,使用的ASM技术。
为什么要使用ASM技术,Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不太好,所以使用了ASM技术。
九、ExcludeFilter和IncludeFilter
这两个Filter是Spring扫描过程中用来过滤的。ExcludeFilter表示排除过滤器,IncludeFilter表示包含过滤器。
如下图所示, 在扫描类的时候, 碰到类为 JuejinService.class的时候会排除
如下图所示, 在扫描类的时候, 哪怕JuejinService类没有使用@Component也会将其声明为注解
includeFilters具体代码实现如下图所示:
- 进入AnnotationCOnfigApplicationContext无参构造方法之后
- 在生成scanner的时候默认会执行 registerDefaultFilters() 方法
- 在这个方法中, 会 new一个Component注解添加进 includeFilters中
在Spring内部是怎么支持 @Component注解
具体可以跟着下面图走一遍源代码, 具体步骤:
- 进入AnnotationConfigApplicationContext构造方法
- 进入无参构造
- 无参生成了一个扫描器 ==> this.scanner = new ClassPathBeanDefinitionScanner(this)
- 好多个方法重载
- 接下来就可以看到 执行了一个 this.registerDefaultFilters() 方法
- 在这个方法里面新建了一个 new AnnoationTypeFilter(Compent.class) 这样子在扫描的时候凡是发现了 @Component注解就生成Bean
FilterType类型
- ANNOTATION:表示是否包含某个注解
- ASSIGNABLE_TYPE:表示是否是某个类
- ASPECTJ:表示否是符合某个Aspectj表达式
- REGEX:表示是否符合某个正则表达式
- CUSTOM:自定义
十、FactoryBean
我们都知道可以通过 @Bean, @Component等注解来生成bean, 那么有没有什么办法能完全由自己创造一个bean呢, 这个时候就用到了 FactoryBean
FactoryBean 一个能生产或修饰对象生成的工厂Bean, 能返回任何Bean的实例
FactoryBean生成的Bean和@Bean生成的bean有什么区别
通过@Bean生成的Bean是经过完整的生命周期的
通过FactoryBean生成的Bean只会经过初始化