Spring 框架之IOC容器加载重要组件

1.读取配置

如果配置了这样的Bean:

或者

或者

这些是不同定义bean的方式, 他们最终都会生成bean。 那Spring为了生成bean代码复用,使用统一的创建流程,所以通过多态方式读取不同的配置会有不同的读取器,读取完后后续创建bean的流程是通用的。

不同的spring容器会使用不同的读取器:

  1. AnnotationConfigApplicationContext-AnnotatedBeanDefinitionReader
  2. ClassPathXmlApplicationContext-XmlBeanDefinitionReader
    1.读取器:BeanDefinitionReader
    接下来,我们来介绍几种在Spring源码中所提供的BeanDefinition读取器(BeanDefinitionReader),这些BeanDefinitionReader在我们使用Spring时用得少,但在Spring源码中用得多,相当于Spring源码的基础设施。
    AnnotatedBeanDefinitionReader
    可以直接把某个类转换为BeanDefinition,并且会解析该类上的注解,比如
    注意:它能解析的注解是:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description
    XmlBeanDefinitionReader
    可以解析标签
java 复制代码
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);12XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context); 3int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml"); 45System.out.println(context.getBean("user")); 

2. 扫描器ClassPathBeanDefinitionScanner

ClassPathBeanDefinitionScanner是扫描器,但是它的作用和BeanDefinitionReader类似,它可以进行扫描,扫描某个包路径,对扫描到的类进行解析,比如,扫描到的类上如果存在@Component注解,

那么就会把这个类解析为一个BeanDefinition,比如:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

context.refresh();

ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);

scanner.scan("com.xs");

System.out.println(context.getBean("userService"));
3.注册BeanDefinition

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,那就是直接通过BeanDefinition,比如:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

/ 生成一个BeanDefinition对象,并设置beanClass为User.class,并注册到ApplicationContext中

AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();

beanDefinition.setBeanClass(User.class);

context.registerBeanDefinition("user", beanDefinition);

System.out.println(context.getBean("user"));

我们还可以通过BeanDefinition设置一个Bean的其他属性;

和申明式事务、编程式事务类似,通过,@Bean,@Component等申明式方式所定义的Bean,最终都会被Spring解析为对应的BeanDefinition对象,并放入Spring容器中。
MetadataReader、ClassMetadata、AnnotationMetadata

在Spring中需要去解析类的信息,比如类名、类中的方法、类上的注解,这些都可以称之为类的元数据,所以Spring中对类的元数据做了抽象,并提供了一些工具类。

MetadataReader表示类的元数据读取器,默认实现类为SimpleMetadataReader。比如:

java 复制代码
public static void main(String[] args) throws IOException { 
SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFac
tory();
// 构造一个MetadataReader
MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("
com.xs.service.UserService");
// 得到一个ClassMetadata,并获取了类名
ClassMetadata classMetadata = metadataReader.getClassMetadata();
System.out.println(classMetadata.getClassName()); 
// 获取一个AnnotationMetadata,并获取类上的注解信息 
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); 
 for (String annotationType : annotationMetadata.getAnnotationTypes()) { 
}

需要注意的是,SimpleMetadataReader去解析类时,使用的ASM技术。

为什么要使用ASM技术,Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不太好,所以使用了ASM技术。
4. BeanFactory

BeanFactory表示Bean工厂,所以很明显,BeanFactory会负责创建Bean,并且提供获取Bean的API。

而ApplicationContext是BeanFactory的一种,在Spring源码中,是这么定义的:

首先,在Java中,接口是可以多继承的,我们发现ApplicationContext继承了ListableBeanFactory和HierarchicalBeanFactory,而ListableBeanFactory和HierarchicalBeanFactory都继承至BeanFactory,

所以我们可以认为ApplicationContext继承了BeanFactory,相当于苹果继承水果,宝马继承汽车一样,ApplicationContext也是BeanFactory的一种,拥有BeanFactory支持的所有功能,不过ApplicationContext比BeanFactory更加强大,ApplicationContext还基础了其他接口,也就表示

ApplicationContext还拥有其他功能,比如MessageSource表示国际化,ApplicationEventPublisher表示事件发布,EnvironmentCapable表示获取环境变量,等等,关于ApplicationContext后面再详细讨论。

在Spring的源码实现中,当我们new一个ApplicationContext时,其底层会new一个BeanFactory出来,当使用ApplicationContext的某些方法时,比如getBean(),底层调用的是BeanFactory的getBean()方法。

在Spring源码中,BeanFactory接口存在一个非常重要的实现类是:DefaultListableBeanFactory,也是非常核心的。

所以,我们可以直接来使用DefaultListableBeanFactory,而不用使用ApplicationContext的某个实现类,比如:
DefaultListableBeanFactory是非常强大的,支持很多功能,可以通过查看DefaultListableBeanFactory的类继承实现结构来看

这部分现在看不懂没关系,源码熟悉一点后回来再来看都可以。

它实现了很多接口,表示,它拥有很多功能:

1.AliasRegistry:支持别名功能,一个名字可以对应多个别名

2.BeanDefinitionRegistry:可以注册、保存、移除、获取某个BeanDefinition

3BeanFactory:Bean工厂,可以根据某个bean的名字、或类型、或别名获取某个Bean对象

4SingletonBeanRegistry:可以直接注册、获取某个单例Bean

5SimpleAliasRegistry:它是一个类,实现了AliasRegistry接口中所定义的功能,支持别名功能

6ListableBeanFactory:在BeanFactory的基础上,增加了其他功能,可以获取所有BeanDefinition的beanNames,可以根据某个类型获取对应的beanNames,可以根据某个类型获取{类型:对应的Bean}的映射关系

7HierarchicalBeanFactory:在BeanFactory的基础上,添加了获取父BeanFactory的功能

8DefaultSingletonBeanRegistry:它是一个类,实现了9SingletonBeanRegistry接口,拥有了直接注册、获取某个

单例Bean的功能

10ConfigurableBeanFactory:在HierarchicalBeanFactory和SingletonBeanRegistry的基础上,添加了设置父BeanFactory、类加载器(表示可以指定某个类加载器进行类的加载)、设置Spring EL表达式解析器(表示该BeanFactory可以解析EL表达式)、设置类型转化服务(表示该BeanFactory可以进行类型转化)、可以添加BeanPostProcessor(表示该BeanFactory支持Bean的后置处理器),可以合并BeanDefinition,可以销毁某个Bean等等功能

11FactoryBeanRegistrySupport:支持了FactoryBean的功能

AutowireCapableBeanFactory:是直接继承了BeanFactory,在BeanFactory的基础上,支持在创建Bean的过程中能对Bean进行自动装配

AbstractBeanFactory:实现了ConfigurableBeanFactory接口,继承了FactoryBeanRegistrySupport,这个BeanFactory的功能已经很全面了,但是不能自动装配和获取beanNamesConfigurableListableBeanFactory:继承了ListableBeanFactory、AutowireCapableBeanFactory、

ConfigurableBeanFactoryAbstractAutowireCapableBeanFactory:继承了AbstractBeanFactory,实现了AutowireCapableBeanFactory,拥有了自动装配的功能DefaultListableBeanFactory:继承了AbstractAutowireCapableBeanFactory,实现了

ConfigurableListableBeanFactory接口和BeanDefinitionRegistry接口,所以DefaultListableBeanFactory的功能很强大

ApplicationContext

HierarchicalBeanFactory:拥有获取父BeanFactory的功能

ListableBeanFactory:拥有获取beanNames的功能

ResourcePatternResolver:资源加载器,可以一次性获取多个资源(文件资源等等)

EnvironmentCapable:可以获取运行时环境(没有设置运行时环境功能)

ApplicationEventPublisher:拥有广播事件的功能(没有添加事件监听器的功能)

MessageSource:拥有国际化功能

我们先来看ApplicationContext两个比较重要的实现类:

AnnotationConfigApplicationContext

ClassPathXmlApplicationContext
AnnotationConfigApplicationContext

ConfigurableApplicationContext:继承了ApplicationContext接口,增加了,添加事件监听器、添加BeanFactoryPostProcessor、设置Environment,获取ConfigurableListableBeanFactory等功能

AbstractApplicationContext:实现了ConfigurableApplicationContext接口

GenericApplicationContext:继承了AbstractApplicationContext,实现了BeanDefinitionRegistry接口,拥有了所有ApplicationContext的功能,并且可以注册BeanDefinition,注意这个类中有一个属性

(DefaultListableBeanFactory beanFactory)

AnnotationConfigRegistry:可以单独注册某个为类为BeanDefinition(可以处理该类上的**@Configuration注解**,已经可以处理**@Bean注解**),同时可以扫描AnnotationConfigApplicationContext:继承了GenericApplicationContext,实现了AnnotationConfigRegistry接

口,拥有了以上所有的功能

ClassPathXmlApplicationContext

ApplicationContext=BeanFactory的全自动版+ 服务周到版

java 复制代码
DefaultListableBeanFactory defaultListableBeanFactory = new
DefaultListableBeanFactory();
AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new
AnnotatedBeanDefinitionReader(defaultListableBeanFactory);
annotatedBeanDefinitionReader.register(MainStart.class); 
// 解析配置
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition)
defaultListableBeanFactory.getBeanDefinition("mainStart");
if(beanDefinition.getMetadata().hasAnnotation(ComponentScan.class.getName())){
 // 读取为BeanDefintion 
 ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new
ClassPathBeanDefinitionScanner(defaultListableBeanFactory);
 classPathBeanDefinitionScanner.scan("com.xushu.all"); 
} 
// 一个个创建bean 
defaultListableBeanFactory.preInstantiateSingletons();
相关推荐
無限進步D3 小时前
Java 运行原理
java·开发语言·入门
難釋懷3 小时前
安装Canal
java
是苏浙3 小时前
JDK17新增特性
java·开发语言
不光头强3 小时前
spring cloud知识总结
后端·spring·spring cloud
GetcharZp6 小时前
告别 Python 依赖!用 LangChainGo 打造高性能大模型应用,Go 程序员必看!
后端
阿里加多6 小时前
第 4 章:Go 线程模型——GMP 深度解析
java·开发语言·后端·golang
likerhood7 小时前
java中`==`和`.equals()`区别
java·开发语言·python
小小李程序员7 小时前
Langchain4j工具调用获取不到ThreadLocal
java·后端·ai