Spring初始化原理(系列)之Bean的初始化原理

之前一直都是在使用Spring框架进行开发,从最初开始使用时候的依赖注入,到第三方框架集成,慢慢就发现Spring真的好神奇啊,居然可以这么玩,完全颠覆了以前的开发方式,但是随着现在Spring MVC+Spring+Spring-Data组合,使我们完全不需要十分关注框架具体细节,只需要关注具体的业务逻辑即可。但是随着现代软件的快速发展,分布式,高并发,微服务化最终到云计算,我们一整套技术栈都可以通过Spring来实现,比如从Spring MVC,Spring Boot,Spring webFlux,Spring Cloud,这一系列的技术栈可以帮助我们快速的上手开发,特别是Spring Boot的自动配置,让我不得不开始研究Spring具体的实现原理了,以前框架搭建,都是用到那里去查那里的源码,并没有投入太多的精力去研究Spring的具体实现,但是现在到了不得不去研究的地步,因为如果不深入去研究下Spring的实现原理,想要开发基于Spring高质量,灵活的,高可靠的程序很难,写一个可用的程序其实很简单,当用户到达一定的量级的时候,就很难处理了。就好比我们现在每天都在说的优化,优化有很多东西,比如数据库优化,程序优化,容器优化,JVM优化,其实我们以上说的所有,针对环境的优化其实对改善性能提高不会太多,而程序的执行性能,技术栈的选型才是核心优化的内容,所以想要开发高效,高质量的程序,必须对Spring实现原理进行探索和研究,而不是通过网上的理论流程,而是实实在在的通过代码去跑一编,来整理出自己想要得出的结论和自己所想是否一致,这个必须要进一步验证,今天我们就来说说Spring的Bean加载原理。

我们已注解的形式来进行梳理,因为从4.0开始Spring就推进使用注解的形式来进行开发及配置,所以我们就先来说一说注解,Spring的核心注解是@Component,其他所有的注解都是标注了该注解的注解且是@Component注解的别名。在类ClassPathScanningCandidateComponentProvider中有详细的说明,代码如下:

/**
	 * Register the default filter for {@link Component @Component}.
	 * 

This will implicitly register all annotations that have the * {@link Component @Component} meta-annotation including the * {@link Repository @Repository}, {@link Service @Service}, and * {@link Controller @Controller} stereotype annotations. *

Also supports Java EE 6's {@link javax.annotation.ManagedBean} and * JSR-330's {@link javax.inject.Named} annotations, if available. * */ @SuppressWarnings("unchecked") protected void registerDefaultFilters() { this.includeFilters.add(new AnnotationTypeFilter(Component.class)); ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader(); try { this.includeFilters.add(new AnnotationTypeFilter( ((Class) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false)); logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning"); } catch (ClassNotFoundException ex) { // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip. } try { this.includeFilters.add(new AnnotationTypeFilter( ((Class) ClassUtils.forName("javax.inject.Named", cl)), false)); logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning"); } catch (ClassNotFoundException ex) { // JSR-330 API not available - simply skip. } }

我们可以很清楚逇看到,默认情况下会过滤@Component这个注解的接口类,所以我们也就很好理解Spring是所管理的容器都是那些类了,而且当我门自定义注解后,只需要标注@Comonent这个注解即可,就会被Spring扫描到,是不是很神奇。然后我们只需实现直接的AOP拦截对应的注解,实现特定的功能需求即可。注解说完了,下面我们来说说Spring是如何扫描Bean的。 主要是以下几个类实现的逻辑。分别是:

ComponentScanBeanDefinitionParser
ClassPathBeanDefinitionScanner
ClassPathScanningCandidateComponentProvider
PathMatchingResourcePatternResolver
CachingMetadataReaderFactory
SimpleMetadataReaderFactory

通过以上这几个类就可以实现Bean的初始化,Spring将资源进一步进行了封装,通过Resource来封装,就可以通过统一的接口来对资源处理,这几个类介绍完了,下面我们就开始说说具体的逻辑吧。

  1. 通过ClassLoader加载资源获取资源路径。
  2. 拼接路径及匹配模式classpath*:com/demo/test/**/*.class
  3. 获取绝对路径D:/environments/mytest/target/classes/com/demo/test/**/*.class
  4. 获取路径下所有的类包括jar包中的类
  5. 遍历Resource[]中所有的类,判断是否包含了@Component注解,如果包含则加入Spring容器。
  6. 后续的依赖处理。

这就是Bean的扫描策略了,以上整理的知识可能还不够准确,还需要进一步完善,今天就先写到这里,后续继续完善。如果有什么好的意见或建议请留言。

 

 

你可能感兴趣的:(spring)