当前位置:   article > 正文

Spring-容器的扫描器相关源码_this.getapplicationstartup().start("spring.context

this.getapplicationstartup().start("spring.context.annotated-bean-reader.cre

首先看创建一个Spring容器的代码:

  1. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  2. 源码:
  3. /**
  4. * Create a new AnnotationConfigApplicationContext that needs to be populated
  5. * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
  6. */
  7. public AnnotationConfigApplicationContext() {
  8. StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
  9. // 额外会创建StandardEnvironment
  10. this.reader = new AnnotatedBeanDefinitionReader(this);
  11. createAnnotatedBeanDefReader.end();
  12. this.scanner = new ClassPathBeanDefinitionScanner(this);
  13. }

StartupStep是什么?

StartupStep是Spring5.3版本新增的,有两个实现类:DefaultStartupStep和FlightRecorderStartupStep

默认使用的是DefaultStartupStep,其实里面什么事情都没有做

FlightRecorderStartupStep使用了jdk9还是11以后的一个新特性,叫JFR

JFR简述:在jdk层面,提供的java程序,在生产运行过程中可以监控的一种机制,就像飞机的黑盒子,记录运行速度、性能

注意:这里不是Spring内部提供的牛逼功能,而是Spring利用jdk新特性的一个点,例如记录执行步骤的时间

了解JFR,可参考文章:深度探索JFR - JFR详细介绍与生产问题定位落地 - 1. JFR说明与启动配置 - 知乎

创建一个Spring容器主要做了什么事情呢?

扫描、创建非懒加载的单例Bean

接下来再看ClassPathBeanDefinitionScanner的扫描方法:(重点关注doScan方法)

  1. public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
  2. private final BeanDefinitionRegistry registry;
  3. ... ...
  4. /**
  5. * Perform a scan within the specified base packages,
  6. * returning the registered bean definitions.
  7. * <p>This method does <i>not</i> register an annotation config processor
  8. * but rather leaves this up to the caller.
  9. * @param basePackages the packages to check for annotated classes
  10. * @return set of beans registered if any for tooling registration purposes (never {@code null})
  11. */
  12. protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
  13. Assert.notEmpty(basePackages, "At least one base package must be specified");
  14. Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
  15. for (String basePackage : basePackages) {
  16. // 核心扫描逻辑,得到BeanDefinition
  17. Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
  18. for (BeanDefinition candidate : candidates) {
  19. // 解析Scope注解,单例还是原型设置进来
  20. ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
  21. candidate.setScope(scopeMetadata.getScopeName());
  22. // @Component注解有没有指定名字,指定直接返回,没有指定构造默认的
  23. // 默认根据类的短名生成。大部分情况首字母小写,但是类名前两个字母都是大写就直接返回类名
  24. // 举例默认情况:UserService - userService; ABTest - ABTest
  25. String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
  26. if (candidate instanceof AbstractBeanDefinition) {
  27. // 遍历出来的BeanDefinition设置默认值
  28. postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
  29. }
  30. if (candidate instanceof AnnotatedBeanDefinition) {
  31. // 解析@Lazy、@Primary、@DependsOn、@Role、@Description,设置给BeanDefinition对应的属性
  32. AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
  33. }
  34. // 检查Spring容器中是否已经存在该beanName
  35. if (checkCandidate(beanName, candidate)) {
  36. BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
  37. definitionHolder =
  38. AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
  39. beanDefinitions.add(definitionHolder);
  40. // 注册
  41. registerBeanDefinition(definitionHolder, this.registry);
  42. }
  43. }
  44. }
  45. return beanDefinitions;
  46. }
  47. /**
  48. * Scan the class path for candidate components.
  49. * @param basePackage the package to check for annotated classes
  50. * @return a corresponding Set of autodetected bean definitions
  51. */
  52. public Set<BeanDefinition> findCandidateComponents(String basePackage) {
  53. if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
  54. return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
  55. }
  56. else {
  57. return scanCandidateComponents(basePackage);
  58. }
  59. }
  60. private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
  61. Set<BeanDefinition> candidates = new LinkedHashSet<>();
  62. try {
  63. // 获取basePackage下所有的文件资源,匹配所有的class文件
  64. String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
  65. resolveBasePackage(basePackage) + '/' + this.resourcePattern;
  66. // 资源,class文件的File对象
  67. Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
  68. boolean traceEnabled = logger.isTraceEnabled();
  69. boolean debugEnabled = logger.isDebugEnabled();
  70. for (Resource resource : resources) {
  71. if (traceEnabled) {
  72. logger.trace("Scanning " + resource);
  73. }
  74. if (resource.isReadable()) {
  75. try {
  76. // 类的元数据读取器,类的注解信息、名字、是不是抽象、实现的接口名字、父类等
  77. // 底层使用的ASM技术,metadataReader相当于类的一个代表
  78. MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
  79. // excludeFilters、includeFilters判断
  80. // includeFilters判断:默认添加一个@Component注解(创建扫描器时添加的)
  81. if (isCandidateComponent(metadataReader)) {
  82. ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
  83. sbd.setSource(resource);
  84. if (isCandidateComponent(sbd)) {
  85. if (debugEnabled) {
  86. logger.debug("Identified candidate component class: " + resource);
  87. }
  88. candidates.add(sbd);
  89. }
  90. else {
  91. if (debugEnabled) {
  92. logger.debug("Ignored because not a concrete top-level class: " + resource);
  93. }
  94. }
  95. }
  96. else {
  97. if (traceEnabled) {
  98. logger.trace("Ignored because not matching any filter: " + resource);
  99. }
  100. }
  101. }
  102. catch (Throwable ex) {
  103. throw new BeanDefinitionStoreException(
  104. "Failed to read candidate component class: " + resource, ex);
  105. }
  106. }
  107. else {
  108. if (traceEnabled) {
  109. logger.trace("Ignored because not readable: " + resource);
  110. }
  111. }
  112. }
  113. }
  114. catch (IOException ex) {
  115. throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
  116. }
  117. return candidates;
  118. }
  119. /**
  120. * Determine whether the given class does not match any exclude filter
  121. * and does match at least one include filter.
  122. * @param metadataReader the ASM ClassReader for the class
  123. * @return whether the class qualifies as a candidate component
  124. */
  125. protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
  126. // 如果传入的类和任何一个排除过滤器匹配了,就返回false,表示不是一个Bean
  127. for (TypeFilter tf : this.excludeFilters) {
  128. if (tf.match(metadataReader, getMetadataReaderFactory())) {
  129. return false;
  130. }
  131. }
  132. // 符合includeFilters的会进行条件匹配,通过了才是Bean,也就是先看有没有@Component,再看是否符合@Conditional
  133. for (TypeFilter tf : this.includeFilters) {
  134. // 有@Component注解匹配
  135. if (tf.match(metadataReader, getMetadataReaderFactory())) {
  136. return isConditionMatch(metadataReader);
  137. }
  138. }
  139. return false;
  140. }
  141. /**
  142. * Determine whether the given class is a candidate component based on any
  143. * {@code @Conditional} annotations.
  144. * @param metadataReader the ASM ClassReader for the class
  145. * @return whether the class qualifies as a candidate component
  146. */
  147. private boolean isConditionMatch(MetadataReader metadataReader) {
  148. if (this.conditionEvaluator == null) {
  149. this.conditionEvaluator =
  150. new ConditionEvaluator(getRegistry(), this.environment, this.resourcePatternResolver);
  151. }
  152. return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
  153. }
  154. /**
  155. * Determine if an item should be skipped based on {@code @Conditional} annotations.
  156. * The {@link ConfigurationPhase} will be deduced from the type of item (i.e. a
  157. * {@code @Configuration} class will be {@link ConfigurationPhase#PARSE_CONFIGURATION})
  158. * @param metadata the meta data
  159. * @return if the item should be skipped
  160. */
  161. public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
  162. return shouldSkip(metadata, null);
  163. }
  164. /**
  165. * Determine if an item should be skipped based on {@code @Conditional} annotations.
  166. * @param metadata the meta data
  167. * @param phase the phase of the call
  168. * @return if the item should be skipped
  169. */
  170. public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
  171. // 没有@Conditional注解,就不要跳过,当前类是一个Bean(有@Component,没有@Conditional)
  172. if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
  173. return false;
  174. }
  175. if (phase == null) {
  176. if (metadata instanceof AnnotationMetadata &&
  177. ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
  178. return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
  179. }
  180. return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
  181. }
  182. List<Condition> conditions = new ArrayList<>();
  183. for (String[] conditionClasses : getConditionClasses(metadata)) {
  184. for (String conditionClass : conditionClasses) {
  185. Condition condition = getCondition(conditionClass, this.context.getClassLoader());
  186. conditions.add(condition);
  187. }
  188. }
  189. AnnotationAwareOrderComparator.sort(conditions);
  190. for (Condition condition : conditions) {
  191. ConfigurationPhase requiredPhase = null;
  192. if (condition instanceof ConfigurationCondition) {
  193. requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
  194. }
  195. if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
  196. return true;
  197. }
  198. }
  199. return false;
  200. }
  201. /**
  202. * Create a new ScannedGenericBeanDefinition for the class that the
  203. * given MetadataReader describes.
  204. * @param metadataReader the MetadataReader for the scanned target class
  205. */
  206. public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
  207. Assert.notNull(metadataReader, "MetadataReader must not be null");
  208. this.metadata = metadataReader.getAnnotationMetadata();
  209. // 这里只是把className设置到BeanDefinition中
  210. setBeanClassName(this.metadata.getClassName());
  211. setResource(metadataReader.getResource());
  212. }
  213. /**
  214. * Specify the bean class name of this bean definition.
  215. */
  216. @Override
  217. public void setBeanClassName(@Nullable String beanClassName) {
  218. // 把className设置到BeanDefinition的beanClass属性,beanClass是Object类型
  219. this.beanClass = beanClassName;
  220. }
  221. /**
  222. * Determine whether the given bean definition qualifies as candidate.
  223. * <p>The default implementation checks whether the class is not an interface
  224. * and not dependent on an enclosing class.
  225. * <p>Can be overridden in subclasses.
  226. * @param beanDefinition the bean definition to check
  227. * @return whether the bean definition qualifies as a candidate component
  228. */
  229. protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
  230. AnnotationMetadata metadata = beanDefinition.getMetadata();
  231. // 不是独立的,不能成为Bean(如果是一个顶级类或者静态内部类,那么就是独立的)
  232. // isConcrete:!(是接口||是抽象类),说白了就不是接口,也不是抽象类
  233. // 是抽象类,但是类里面有@Lookup注解修饰的方法,可以成为Bean
  234. // 总结:独立的;不是接口也不是抽象类;是抽象类,并且类内方法有@Lookup注解。三种情况是Bean
  235. return (metadata.isIndependent() && (metadata.isConcrete() ||
  236. (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
  237. }
  238. /**
  239. * Check the given candidate's bean name, determining whether the corresponding
  240. * bean definition needs to be registered or conflicts with an existing definition.
  241. * @param beanName the suggested name for the bean
  242. * @param beanDefinition the corresponding bean definition
  243. * @return {@code true} if the bean can be registered as-is;
  244. * {@code false} if it should be skipped because there is an
  245. * existing, compatible bean definition for the specified name
  246. * @throws ConflictingBeanDefinitionException if an existing, incompatible
  247. * bean definition has been found for the specified name
  248. */
  249. protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
  250. if (!this.registry.containsBeanDefinition(beanName)) {
  251. return true;
  252. }
  253. BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
  254. BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
  255. if (originatingDef != null) {
  256. existingDef = originatingDef;
  257. }
  258. // 是否兼容,如果兼容返回false表示不会重新注册到Spring容器中,如果不冲突则会抛异常。
  259. if (isCompatible(beanDefinition, existingDef)) {
  260. return false;
  261. }
  262. throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
  263. "' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
  264. "non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
  265. }
  266. ... ...
  267. }

思考:BeanDefinitionRegistry能不能用DefaultListableBeanFactory替换?

DefaultListableBeanFactory是BeanDefinitionRegistry的重要实现类,功能上可以替换但是没有必要。

这里扫描器主要的功能是:把扫描得到的BeanDefinition注册到Spring容器里面去,注册功能是BeanDefinitionRegistry这个接口提供的。DefaultListableBeanFactory确实有注册的功能,但是DefaultListableBeanFactory还有很多其他的功能,这里并不需要。单一职责

实际运行的时候registry属性的值就是DefaultListableBeanFactory对象

注意:有@Component注解不一定是一个Bean。如果还有@Conditional注解,就要看条件是否匹配,条件匹配了才是一个Bean,条件不匹配就不是一个Bean(@Conditional注解指定的类需要实现Condition接口,并且重写matches方法,matches方法返回true表示匹配,返回false不匹配)

BeanDefinition的beanClass属性为什么是Object类型?而不是Class?

扫描到setBeanClassName方法这里时,是通过ASM技术去解析这个类,并没有去加载这个类,只是把Bean的名字设置给BeanDefinition的beanClass属性。等真正的去加载这个Bean时,才会得到Class对象,再把这个对象赋值给beanClass属性。这里使用Object就是考虑到两种情况:最开始赋值的是Bean的名字,加载后赋值Class对象

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/609349
推荐阅读
相关标签
  

闽ICP备14008679号