Spring中的包扫描
在Spring中bean的注入有两种方式:
- 自定义bean:xml或配置类
- 注解,设置自动扫描
Spring中xml配置文件:
**配置类:**在类上加注解@Configuration,将类设置为配置类代替xml配置文件
由程序员手动设置bean是比较繁琐的,Spring又提供了偷懒的方法
注解、自动扫描:
在springmvc.xml中<context:component-scan base-package="com.learn.controller"/>
,即可扫描controller包下的所有bean
@Controller注解即表示该类为Spring中的一个bean
配置类中的自动扫描:即然@Configuration注解的配置类类似与xml配置文件,那能不能设置自动扫描?
@ComponentScan 注解:默认扫描该类所在的包下所有的配置类
那么没有在Config类中注入的bean,只要在当前目录下设置了,就可以从Spring容器中得到:
例如:当前目录下Beer并没有在Config中注入
Beer类设置为Spring组件:
测试类依旧可以直接得到:
Spring中通过@ComponentScan注解或者 < context:component-scan >标签完成包扫描
那么SpringBoot中呢?
SpringBoot中的包扫描
我们知道SpringBoot中:我们编写的类比较放置在xxApplication类所在目录下
这不就是前面Spring中的包扫描:扫描该类所在的包下所有的配置类
一个SpringBoot案例:
我们找不到任何关于包扫描的xml或者注解,定义好一个controller,然后启动就可以访问了?这是为什么?
这就是为什么说SpringBoot是Spring的精简加强版
SpringBoot包扫描原理
一切的秘密都在这:
SpringBoot的启动类中有很多东西,这里仅分析包扫描的原理
@SpringBootApplication
@SpringBootApplication注解的三个重要子注解:
- @SpringBootConfiguration注解就是SpringBoot版的@Configuration注解:表示这是一个配置类
- @EnableAutoConfiguration注解是设置启动时的自动装配
-
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
即包扫描
里面的内容是什么意思呢?excludeFilters表示哪些类不用被扫描到
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class)
custom表示自定义过滤规则(需要实现TypeFilter接口),TypeExcludeFilter就是SpringBoot定义的过滤类
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
自定义的匹配注册的自动配置类的过滤类AutoConfigurationExcludeFilter
那么是如何实现扫描该类所在的包呢?
SpringApplication.run(MyspringbootApplication.class, args)
该方法是SpringBoot的核心,其中有很多方法用于准备SpringBoot的环境、配置等
我们关注3个有关context方法:
- createApplicationContext()
- prepareContext(…)
- refreshContext(context)
createApplicationContext: 创建Spring容器,返回ConfigurableApplicationContext
我们都知道ApplicationContext就是Spring的核心的IoC容器
prepareContext: 即准备context
其中有一个load(context, sources.toArray(new Object[0]))
方法(多层方法),最终进入
isComponent方法判断类是否有Component的注解,明显启动类是有的,即将启动类注册
refreshContext(context):刷新context
很复杂
refreshContext方法 -》 invokeBeanFactoryPostProcessors方法 -》ConfigurationClassPostProcessor类 -》 processConfigBeanDefinitions方法 -》 parser.parse(candidates)方法 -》parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());方法 -》 processConfigurationClass方法 -》doProcessConfigurationClass方法
终于到了处理ComponentScan注解的方法:
其中的componentScans.isEmpty()的判断,即判定配置@ComponentScan的这个属性,得到添加的这个启动类的名字的最后一个点之前的路径,比如启动类是A.B.C.D.class, 那么路径就是A.B.C.D
Spring会通过传入的路径来遍历下面的每一个class
结语
SpringBoot是Spring的简化,需要配置的操作全部实现了自动化(自动装配)
SpringBoot的包扫描是隐藏的,需要深究才能找到
SpringBoot源码太复杂了,希望以后能看懂