service灯亮无法启动是什么原因,service灯亮为什么清不掉

首页 > 经验 > 作者:YD1662022-10-29 23:57:06

excludeFilter和IncludeFilter用于扫描时判断class是否符合要求。

默认的excludeFilter:扫描时排除掉自己这个class

默认的includeFilter: 扫描时判断该class是否标识@Component注解

4.Bean定义扫描器

BeanDefinitionScanner主要做了三件事:

1、扫描包路径下的类

2、给BeanDefiniton设值

3、使用BeanDefinition注册器将BeanDefiniton注册到容器中

4.1扫描包路径下的类

扫描包路径的步骤可以简单理解为遍历class文件的过程,遍历包下的每个class,判断该class是否满足条件——标识了@Component注解,将满足条件的class转化为BeanDefiniton,此时BeanDefiniton只有metedata信息,还没有具体设值。

4.2给BeanDefiniton设值

如果我们在类上加了类似这些注解:@Lazy @Primary @DependsOn,那么就需要将这些注解转化为实际的属性设到BeanDefiniton中。

4.3流程图

service灯亮无法启动是什么原因,service灯亮为什么清不掉(5)

5.BeanDefinition注册器

BeanDefinitionRegistry的作用就是将BeanDefiniton放到BeanDefinitonMap中

思考

现在我们已经知道了扫描包的整体过程,再来回顾一下这个问题:Mybatis的Mapper是怎么注入到Spring容器中的?

像这种问题咋一看很难理解,常常在面试的情况发生,因为面试官是拿着答案问问题。

但是我们思考的话,就应该换个角度:怎么才能让Mapper注册到Spring中 -> 怎么才能让自定义的注解标识的Class注册到Spring中?

不知道这样问是否简单些呢?

方法1.使用TypeFilter

我们知道@Component注解是和默认注册的IncludeFilter配套使用的,那么同样我们也可以使用一个自定义的IncludeFilter与我们的自定义注解配套使用

自定义Mapper注解

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Mapper { }

使用Mapper

@Mapper public class MyMapper { public void hello(){ System.out.println("myMapper hello"); } }

测试

添加一个自定义的IncludeFilter进行测试

service灯亮无法启动是什么原因,service灯亮为什么清不掉(6)

**注意:**此方式只能支持自定义注解标识在实体类的情况,如果将Mapper注解加在接口上,则你会收获一个异常:No bean named 'myMapper' available

答案很简单,因为接口不能实例化,所以Spring默认判断如果该类非实体类,则不注册到容器中。

那么我们怎么才能让加了Mapper注解的接口能注册到Spring中呢?

2.自定义扫描器

既然Spring的扫描器无法支持接口,那么我们就重写它——的判断逻辑。

开源框架扩展心得:继承整体逻辑,重写一小块逻辑。

所以我们方式很简单:继承ClassPathBeanDefinitionScanner,重写判断Class是否符合的逻辑

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner { @Override protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { // 重写判断beanDefinition是否为接口逻辑,改为只有类为接口时才允许注册 return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent(); } //省略构造方法 }

逻辑已经改好了,现在迎来一个新问题:怎么让Spring使用它?

通过整体流程我们知道,Bean定义扫描器是在**@ComponentScan注解解析器**的解析流程中创建(new)出来的,我们又不能更改这个流程,所以, Game Over?

但,为什么一定要在Spring的扫描流程中使用我们的扫描器呢?我们可以在Spring的扫描流程结束后,再扫描一遍不就好了吗?

还记得有什么方式可以做到这件事吗?后置处理器!

3.使用后置处理器

我们通过使用BeanDefinitionRegistryPostProcessor,让Spring的扫描流程结束之后,进行一次后置处理。在后置处理中,创建出自定义的扫描器,进行第二次扫描。

@Component public class MapperScannerProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { // 创建出自定义的扫描器 ClassPathMapperScanner classPathMapperScanner = new ClassPathMapperScanner(registry, false); // 添加filter,class添加了Mapper注解才注册到Spring中 classPathMapperScanner.addIncludeFilter(new AnnotationTypeFilter(Mapper.class)); // 这里可以改为从外部设值,不必写死 classPathMapperScanner.scan("com.my.spring.test.custom"); } }

使用这种方式,你会发现,我们的接口确实注册到BeanDefinitionMap中了。

service灯亮无法启动是什么原因,service灯亮为什么清不掉(7)

但是,你仍然会收到一个错误:Failed to instantiate [com.my.spring.test.custom.InterfaceMapper]: Specified class is an interface

接口确实是无法实例化的,虽然我们把它注册到了Spring中。但Mybatis又是怎么做的呢?

答案是替换,Mybatis将图中的beanClass替换成了FactoryBean: MapperFactoryBean,然后将原有的beanClass放入了它的mapperInterface属性中

它的getObject方法长这样

public T getObject() throws Exception { return getSqlSession().getMapper(this.mapperInterface); }

如果你还记得Mybatis的原始使用方式,应该对这行代码并不陌生。

好了,关于思考的内容就到这里,我们只是借用Mybatis的现象进行思考,再深入就是Mybatis的内容了。

小结

本文借助一个开发时常见的问题进行分析,介绍了Spring的配置类解析与扫描过程,同时,还借助了Mybatis中的现象,思考怎么才能让自定义的注解标识Class注册到Spring中这一问题,并使用案例给出了一份较好的答案,希望大家能够通过案例更加深入的了解该流程。

同样,通过本次学习,来回答一下以下问题吧

1、什么是配置类?Spring中有哪几种配置类?有什么区别?

2、BeanDefinitionRegistryPostProcessor有什么用?你知道哪些案例吗?

你是不是心里想,好家伙敖丙还学会留可课后作业了?

我是敖丙,你知道的越多,你不知道的越多,感谢各位人才的:点赞收藏评论,我们下期见!


文章持续更新,回复【资料】有我准备的一线大厂面试资料和简历模板,有大厂面试完整考点。

,
上一页12末页

栏目热文

文档排行

本站推荐

Copyright © 2018 - 2021 www.yd166.com., All Rights Reserved.