感兴趣的话大家可以关注一下公众号 : 猿人刘先生 , 欢迎大家一起学习 , 一起进步 , 一起来交流吧!
本篇文章将对Spring底层的一些概念做一些简单的分析 , 也是为了方便后续在阅读源码的时候更加的方便
BeanDefintion
BeanDefintion是一个接口 , 它表示一个Bean的定义 , BeanDefintion存在很多属性来描述一个Bean的特点 , Spring在扫描完需要注册的Bean之后会进行解析 , 而解析的数据就会存入到BeanDefintion
我们在定义Bean的时候可以分为两种方式 :
申明式
申明式定义一个Bean就比如我们用的@Bean , @Component等注解 , 或者是xml标签的形式来定义一个Bean
编程式
编程式就是通过写代码的方式来定义 , 如下
首先定义一个MenberService
public class MemberService {
public void test(){
System.out.println("test方法被调用...");
}
}
接着我们从Spring获取这个’Bean’ , 看是否能获取到
public class TestSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = (MemberService) applicationContext.getBean("memberService");
memberService.test();
}
}
运行之后我们回发现报错了 , 报错内容如下 :
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘memberService’ available
没有找到一个名为memberService的Bean来使用
我们再用编程式的方式定义
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// 得到一个BeanDefinition对象
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
// 设置Bean的类型
beanDefinition.setBeanClass(MemberService.class);
// 设置Bean的作用域
beanDefinition.setScope("prototype");
// 当然光这样申明还是不够的 , 我们需要调用一个函数来把这个beanDefinition注册到容器中 , 在注册的时候我们可以指定一个Bean的名称
applicationContext.registerBeanDefinition("memberService" , beanDefinition);
MemberService memberService = (MemberService) applicationContext.getBean("memberService");
memberService.test();
}
}
接着运行进行测试 , 会发现这次并没有报错 , 并且也打印出来了 “test方法被调用…”
其实不难理解 , 我们通过注解的方式去定义 , 当Spring扫描完解析的时候 , 他底层也会把解析的结果封装到BeanDefinition, 我们现在不通过注解申明的方式 , 而是直接编程式的把值封装到BeanDefinition中 , 然后注册到Spring容器 , 这样我们就可以使用了
BeanDefinitionReader
现在我们介绍几种BeanDefintion的几种读取器 , 虽然在工作中用的很少 , 但是 , 它也是Spring基础设施中比较重要的一部分
AnnotatedBeanDefinitionReader
可以直接把某个类转换为BeanDefinition,并且会解析该类上的注解,如下
public class TestSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// 把某一个类转换为BeanDefinition之后 , 我们也需要将它注册到Spring容器中 , 所以需要传一个ApplicationContext对象
AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(applicationContext);
// 注册到Spring容器中
annotatedBeanDefinitionReader.register(MemberService.class);
MemberService memberService = (MemberService) applicationContext.getBean("memberService");
memberService.test();
}
}
运行测试发现控制台打印 " test方法被调用…" , 我们可以简单看一下register()方法
public void register(Class<?>... componentClasses) {
for (Class<?> componentClass : componentClasses) {
registerBean(componentClass);
}
}
public void registerBean(Class<?> beanClass) {
doRegisterBean(beanClass, null, null, null, null);
}
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(supplier);
// 解析@Scope注解的结果为ScopeMetadata
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
// 将类的作用域添加到数据结构中
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
我们看一下processCommonDefinitionAnnotations()方法
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
processCommonDefinitionAnnotations(abd, abd.getMetadata());
}
// 处理@Lazy、@Primary、@DependsOn、@Role、@Description
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
else if (abd.getMetadata() != metadata) {
lazy = attributesFor(abd.getMetadata(), Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
}
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
abd.setRole(role.getNumber("value").intValue());
}
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
abd.setDescription(description.getString("value"));
}
}
可以看到 , 他底层的逻辑代码和我们刚刚用编程式定义的方式差不多 , 也是创建一个BeanDefintion对象 , 然后解析注解并设置BeanDefintion的值 , 那么这个AnnotatedBeanDefinitionReader读取器在什么时候用的呢?其实是在创建AnnotationConfigApplicationContext容器对象时候用的 , 我们点进去看一下它的构造方法
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
// 构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner
this();
// 注册bean配置类
register(componentClasses);
// 刷新上下文
refresh();
}
然后看this()方法
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
// 额外会创建StandardEnvironment
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
我们就可以看到它构造了一个AnnotatedBeanDefinitionReader对象 , 其实Spring容器本身也有register()方法
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
applicationContext.register();
其实它们使用的是同一个方法 , 看一看applicationContext.register()方法的源码
@Override
public void register(Class<?>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register")
.tag("classes", () -> Arrays.toString(componentClasses));
this.reader.register(componentClasses);
registerComponentClass.end();
}
public void register(Class<?>... componentClasses) {
for (Class<?> componentClass : componentClasses) {
registerBean(componentClass);
}
}
public void registerBean(Class<?> beanClass) {
doRegisterBean(beanClass, null, null, null, null);
}
可以看到, 它们最终调用的都是doRegisterBean()方法 , 都是会把传入的类转换为一个BeanDefintion
XmlBeanDefinitionReader
既然有解析类的读取器的 , 那么也就应该有解析xml标签的 , 它就是XmlBeanDefinitionReader , 如下
首先定义一个xml文件
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
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 http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"
>
<bean id="member" class="com.lyh.service.MemberService"/>
</beans>
然后我们通过如下的方式来获取
public class TestSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
MemberService memberService = (MemberService) applicationContext.getBean("memberService");
memberService.test();
}
}
ClassPathBeanDefinitionScanner
前面介绍的两个是读取器 , 现在来介绍一个BeanDefinition扫描器 , 读取器 , 读取类以及xml文件然后解析成为一个BeanDefintion , 那么扫描器, 那么就是读取某个包路径下的类 , 然后进行解析 ,比如,扫描到的类上如果存在@Component 注解,那么就会把这个类解析为一个BeanDefinition , 如下
申明一个ScannerService来测试
public class ScannerService {
public void test(){
System.out.println("执行了ScannerService.test()方法");
}
}
取消AppConfig.class这个入参
public class TestSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
ScannerService scannerService = (ScannerService) applicationContext.getBean("scannerService");
scannerService.test();
}
}
这样运行肯定是报错的 , 即使在ScannerService类加上了@Component注解 , 因为这里没有传配置文件进去 , 所以构造的是一个空的Spring容器
报错信息如下:
Exception in thread “main” java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext@433c675d has not been refreshed yet
在这里插入代码片
它提示我们这个容器还没有刷新一下 , 加一行代码来刷新一下
public class TestSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.refresh();
ScannerService scannerService = (ScannerService) applicationContext.getBean("scannerService");
scannerService.test();
}
}
发现刷新之后还是报错 , 报错信息如下 :
Exception in thread “main” org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘scannerService’ available
没有一个名为scannerService的Bean用来使用
我们现在用这个扫描器试一下
public class TestSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(applicationContext);
scanner.scan("com.lyh");
ScannerService scannerService = (ScannerService) applicationContext.getBean("scannerService");
scannerService.test();
}
}
发现控制台打印了 “执行了ScannerService.test()方法” , 也就是说这个扫描器生效了 , 它扫描到了ScannerService并且这个类加了@Component , 就表示这个类需要注册为一个Bean , 就会把这个类解析并放入Spring容器 , 其实比较细心的话就可以发现ClassPathBeanDefinitionScanner这个类是在之前申明AnnotatedBeanDefinitionReader读取器的时候也申明了
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
// 额外会创建StandardEnvironment
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
所以这里我们就知道了 , 我们的Spring容器它既可以去注册某一个类成为Bean ,也可以去扫描 , 当然它的内部会进行扫描 , 我们自己触发也是可以的 , 所以AnnotationConfigApplicationContext 也是有这两个功能的 , 一个是直接注册 , 一个是扫描
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 需要传入一个包路径
applicationContext.scan();
BeanDefinition子类
上面我们说到 , BeanDefinition是一个接口 , 那么重要的实现类有这么三个 :
1.GenericBeanDefinition
2.AnnotatedGenericBeanDefinition
3.ScannedGenericBeanDefinition
它们之前的父子关系是这样的
AnnotatedGenericBeanDefinition和ScannedGenericBeanDefinition的区别
先来看ScannedGenericBeanDefinition , 它表示是扫描出来的BeanDefinition的类型
我们来看源码 , 从刚刚scan()的源码进去
scanner.scan(“com.lyh”);
public int scan(String... basePackages) {
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
doScan(basePackages);
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
再来看doScan()
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
// 解析@Lazy、@Primary、@DependsOn、@Role、@Description
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 检查Spring容器中是否已经存在该beanName
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 注册
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
再来看findCandidateComponents()
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
再来看scanCandidateComponents()
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
// 获取basePackage下所有的文件资源
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// excludeFilters、includeFilters判断
if (isCandidateComponent(metadataReader)) { // @Component-->includeFilters判断
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
我们可以看到这样一行代码 :
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
就表示扫描出来的BeanDefinition类型是ScannedGenericBeanDefinition
再来看AnnotatedGenericBeanDefinition
我们还是进入到AnnotationConfigApplicationContext的构造方法
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
// 构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner
this();
// 注册bean配置类
register(componentClasses);
// 刷新上下文
refresh();
}
看register()方法
@Override
public void register(Class<?>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register")
.tag("classes", () -> Arrays.toString(componentClasses));
this.reader.register(componentClasses);
registerComponentClass.end();
}
再看 this.reader.register();
public void register(Class<?>... componentClasses) {
for (Class<?> componentClass : componentClasses) {
registerBean(componentClass);
}
}
再看registerBean()
public void registerBean(Class<?> beanClass) {
doRegisterBean(beanClass, null, null, null, null);
}
再看doRegisterBean()
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(supplier);
// 解析@Scope注解的结果为ScopeMetadata
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
// 将类的作用域添加到数据结构中
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
我们可以看到这样一行代码 :
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
就表示扫描并解析到的BeanDefinition类型是AnnotatedGenericBeanDefinition类型
我们简单理解 , 一个扫描器 ,一个读取器 , 最终得到的都是一个BeanDefinition对象 , 但是他是进行区分的
当然还有比较重要的两个BeanDefinition子类
1.RootBeanDefinition
2.ChildBeanDefinition
他们的父子关系是这样的
ChildBeanDefinition和RootBeanDefinition的区别
ChildBeanDefinition基本从Spring2.5开始就很少用了 , 都是用GenericBeanDefinition来代替
RootBeanDefinition 它是常用的 , 而且用的比较多 , 因为RootBeanDefinition和Bean的生命周期有关 , 所以我们后面来讲 , 它是和合并beanDefinition有关的 , 目前为止有这个合并beanDefinition的概念即可
BeanFactory
BeanFactory它是一个接口 , 表示Bean工厂 , 它的作用就是用来创建Bean对象的 , 我们一般常用的Bean工厂是ApplicationContext , 为什么说ApplicationContext 也是Bean工厂呢?
源码中它的类是这样定义的
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
而ListableBeanFactory, HierarchicalBeanFactory都继承了BeanFactory , 所以说ApplicationContext它其实就是一个Bean工厂 , 所以ApplicationContext 他肯定拥有BeanDactory的功能 , 那么ApplicationContext和BeanFactory有什么区别呢?
其实从源码我们不难看出 , 它还继承了一些其他的接口, 比如ApplicationEventPublisher事件发布器 ,
EnvironmentCapable获取环境变量等 , 这个是BeanFactory所没有的 ,它的功能也就比BeanFactory更强大一点
DefaultListableBeanFactory
上面说到解析为BeanDefintion之后会注册到Spring容器中 , 那么什么是容器? 其实在DefaultListableBeanFactory这个类中就有体现 , 源码中是这样定义的
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
其实说白了它就是一个map , key就是Bean的名称 , value就是解析出来的Map ,当然 , 我们也可以把Spring容器理解为单例池 , 单例池就是一个Map , 它存的就是所有的单例Bean , key也是Bean的名称 , value是Bean的实例 , 源码是这样定义的
// 单例池
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
是在我们在使用AnnotationConfigApplicationContext的时候就有用到这个类 , 我们需要知道的是 , 在加载构造方法之前 , 它会先加载父类的构造方法 , 而在父类的构造方法中就初始化一个DefaultListableBeanFactory , 其实我们的getBean()功能就是DefaultListableBeanFactory 实现的
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
DefaultListableBeanFactory的功能是非常强大的 , 支持很多功能,可以通过查看DefaultListableBeanFactory的类继承实现结构来看
Aliasregistry
Aliasregistry ,通过类图我们可以看到DefaultListableBeanFactory也是实现了Aliasregistry接口的 ,
而Aliasregistry接口提供的就是别名注册的功能 , 如果没有实现这个接口 , 就表示一个Bean只能有一个名称 ,但是实现了这个接口 , 我们就可以给这个Bean起一个别名
singletionBeanisgtry
singletionBeanisgtry , 它提供的就是单例Bean的功能
BeanDinfinitionRegistry
BeanDinfinitionRegistry , 实现了这个接口就可以有BeanDinfinition注册的功能
HierarchicalBeanFactory
HierarchicalBeanFactory , 它可以获取父Bean工厂 , 如果实现了这个接口 , 就表示这个Bean工厂是支持父子Bean工厂的 , 也就是说如果有两个Bean工厂 , 它们是父子Bean工厂 , 如果子Bean工厂get不到Bean , 那么我们就会从父工厂去get
ListableBeanFactory
ListableBeanFactory , 它可以根据Bean的名称判断是否包含BeanDefinition , 以及获取BeanDefinition的数量 , 获取所有BeanDefinition的名称也就是Bean的名称 , 比如还可以根据指定类型获取Bean的名称 , 其实这个类提供的也就是一个展示的功能 , Bean的名称 , 数量…等
AutowireCapableBeanFactory
AutowireCapableBeanFactor,是直接继承了BeanFactory,在BeanFactory的基础上,支持 在创建Bean的过程中能对Bean进行自动装配
ConfigurableBeanFactory
在HierarchicalBeanFactory和SingletonBeanRegistry的基础上, 添加了设置父BeanFactory、类加载器(表示可以指定某个类加载器进行类的加载)、设置 Spring EL表达式解析器(表示该BeanFactory可以解析EL表达式)、设置类型转化服务(表示 该BeanFactory可以进行类型转化)、可以添加BeanPostProcessor(表示该BeanFactory支持 Bean的后置处理器),可以合并BeanDefinition,可以销毁某个Bean等等功能
AbstractAutowireCapableBeanFactory
AbstractAutowireCapableBeanFactor, 继承了AbstractBeanFactory,实现了 AutowireCapableBeanFactory,拥有了自动装配的功能
对于这些接口 , 类不明白也没关系, 着重理解BeanFactory就行 , 其实这也可以充分的体会到Spring内部这种面向接口的思想 , 在以后的工作中 ,我们也可以模仿Spring这种面向接口的设计思想 , 每一个接口都是一个功能 , 如果想拥有这个功能 , 那我们实现这个接口就行
ApplicationContext
上面有分析到,ApplicationContext是个接口,实际上也是一个BeanFactory,不过比BeanFactory 更加强大,比如:
HierarchicalBeanFactory
拥有获取父BeanFactory的功能
ListableBeanFactory
拥有获取beanNames的功能
ResourcePatternResolver
资源加载器,可以一次性获取多个资源(文件资源等等)
public class TestSpring {
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
Resource resource = applicationContext.getResource("file://E:\\studywork\\spring-framework-5.3.10\\spring-lyh\\src\\main\\java\\com\\lyh\\service\\UserService.java");
System.out.println(resource.contentLength());
System.out.println(resource.getFilename());
Resource resource1 = applicationContext.getResource("https://www.baidu.com");
System.out.println(resource1.contentLength());
System.out.println(resource1.getURL());
Resource resource2 = applicationContext.getResource("classpath:spring.xml");
System.out.println(resource2.contentLength());
System.out.println(resource2.getURL());
String message = applicationContext.getMessage("test", null, new Locale("en"));
System.out.println("message : " + message);
}
}
还可以一次性获取多个
Resource[] resources = applicationContext.getResources("classpath:com/lyh/*.class");
for (Resource re : resources) {
System.out.println(re.contentLength());
System.out.println(re.getFilename());
}
源码中是在扫描的时候用到的 , 这一块的源码之前有详细的入口 , 不清楚的可以在本篇文章中Ctrl+f搜一下这个方法 , 这个方法就会传入一个包路径 , 然后加载资源
在开发中我们可以这样使用
@Component
public class MemberService implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void test1(){
Resource resource = applicationContext.getResource("");
System.out.println("test1方法被调用 resource " + resource);
}
}
EnvironmentCapable
可以获取运行时环境(没有设置运行时环境功能)
public class TestSpring {
public static void main(String[] args){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// 获取操作系统层面的环境变量
Map<String, Object> systemEnvironment = applicationContext.getEnvironment().getSystemEnvironment();
System.out.println(systemEnvironment);
System.out.println("=======");
// 获取通过-d的方式指定的配置文件
Map<String, Object> systemProperties = applicationContext.getEnvironment().getSystemProperties();
System.out.println(systemProperties);
System.out.println("=======");
// 获取通过注解指定的配置文件的值 : @PropertySource("classpath:spring.properties")
MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources();
System.out.println(propertySources);
System.out.println("=======");
// 也可以指定具体的值 操作系统
System.out.println(applicationContext.getEnvironment().getProperty("NO_PROXY"));
// 通过-d指定的参数
System.out.println(applicationContext.getEnvironment().getProperty("sun.jnu.encoding"));
// 获取spring.properties配置文件的内容
System.out.println(applicationContext.getEnvironment().getProperty("lyh"));
}
}
ApplicationEventPublisher
拥有广播事件的功能(没有添加事件监听器的功能)
首先在Appconfig定义一个事件发布器
@Bean
public ApplicationListener applicationListener() {
return new ApplicationListener() {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("接收到了一个事件 : " + event);
}
};
}
在工作中我们也可以这样用
@Component
public class MemberService implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void test(){
String message = applicationContext.getMessage("test", null, new Locale("en"));
System.out.println("test方法被调用 message为 " + message);
}
public void test1(){
Resource resource = applicationContext.getResource("");
System.out.println("test1方法被调用 resource " + resource);
}
public void test2(){
applicationContext.publishEvent("kkk");
System.out.println("test2方法被调用 发布了事件");
}
}
当我们调用test2()方法时就会发布一个事件
MessageSource
拥有国际化功能
我们首先在resources下新建一个文件
右键resources --> new --> resource Bundle , 然后就会出来如下图所示的界面 , 我们首先定义一个名称 : message(名称随意) , 然后添加一个英语 , 点击确认
然后就会帮我们创建出两个文件
我们在两个文件中指定如下内容 , 内容随意
在AppConfig中定义一个MessageSource
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("message");
return messageSource;
}
有了这个Bean,你可以在你任意想要进行国际化的地方使用该MessageSource。
同时,因为ApplicationContext也拥有国家化的功能,所以可以直接这么用:
public class TestSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// en对应配置文件message_en的'en'
String message = applicationContext.getMessage("test", null, new Locale("en"));
System.out.println(message);
}
}
但是我们在实际开发中肯定不是以这样的方式去获取国际化资源 , 那么应该怎么做呢?
@Component
public class MemberService implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void test(){
String message = applicationContext.getMessage("test", null, new Locale("en"));
System.out.println("test方法被调用 message为 " + message);
}
}
就像这样 , 我们实现一下ApplicationContextAware接口 , 这样不就想怎么用就怎么用了吗
关于ApplicationContext我们也有两个经常使用的具体的实现类
AnnotationConfigApplicationContext
ConfigurableApplicationContext
继承了ApplicationContext接口,增加了,添加事件监听器、添加BeanFactoryPostProcessor、设置Environment,获取ConfigurableListableBeanFactory等功能
AbstractApplicationContext
实现了ConfigurableApplicationContext接口 , AbstractApplicationContext是Spring应用上下文中最重要的一个类,这个抽象类中提供了几乎ApplicationContext的所有操作。主要有容器工厂的处理,事件的发送广播,监听器添加,容器初始化操作refresh方法,然后就是bean的生成获取方法接口等。主要还是提供了一些方法,复杂的操作也是没有太多。
GenericApplicationContext
继承了AbstractApplicationContext,实现了BeanDefinitionRegistry接口,拥有了所有ApplicationContext的功能,并且可以注册BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory beanFactory)
AnnotationConfigRegistry
可以单独注册某个为类为BeanDefinition(可以处理该类上的@Configuration注解,已经可以处理@Bean注解),同时可以扫描
AnnotationConfigApplicationContext
继承了GenericApplicationContext,实现了AnnotationConfigRegistry
AnnotationConfigRegistry
拥有了以上所有的功能
ClassPathXmlApplicationContext
它也是继承了AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition , 并且现在用AnnotationConfigApplicationContext比较多一点 , 所以ClassPathXmlApplicationContext就不着重说了
PropertyEditor
这其实是JDK中提供的类型转化工具类 , 在Spring源码中,有可能需要把String转成其他类型,所以在Spring源码中提供了一些技术来更方便的做对象的类型转化,关于类型转化的应用场景, 后续看源码的过程中会遇到很多。
定义类型转换器
public class StringToUserPropertyEditor extends PropertyEditorSupport implements PropertyEditor {
@Override
public void setAsText(String text) throws IllegalArgumentException {
User user = new User();
user.setName(text);
this.setValue(user);
}
}
StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();
// 设置要转换的值
propertyEditor.setAsText("1");
User value = (User) propertyEditor.getValue();
System.out.println(value);
如何向Spring中注册PropertyEditor:
@Bean
public CustomEditorConfigurer customEditorConfigurer() {
CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
Map<Class<?>, Class<? extends PropertyEditor>> propertyEditorMap = new HashMap<>();
// 表示StringToUserPropertyEditor可以将String转化成User类型,在Spring源码中,如果发现当前对象是String,而需要的类型是User,就会使用该PropertyEditor来做类型转化
propertyEditorMap.put(User.class, StringToUserPropertyEditor.class);
customEditorConfigurer.setCustomEditors(propertyEditorMap);
return customEditorConfigurer;
}
假设现在有如下Bean:
@Component
public class UserService {
@Value("lyh")
private User user;
public void test() {
System.out.println(user);
}
}
当我们使用/@Value(“lyh”)想为user赋值时 , Spring就会去看程序员有没有定义一个类型转换器 , 可以把String转换为user, 因为我们刚刚向容器注册了一个类型转换器, 那么user属性就能正常的完成属性赋值
ConversionService
Spring中提供的类型转化服务,它比PropertyEditor更强大
public class StringToUserConverter implements ConditionalGenericConverter {
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
// sourceType.getType() : 带转换的类型
// targetType.getType(): 转换后类型
return sourceType.getType().equals(String.class) && targetType.getType().equals(User.class);
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(String.class, User.class));
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
// 转换的逻辑
User user = new User();
user.setName((String)source);
return user;
}
}
public class TestSpring {
public static void main(String[] args){
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToUserConverter());
User value = conversionService.convert("1", User.class);
System.out.println(value);
}
}
如何向Spring中注册ConversionService:
@Bean
public ConversionServiceFactoryBean conversionService() {
ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));
return conversionServiceFactoryBean;
}
TypeConverter
整合了PropertyEditor和ConversionService的功能,是Spring内部用的 , 因为我们在实际使用的时候可能会同时定义PropertyEditor和ConversionService , 所以Spring就用SimpleTypeConverter来把两种方式都添加进去
public class TestSpring {
public static void main(String[] args){
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());
//typeConverter.setConversionService(conversionService);
User value = typeConverter.convertIfNecessary("1", User.class);
System.out.println(value);
}
}
这个类型转换器在源码中是这样体现的
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService" , MemberService.class);
System.out.println(memberService);
这样我们就不用强制转换了 , 我们来看看源码 , 我们进入到doGetBean()方法
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name, requiredType);
}
继续进入getBean() , 此时应该到了BeanFactory的getBean();
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
然后进入到AbstractBeanFactory的getBean();
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
进入到doGetBean()即可
最后会看到
return adaptBeanInstance(name, beanInstance, requiredType);
它首先判断当前Bean的类型是否和给定的类型相符 , 如果不同 , 就会进行类型转换 , 能不能转的过来 , 就要看有没有定义上面的这些类型转换器 , 如果可以强转, 那么就返回 , 如果不可以强转, 那么就会报异常, 类型不符 , 如果没有指定 , 就直接返回
OrderComparator
OrderComparator是Spring所提供的一种比较器,可以用来根据@Order注解或实现Ordered接口来执行值进行笔记,从而可以进行排序 , 比如:
public class A implements Ordered {
@Override
public int getOrder() {
return 3;
}
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}
public class B implements Ordered {
@Override
public int getOrder() {
return 2;
}
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}
public class Main {
public static void main(String[] args) {
A a = new A(); // order=3
B b = new B(); // order=2
OrderComparator comparator = new OrderComparator();
System.out.println(comparator.compare(a, b)); // 1
List list = new ArrayList<>();
list.add(a);
list.add(b);
// 按order值升序排序
list.sort(comparator);
System.out.println(list); // B,A
}
}
另外,Spring中还提供了一个OrderComparator的子类:AnnotationAwareOrderComparator,它支持用@Order来指定order值。比如:
@Order(3)
public class A {
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}
@Order(2)
public class B {
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}
public class Main {
public static void main(String[] args) {
A a = new A(); // order=3
B b = new B(); // order=2
AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
System.out.println(comparator.compare(a, b)); // 1
List list = new ArrayList<>();
list.add(a);
list.add(b);
// 按order值升序排序
list.sort(comparator);
System.out.println(list); // B,A
}
}
BeanPostProcessor
BeanPostProcess表示Bena的后置处理器,我们可以定义一个或多个BeanPostProcessor,比如通过一下代码定义一个BeanPostProcessor:
@Component
public class ZhouyuBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("userService".equals(beanName)) {
System.out.println("初始化前");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("userService".equals(beanName)) {
System.out.println("初始化后");
}
return bean;
}
}
一个BeanPostProcessor可以在任意一个Bean的初始化之前以及初始化之后去额外的做一些用户自定义的逻辑,当然,我们可以通过判断beanName来进行针对性处理(针对某个Bean,或某部分Bean)。
我们可以通过定义BeanPostProcessor来干涉Spring创建Bean的过程。
BeanFactoryPostProcessor
BeanFactoryPostProcessor表示Bean工厂的后置处理器,其实和BeanPostProcessor类似,BeanPostProcessor是干涉Bean的创建过程,BeanFactoryPostProcessor是干涉BeanFactory的创建过程。比如,我们可以这样定义一个BeanFactoryPostProcessor:
@Component
public class ZhouyuBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("加工beanFactory");
}
}
我们可以在postProcessBeanFactory()方法中对BeanFactory进行加工。
FactoryBean
上面提到,我们可以通过BeanPostPorcessor来干涉Spring创建Bean的过程,但是如果我们想一个Bean完完全全由我们来创造,也是可以的,比如通过FactoryBean:
@Component
public class LyhFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
UserService userService = new UserService();
return userService;
}
@Override
public Class<?> getObjectType() {
return UserService.class;
}
}
通过上面这段代码,我们自己创造了一个UserService对象,并且它将成为Bean。但是通过这种方式创造出来的UserService的Bean,只会经过初始化后,其他Spring的生命周期步骤是不会经过的,比如依赖注入。
有同学可能会想到,通过@Bean也可以自己生成一个对象作为Bean,那么和FactoryBean的区别是什么呢?
其实在很多场景下他俩是可以替换的,但是站在原理层面来说的,区别很明显,@Bean定义的Bean是会经过完整的Bean生命周期的。而FactoryBean只是经过了初始化后这一步 , 因为虽然是以实现FactoryBean重写方法的方式定义的Bean , 但是不能把AOP这个功能给抛弃了
它的源码也是在doGetBean() , 如下图 , 一定要注意transformedBeanName()这个方法 , 等等我们来讲用途
它会判断 , 如果没有实现FactoryBean ,会直接返回 , 否则进行处理
到这里 , 它就会执行getObject()方法 , 然后返回 , getObject()方法也就是你自己实现了FactoryBean接口所重写的方法
然后我们再来说第一张图片的transformedBeanName()方法 , 如果实现了FactoryBean , 那么这个类也是一个Bean ,那么我们想获取这个Bean怎么获取呢?就比如上面的例子 , 我想获取LyhFactoryBean , 怎么获取呢?
public class TestSpring {
public static void main(String[] args){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// 返回getObject()方法返回的Bean
UserService userService = (UserService)applicationContext.getBean("lyhFactoryBean");
System.out.println(userService);
// 返回LyhFactoryBean
LyhFactoryBean lyhFactoryBean = (LyhFactoryBean)applicationContext.getBean("&lyhFactoryBean");
System.out.println(lyhFactoryBean);
所以transformedBeanName()方法其实是针对这种情况做了处理
ExcludeFilter和IncludeFilter
这两个Filter是Spring扫描过程中用来过滤的。ExcludeFilter表示排除过滤器,IncludeFilter表示包含过滤器。
比如以下配置,表示扫描com.lyh这个包下面的所有类,但是排除UserService类,也就是就算它上面有
@Component注解也不会成为Bean。
@ComponentScan(value = "com.lyh",
excludeFilters = {@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class)}.)
public class AppConfig {
}
再比如以下配置,就算UserService类上没有@Component注解,它也会被扫描成为一个Bean。
@ComponentScan(value = "com.lyh",
includeFilters = {@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class)})
public class AppConfig {
}
FilterType分为:
ANNOTATION:表示是否包含某个注解
ASSIGNABLE_TYPE:表示是否是某个类
ASPECTJ:表示否是符合某个Aspectj表达式
REGEX:表示是否符合某个正则表达式
CUSTOM:自定义
在Spring的扫描逻辑中,默认会添加一个AnnotationTypeFilter给includeFilters,表示默认情况下Spring扫描过程中会认为类上有@Component注解的就是Bean。
MetadataReader、ClassMetadata、AnnotationMetadata
在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.zhouyu.service.UserService");
// 得到一个ClassMetadata,并获取了类名
ClassMetadata classMetadata = metadataReader.getClassMetadata();
System.out.println(classMetadata.getClassName());
// 获取一个AnnotationMetadata,并获取类上的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
for (String annotationType : annotationMetadata.getAnnotationTypes()) {
System.out.println(annotationType);
}
}
}
那么有人会想 , 为什么不用反射呢?
其实SimpleMetadataReaderFactory类的功能是非常强大的 , 它可以获取接口的名称 , 获取内部类的名称 , 通过一个方法的直接调用就可以 , 但是用反射获取要写不少代码 , 对于这些类的API大家可以动手来试验一下 , 更容易理解
需要注意的是SimpleMetadataReader去解析类时,使用的ASM技术。
为什么要使用ASM技术
Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不太好,所以使用了ASM技术。
本篇文章到这里就结束了 , 介绍了Spring一些比较重要的常用的类的基本功能 , 概念, 在阅读Spring的源码中 , 我们可以知道个所以然 , 知道大概是干什么用的 , 这样会比较方便一点