后面你相熟了SpringBoot的扩大点SpringApplicationRunListeners的设计,配置文件ConfigurableEnvironment的形象封装。其实这些都还不是它最外围的,最最外围的时Spring的容器的创立和筹备,主动配置的拆卸,tomcat的容器的启动。
这一节咱们就来开始钻研Spring的容器相干的逻辑,看看它有什么形象的设计和扩大点,又次要做了哪一些事件呢?
public ConfigurableApplicationContext run(String... args) { //扩大点 SpringApplicationRunListeners listeners.starting(); //配置文件的解决和形象封装 ConfigurableEnvironment //容器相干解决 context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] {ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments,printedBanner); refreshContext(context); //其余逻辑}
容器相干的逻辑次要由三个办法组成:createApplicationContext()、prepareContext()、refreshContext()。
这三个办法,每一个都做了很多事件,咱们一个个来剖析下。
Spring容器的创立时的外围组件
createApplicationContext容器创立的逻辑,其实非常简单,就是通过反射创立了一个容器的实现类,默认创立AnnotationConfigServletWebServerApplicationContext。
代码如下:
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot." + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { switch (this.webApplicationType) { case SERVLET: contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS); break; case REACTIVE: contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break; default: contextClass = Class.forName(DEFAULT_CONTEXT_CLASS); } } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }
你可能第一次看这个办法,只是这样晓得了反射创立了一个容器的实现类可能就完结了。
你其实能够看下这个类反射创立也是会走构造函数的,所以能够简略剖析下创立时,初始化了那些组件。
你跟着成长记,剖析了很多对象的创立,你会发现,剖析这个类的脉络,或者组件,画一个图,根本都曾经造成一个固定的剖析套路了。
//本身构造函数 public AnnotationConfigServletWebServerApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); } //父类构造函数 public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); }
次要创立的是DefaultListableBeanFactory,Reader和一个Scanner。
之前遍及过一个Spring根本术语,大家还记得么?容器通常称为ApplicationContext或者BeanFactory,context也简称为容器。ApplicationContext包装了BeanFactory,封装更高级的API而已,有各种实现类。
所以DefaultListableBeanFactory这个就是真正的容器对象。
术语遍及BeanDefinition、BeanDefinitionRegistry、InternalBean
这里波及到了新的术语遍及BeanDefinition、BeanDefinitionRegistry。
BeanDefinition示意了其实就是咱们交给对Spring容器治理对象,也就是Bean的形容和定义,比方这个Bean是否是单例、是否有依赖其余Bean、依赖了那些Bean、Bean的名称、别名等等。
BeanDefinitionRegistry封装了对BeanDefinition常见操作的接口,容器默认实现了这个接口,所以个别它也代表了容器。容器BeanFactory实现了它,能够通过实现的办法,保护List<BeanDefinition>。
InternalBean 其实是指Spring本人注入的相干Bean,用来实现SpringBoot的外围性能的。
Context的构造函数除了创立DefaultListableBeanFactory容器,而Reader和一个Scanner他们各自有本人的创立流程。我简略画个图给大家概括下:
上图概括了Reader和Scanner的组件,其中最最外围的是外部Bean的加载,其余的组件都是为了容器服务的而已。
总而言之,能够看到容器创立时候,Reader和一个Scanner是负责扫描和解析注解的,能够扫描所有相干Bean定义的注解,并且本人还会补充外部提前定义的一些Bean。并且这些internalBean都是默认写死的一些BeanDefination,暗藏在构造函数汇中加载的一步,这一步十分要害,SpringBoot外围性能的实现点都是靠写bean来实现的,前面咱们会看到的。
从Reader和Scanner开始思考下Spring容器的形象设计
晓得这个AnnotationConfigServletWebServerApplicationContext容器的外围组件后,咱们能够思考下,这些组件是用来做什么的?之间的关系是啥,次要形象进去是为了做什么呢?
你能够设想下,Spring容器的目标是为了IOC,也就是帮咱们保护大量Bean对象的创立和治理。那么外围问题就是,这些Bean是怎么找到,并且创立到容器中的呢?
这就关系到了很要害的形象设计。它就是从Resource->ClassLoader->Reader/Scanner->BeanDefination的设计了。
Resource
我来具体解释下,Resource顾名思义,示意的是各种资源。包含了各种Bean形容文件,如java类中@Bean @Configuration的定义,@Service和@Controller的定义,又比方xml中<bean/>标签的定义,groovy中bean的定义等等。这些够能够统称为资源。
ResourceLoader(ClassLoader)
这些资源都是在classpath上面的,只有通过ClassLoader咱们能够扫描到和加载到的。
Reader
然而因为这些资源的定义bean的格局各种各样,此时就须要一个形象,来对立解析这些资源,所以就有了Reader和Scanner了,不同的Reader解析不同的文件,如xmlReader,groovyReader等,注解定义的Bean通过Scanner来找到,并且解析辨认。
BeanDefination
最终辨认为Bean的一个形象定义BeanDefination。容器会保护相应的汇合,记录所有的Bean的定义。
这就是Spring容器十分好的一个形象设计,很值得咱们借鉴学习。
整体能够能够概括如下图所示:
创立了容器,容器外部,有一些组件能够帮忙容器辨认到Bean,并且对立解析为BeanDefination。心愿你能够领悟到这个,这个对你了解Spring容器十分要害的。
至于具体每一个Reader或Scanner如何通过ClassLoader扫描和查找资源的,创立容器这里还没有波及,之后如果能够的话,大家再仔细分析这些组件就能够了。
最初提一点,创立容器后,有一段exceptionReporters的获取,这个从名字就能够猜出来,是解决异样统计和汇报的组件,不是很要害,咱们抓大放小,过就能够了。
public ConfigurableApplicationContext run(String... args) { //扩大点 SpringApplicationRunListeners listeners.starting(); //配置文件的解决和形象封装 ConfigurableEnvironment //容器相干解决,外围剖析了它的外围组件脉络和形象设计 context = createApplicationContext(); //解决异样统计和汇报的组件,不重要,抓大放小,过就能够了。 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] {ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments,printedBanner); refreshContext(context); //其余逻辑}
小结
明天咱们次要剖析了容器的创立。外围剖析了它的外围组件脉络和形象设计
1)外围组件Reader和Scanner,还有最要害的DefaultListableBeanFactory。并且相熟了BeanDefinition、BeanDefinitionRegistry的概念。
2)容器要害的形象设计,从Resource->ClassLoader->Reader/Scanner->BeanDefination。Spring通过这样的设计来获取到Bean对象的定义,最终帮咱们治理对象。
下一节咱们来一起看下有了容器对象,会为容器筹备和设置哪些其余的内容,在这个过程中,容器又有会执行哪一些扩大点。
本文由博客一文多发平台 OpenWrite 公布!