米6体育app-这是属于功能上的缺失
你的位置:米6体育app > 米6体育app > 这是属于功能上的缺失
这是属于功能上的缺失
发布日期:2022-02-16 13:51    点击次数:91

这是属于功能上的缺失

媒介

为什么需要Spring? 什么是Spring?米6体育app

关于这么的问题,大部分人都是处于一种朦拖沓胧的景色,说的出来,但又不是十足说的出来,今天咱们就以架构设计的角度尝试解开Spring的宛转面纱。

本篇著述以轮回渐进的方式进行先容,大家不消蹙悚,我不错保证,只消你会编程就能看懂。

本篇著述基于Spring 5.2.8,阅读时长大略需要20分钟

案例

咱们先来看一个案例:有一个小伙,有一辆祯祥车, 粗俗就开祯祥车上班

代码已矣:

public 米6体育appclass GeelyCar {      public void run(){         System.out.println("geely running");     } } 
public class Boy {   // 依赖GeelyCar     private final GeelyCar geelyCar = new GeelyCar();      public void drive(){         geelyCar.run();     } } 

有一天,小伙赢利了,又买了辆红旗,想开新车。

约略,把依赖换成HongQiCar

代码已矣:

public class HongQiCar {      public void run(){         System.out.println("hongqi running");     } } 
public class Boy {     // 修改依赖为HongQiCar     private final HongQiCar hongQiCar = new HongQiCar();      public void drive(){         hongQiCar.run();     } } 

新车开腻了,又想换回老车,这期间,就会出现一个问题:这个代码一直在改来改去

很彰着,这个案例违背了咱们的依赖颠倒原则(DIP):法式不应依赖于已矣,而应依赖于空洞

优化后

当今咱们对代码进行如下优化:

Boy依赖于Car接口,而之前的GeelyCar与HongQiCar为Car接口已矣

代码已矣:

界说出Car接口

public interface Car {      void run(); } 

将之前的GeelyCar与HongQiCar改为Car的已矣类

public class GeelyCar implements Car {      @Override     public void run(){         System.out.println("geely running");     } } 

HongQiCar相易

Person此时依赖的为Car接口

public class Boy {   // 依赖于接口     private final Car car;        public Person(Car car){         this.car = car;     }      public void drive(){         car.run();     } } 

此时小伙想换什么车开,就传入什么参数即可,代码不再发生变化。

局限性

以上案例改良后看起来如实莫得什么舛讹了,但如故存在一定的局限性,淌若此时增多新的场景:

有一天小伙喝酒了没法开车,需要找个代驾。代驾并不关切他给哪个小伙开车,也不关切开的是什么车,小伙就短暂成了个空洞,这期间码又要进行调动了,代驾依赖小伙的代码可能会长这个花式:

private final Boy boy = new YoungBoy(new HongQiCar()); 

跟着系统的复杂度增多,这么的问题就会越来越多,越来越难以保重,那么咱们应当怎样措置这个问题呢?

思考

率先,咱们不错确定:使用依赖颠倒原则是莫得问题的,它在一定进度上措置了咱们的问题。

咱们以为出问题的场所是在传入参数的过程:法式需要什么咱们就传入什么,一但系统中出现多重依赖的类关系,这个传入的参数就会变得极其复杂。

随机咱们不错把思绪回转一下:咱们有什么,法式就用什么!

当咱们只已矣HongQiCar和YoungBoy时,代驾就使用的是开着HongQiCar的YoungBoy!

当咱们只已矣GeelyCar和OldBoy时,代驾自关联词然就改酿成了开着GeelyCar的OldBoy!

而怎样回转,等于Spring所措置的一浩劫题。

Spring先容

Spring是一个一站式轻量级分量级的拓荒框架,标的是为了措置企业级诓骗拓荒的复杂性,它为拓荒Java诓骗法式提供全面的基础架构救助,让Java拓荒者不再需要关切类与类之间的依赖关系,不错专注的拓荒诓骗法式(crud)。

Spring为企业级拓荒提供给了丰富的功能,而这些功能的底层都依赖于它的两个中枢特质:依赖注入(DI)和面向切面编程(AOP)。

Spring的中枢见识 IoC容器

IoC的全称为Inversion of Control,意为欺压回转,IoC也被称为依赖性注入(DI),这是一个通过依赖注入对象的过程:对象仅通过构造函数、工场要领,或者在对象实例化在其上缔造的属性来界说其依赖关系(即与它们组合的其他对象),然后容器在创建bean时注入这些需要的依赖。这个过程从根底上说是Bean自己通过使用径直构建类或诸如干事定位模式的机制,来欺压其依赖关系的实例化或位置的逆过程(因此被称为欺压回转)。

依赖颠倒原则是IoC的设计旨趣,依赖注入是IoC的已矣方式。

容器

在Spring中,咱们不错使用XML、Java注解或Java代码的方式来编写设置信息,而通过设置信息,获得相干实例化、设置和拼装对象的阐发,进行实例化、设置和拼装诓骗对象的称为容器。

一般情况下,咱们只需要添加几个注解,这么容器进行创建和运行化后,咱们就不错得到一个可设置的,可实践的系统或诓骗法式。

Bean

在Spring中,由Spring IOC容器进行实例化—>拼装治理—>组成法式骨架的对象称为Bean。Bean等于诓骗法式中无边对象之一。

以上三点串起来等于:Spring里面是一个摒弃Bean的IoC容器,通过依赖注入的方式处理Bean之间的依赖关系。

AOP

面向切面编程(Aspect-oriented Programming),是相对面向对象编程(OOP)的一种功能补充,OOP面向的主要对象是类,而AOP则是切面。在处理日记、安全治理、事务治理等方面有相配报复的作用。AOP是Spring框架报复的组件,固然IOC容器莫得依赖AOP,但是AOP提供了相配强大的功能,用来对IOC做补充。

AOP不错让咱们在不修改原有代码的情况下,对咱们的业务功能进行增强:将一段功能切入到咱们指定的位置,如在要领的调用链之间打印日记。

Spring的优点

1、Spring通过DI、AOP来简化企业级Java拓荒

2、Spring的低侵入式设计,让代码的玷辱极低

3、Spring的IoC容器缩短了业务对象之间的复杂性,让组件之间彼此解耦

4、Spring的AOP救助允许将一些通用任务如安全、事务、日记等进行集中式处理,从而擢升了更好的复用性

5、Spring的高度盛开性,并不彊制诓骗十足依赖于Spring,拓荒者可解放选用Spring框架的部分或全部

6、Spring的高度推广性,让路发者不错应答的让我方的框架在Spring上进行集成

7、Spring的生态极其完好,集成了种种优秀的框架,让路发者不错应答的使用它们

咱们不错莫得Java,但是不可莫得Spring~

用Spring改良案例

咱们当今也曾意识了什么是Spring,当今就尝试使用Spring对案例进行改良一下

正本的结构莫得变化,只需在GeelyCar或HongQiCar上增多@Component注解,Boy在使用时加上@Autowired注解

代码形态:

@Componentpublic class GeelyCar implements Car { @Override public void run() {  System.out.println("geely car running"); }} 

HongQiCar相易

在Spring中,当类记号了@Component注解后就暗意这是一个Bean,不错被IoC容器所治理

@Componentpublic class Boy {  // 使用Autowired注解暗意car需要进行依赖注入 @Autowired private Car car; public void driver(){  car.run(); }} 

咱们之前所说的:咱们已矣什么,法式就使用什么,在这里就等同于咱们在哪个类上记号了Component注解,哪个类就会是一个Bean,Spring就会使用它注入Boy的属性Car中

是以当咱们给GeelyCar记号Component注解时,Boy开的车等于GeelyCar,当咱们给HongQiCar记号Component注解时,Boy开的车等于HongQiCar

天然,咱们不不错在GeelyCar和HongQiCar上同期记号Component注解,因为这么Spring就不潜入用哪个Car进行注入了——Spring也有采取清贫症(or 一boy不可开俩车?)

使用Spring启动法式

// 告诉Spring从哪个包下扫描Bean,不写等于面前包旅途@ComponentScan(basePackages = "com.my.spring.test.demo")public class Main { public static void main(String[] args) {  // 将Main(设置信息)传入到ApplicationContext(IoC容器)中  ApplicationContext context = new AnnotationConfigApplicationContext(Main.class);  // 从(IoC容器)中获得到咱们的boy  Boy boy = (Boy) context.getBean("boy");  // 开车  boy.driver(); }} 

这里就不错把咱们刚刚先容Spring的学问进行解读了

把具有ComponentScan注解(设置信息)的Main类,传给AnnotationConfigApplicationContext(IoC容器)进走运行化,就等于:IoC容器通过获得设置信息进行实例化、治理和拼装Bean。

而怎样进行依赖注入则是在IoC容器里面完成的,这亦然本文要盘问的重心

思考

咱们通过一个改良案例完好的意识了Spring的基本功能,也对之前的见识有了一个具象化的体验,而咱们还并不潜入Spring的依赖注入这一里面动作是怎样完成的,所谓知其然更要知其是以然,聚会咱们的现存学问,以及对Spring的领路,斗胆猜测推测一下吧(这是很报复的才略哦)

其实推断等于指:淌若让咱们我方已矣,咱们会怎样已矣这个过程?

率先,咱们要潜入咱们需要做的事情是什么:扫描指定包底下的类,进行实例化,并把柄依赖关系组合好。

设施瓦解:

扫描指定包底下的类 -> 淌若这个类记号了Component注解(是个Bean) -> 把这个类的信息存起来

进行实例化 -> 遍历存好的类信息 -> 通过反射把这些类进行实例化

把柄依赖关系组合 -> 解析类信息 -> 判断类中是否有需要进行依赖注入的字段 -> 对字段进行注入

有筹算已矣

咱们当今也曾有了一个看起来像是那么一趟事的措置有筹算,当今就尝试把这个有筹算已矣出来

界说注解

率先咱们需要界说出需要用到的注解:ComponentScan,Component,Autowired

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ComponentScan {      String basePackages() default ""; } 
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Component {      String value() default ""; } 
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Autowired { } 
扫描指定包底下的类

扫描指定包下的通盘类,听起来好像一时迷吞吐糊,其实它等同于另一个问题:怎样遍历文献目次?

那么存放类信息应该用什么呢?咱们望望上头例子中getBean的要领,是不是像Map中的通过key获得value?而Map中还有好多已矣,但线程安全的却惟有一个,那等于ConcurrentHashMap(别跟我说HashTable)

界说存放类信息的map

private final Map<String, Class<?>> classMap = new ConcurrentHashMap<>(16); 

具体经由,底下雷同附上代码已矣:

代码已矣,不错与经由图聚会调查:

扫描类信息

private void scan(Class<?> configClass) {   // 解析设置类,获得到扫描包旅途   String basePackages = this.getBasePackages(configClass);   // 使用扫描包旅途进行文献遍历操作   this.doScan(basePackages); } 
private String getBasePackages(Class<?> configClass) {   // 从ComponentScan注解中获得扫描包旅途   ComponentScan componentScan = configClass.getAnnotation(ComponentScan.class);   return componentScan.basePackages(); } 
private void doScan(String basePackages) {   // 获得资源信息   URI resource = this.getResource(basePackages);    File dir = new File(resource.getPath());   for (File file : dir.listFiles()) {     if (file.isDirectory()) {       // 递归扫描       doScan(basePackages + "." + file.getName());     }     else {       // com.my.spring.example + . + Boy.class -> com.my.spring.example.Boy       String className = basePackages + "." + file.getName().replace(".class", "");       // 将class存放到classMap中       this.registerClass(className);     }   } } 
private void registerClass(String className){   try {     // 加载类信息     Class<?> clazz = classLoader.loadClass(className);     // 判断是否记号Component注解     if(clazz.isAnnotationPresent(Component.class)){       // 生成beanName com.my.spring.example.Boy -> boy       String beanName = this.generateBeanName(clazz);       // car: com.my.spring.example.Car       classMap.put(beanName, clazz);     }   } catch (ClassNotFoundException ignore) {} } 
实例化

当今也曾把通盘适合的类都解析好了,接下来等于实例化的过程了

界说存放Bean的Map

private final Map<String, Object> beanMap = new ConcurrentHashMap<>(16); 

具体经由,底下雷同给出代码已矣:

代码已矣,不错与经由图聚会调查:

遍历classMap进行实例化Bean

public void instantiateBean() {   for (String beanName : classMap.keySet()) {     getBean(beanName);   } } 
public Object getBean(String beanName){   // 先从缓存中获得   Object bean = beanMap.get(beanName);   if(bean != null){     return bean;   }   return this.createBean(beanName); } 
private Object createBean(String beanName){   Class<?> clazz = classMap.get(beanName);   try {     // 创建bean     Object bean = this.doCreateBean(clazz);     // 将bean存到容器中     beanMap.put(beanName, bean);     return bean;   } catch (IllegalAccessException e) {     throw new RuntimeException(e);   } } 
private Object doCreateBean(Class<?> clazz) throws IllegalAccessException {  // 实例化bean  Object bean = this.newInstance(clazz);  // 填充字段,将字段设值  this.populateBean(bean, clazz);  return bean;} 
private Object newInstance(Class<?> clazz){  try {    // 这里只救助默许构造器    return clazz.getDeclaredConstructor().newInstance();  } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {    throw new RuntimeException(e);  }} 
private void populateBean(Object bean, Class<?> clazz) throws IllegalAccessException {  // 解析class信息,判断类中是否有需要进行依赖注入的字段  final Field[] fields = clazz.getDeclaredFields();  for (Field field : fields) {    Autowired autowired = field.getAnnotation(Autowired.class);    if(autowired != null){      // 获得bean      Object value = this.resolveBean(field.getType());      field.setAccessible(true);      field.set(bean, value);    }  }} 
private Object resolveBean(Class<?> clazz){  // 先判断clazz是否为一个接口,是则判断classMap中是否存在子类  if(clazz.isInterface()){    // 暂时只救助classMap惟有一个子类的情况    for (Map.Entry<String, Class<?>> entry : classMap.entrySet()) {      if (clazz.isAssignableFrom(entry.getValue())) {        return getBean(entry.getValue());      }    }    throw new RuntimeException("找不到不错进行依赖注入的bean");  }else {    return getBean(clazz);  }} 
public Object getBean(Class<?> clazz){   // 生成bean的称号   String beanName = this.generateBeanName(clazz);   // 此处对应最动手的getBean要领   return this.getBean(beanName); } 
组合

两个中枢要领也曾写好了,接下把它们组合起来,我把它们已矣在自界说的ApplicationContext类中,构造要领如下:

public ApplicationContext(Class<?> configClass) {   // 1.扫描设置信息中指定包下的类   this.scan(configClass);   // 2.实例化扫描到的类   this.instantiateBean(); } 

UML类图:

测试

代码结构与案例相易,这里展示一下咱们我方的Spring是否不错平方运行

运行平方,中国人不骗中国人

源码会在文末给出

转头

当今,咱们也曾把柄假想的有筹算进行了已矣,运行的情况也达到了预期的恶果。但淌若仔细规齐整下,再聚会咱们粗俗使用Spring的场景,就会发现这一份代码的不少问题:

1、无法救助构造器注入,天然也莫得救助要领注入,这是属于功能上的缺失。

2、加载类信息的问题,加载类时咱们使用的是classLoader.loadClass的方式,固然这幸免了类的运行化(可千万别用Class.forName的方式),但如故不可幸免的把类元信息加载到了元空间中,当咱们扫描包下有不需要的类时,这就销耗了咱们的内存。

3、无法措置bean之间的轮回依赖,比如有一个A对象依赖了B对象, B对象又依赖了A对象,这个期间咱们再来望望代码逻辑,就会发现此时会堕入死轮回。

4、推广性很差,咱们把通盘的功能都写在一个类里,当想要完善功能(比如以上3个问题)时,就需要往往修改这个类,这个类也会变得越来越肥壮,别说迭代新功能,保重都会令人头疼。

优化有筹算

关于前三个问题都访佛于功能上的问题,功能嘛,改一改就好了。

咱们需要谨防关注的是第四个问题,一款框架想要变得优秀,那么它的迭代才略一定要好,这么功能时间变得丰富,而迭代才略的影响要素有好多,其中之一等于它的推广性。

那么应该怎样擢升咱们的有筹算的推广性呢,六大设计原则给了咱们很好的率领作用。

在有筹算中,ApplicationContext做了好多事情, 主要不错分为两大块

1、扫描指定包下的类

2、实例化Bean

借助单一使命原则的思惟:一个类只做一种事,一个要领只做一件事。

咱们把扫描指定包下的类这件事单独使用一个处理器进行处理,因为扫描设置是从设置类而来,那咱们就叫他设置类处理器:ConfigurationCalssProcessor

实例化Bean这件事情也雷同如斯,实例化Bean又分为了两件事:实例化和依赖注入

实例化Bean等于颠倒于一个坐蓐Bean的过程,咱们就把这件事使用一个工场类进行处理,它就叫做:BeanFactory,既然是在坐蓐Bean,那就需要原料(Class),是以咱们把classMap和beanMap都界说到这里

而依赖注入的过程,其实等于在处理Autowired注解,那它就叫做: AutowiredAnnotationBeanProcessor

咱们还在潜入,在Spring中,不单是惟有这种使用方式,还有xml,mvc,SpringBoot的方式,是以咱们将ApplicationContext进行空洞,只已矣骨干经由,正本的注解方式交由AnnotationApplicationContext已矣。

借助依赖颠倒原则:法式应当依赖于空洞

在异日,类信息不单是不错从类信息来,也不错从设置文献而来,是以咱们将ConfigurationCalssProcessor空洞

而依赖注入的方式不一定非得是用Autowried注解记号,也不错是别的注解记号,比如Resource,是以咱们将AutowiredAnnotationBeanProcessor空洞

Bean的类型也不错有好多,不错是单例的,不错使多例的,也不错是个工场Bean,是以咱们将BeanFactory空洞

当今,咱们借助两大设计原则对咱们的有筹算进行了优化,比较于之前可谓是”夺胎换骨“。

Spring的设计

在上一步,咱们已矣了我方的有筹算,并基于一些假想进行了推广性优化,当今,咱们就来意识一下本色上Spring的设计

那么,在Spring中又是由哪些"扮装"组成的呢?

1、Bean: Spring手脚一个IoC容器,最报复确天然是Bean咯

2、BeanFactory: 坐蓐与治理Bean的工场

3、BeanDefinition: Bean的界说,也等于咱们有筹算中的Class,Spring对它进行了封装

4、BeanDefinitionRegistry: 访佛于Bean与BeanFactory的关系,BeanDefinitionRegistry用于治理BeanDefinition

5、BeanDefinitionRegistryPostProcessor: 用于在解析设置类时的处理器,访佛于咱们有筹算中的ClassProcessor

6、BeanFactoryPostProcessor: BeanDefinitionRegistryPostProcessor父类,让咱们不错再解析设置类之后进行后置处理

7、BeanPostProcessor: Bean的后置处理器,用于在坐蓐Bean的过程中进行一些处理,比如依赖注入,访佛咱们的AutowiredAnnotationBeanProcessor

8、ApplicationContext: 淌若说以上的扮装都是在工场中坐蓐Bean的工人,那么ApplicationContext等于咱们Spring的门面,ApplicationContext与BeanFactory是一种组合的关系,是以它十足推广了BeanFactory的功能,并在其基础上添加了更多特定于企业的功能,比如咱们熟知的ApplicationListener(事件监听器)

以上说的访佛其实有一些秦伯嫁女了,因为本色上应该是咱们有筹算中的已矣访佛于Spring中的已矣,这么说只是为了让大家更好的领路

咱们在阅历了我方有筹算的设计与优化后,对这些扮装其实口角常容易领路的

接下来,咱们就一个一个的详备了解一下

BeanFactory

BeanFactory是Spring中的一个顶级接口,它界说了获得Bean的方式,Spring中还有另一个接口叫SingletonBeanRegistry,它界说的是操作单例Bean的方式,这里我将这两个放在一路进行先容,因为它们大体相易,SingletonBeanRegistry的注目上也写了不错与BeanFactory接口一路已矣,肤浅调理治理。

BeanFactory

1、ListableBeanFactory:接口,界说了获得Bean/BeanDefinition列表相干的要领,如getBeansOfType(Class type)

2、AutowireCapableBeanFactory:接口,界说了Bean生命周期相干的要领,如创建bean, 依赖注入,运行化

3、AbstractBeanFactory:空洞类,基本上已矣了通盘相干Bean操作的要领,界说了Bean生命周期相干的空洞要领

4、AbstractAutowireCapableBeanFactory:空洞类,吸收了AbstractBeanFactory,已矣了Bean生命周期相干的内容,固然是个空洞类,但它莫得空洞要领

5、DefaultListableBeanFactory:吸收与已矣以上通盘类和接口,是为Spring中最底层的BeanFactory, 自身已矣了ListableBeanFactory接口

6、ApplicationContext:亦然一个接口,咱们会不才面有独特对它的先容

SingletonBeanRegistry

1、DefaultSingletonBeanRegistry: 界说了Bean的缓存池,访佛于咱们的BeanMap,已矣了相干单例的操作,比如getSingleton(口试常问的三级缓存就在这里)

2、FactoryBeanRegistrySupport:提供了对FactoryBean的救助,比如从FactoryBean中获得Bean

BeanDefinition

BeanDefinition其实亦然个接口(想不到吧),这里界说了许多和类信息相干的操作要领,肤浅在坐蓐Bean的期间径直使用,比如getBeanClassName

它的大略结构如下(这里例如RootBeanDefinition子类):

里面的种种属性想必大家也毫不目生

雷同的,它也有许多已矣类:

1、AnnotatedGenericBeanDefinition:解析设置类与解析Import注解带入的类时,就会使用它进行封装

2、ScannedGenericBeanDefinition:封装通过@ComponentScan扫描包所得到的类信息

3、ConfigurationClassBeanDefinition:封装通过@Bean注解所得到的类信息

4、RootBeanDefinition:ConfigurationClassBeanDefinition父类,一般在Spring里面使用,将其他的BeanDefition升沉成该类

BeanDefinitionRegistry

界说了与BeanDefiniton相干的操作,如registerBeanDefinition,getBeanDefinition,在BeanFactory中,已矣类等于DefaultListableBeanFactory

BeanDefinitionRegistryPostProcessor

插话:讲到这里,有莫得发现Spring的定名极其范例,Spring团队曾言Spring中的类名都是仔细探究才证据的,真的名副其实呀,是以看Spring源码真的是一件很豪放的事情,望望类名要领名就能猜出它们的功能了。

该接口只界说了一个功能:处理BeanDefinitonRegistry,也等于解析设置类中的Import、Component、ComponentScan等注解进行相应的处理,处理完毕后将这些类注册成对应的BeanDefinition

在Spring里面中,惟有一个已矣:ConfigurationClassPostProcessor

BeanFactoryPostProcessor

所谓BeanFactory的后置处理器,它界说了在解析完设置类后不错调用的处理逻辑,访佛于一个插槽,淌若咱们想在设置类解析完后做点什么,就不错已矣该接口。

在Spring里面中,雷同惟有ConfigurationClassPostProcessor已矣了它:用于独特处理加了Configuration注解的类

这里串场一个小问题,如知以下代码:

@Configuraiton public class MyConfiguration{   @Bean   public Car car(){       return new Car(wheel());   }   @Bean   public Wheel wheel(){       return new Wheel();   } } 

问:Wheel对象在Spring启动时,被new了几次?为什么?

BeanPostProcessor

江湖翻译:Bean的后置处理器

该后置处理器一语气了Bean的生命周期通盘过程,在Bean的创建过程中,一姜被调用了9次,至于哪9次咱们下次再来探究,以下先容它的已矣类以及作用

1、AutowiredAnnotationBeanPostProcessor:用于推断构造器进行实例化,以及处理Autowired和Value注解

2、CommonAnnotationBeanPostProcessor:处理Java范例中的注解,如Resource、PostConstruct

3、ApplicationListenerDetector: 在Bean的运行化后使用,将已矣了ApplicationListener接口的bean添加到事件监听器列表中

4、ApplicationContextAwareProcessor:用于回调已矣了Aware接口的Bean

5、ImportAwareBeanPostProcessor: 用于回调已矣了ImportAware接口的Bean

ApplicationContext

ApplicationContext手脚Spring的中枢,以门面模式拒绝了BeanFactory,以模板要领模式界说了Spring启动经由的骨架,又以战略模式调用了种种各样的Processor......确实是纵横交叉又精妙绝伦!

它的已矣类如下:

1、ConfigurableApplicationContext:接口,界说了设置与生命周期相干操作,如refresh

2、AbstractApplicationContext: 空洞类,已矣了refresh要领,refresh要领手脚Spring中枢中的中枢,不错说通盘Spring皆在refresh之中,通盘子类都通过refresh要领启动,在调用该要领之后,将实例化通盘单例

3、AnnotationConfigApplicationContext: 在启动时使用相干的注解读取器与扫描器,往Spring容器中注册需要用的处理器,尔后在refresh要领在被主经由调用即可

4、AnnotationConfigWebApplicationContext:已矣loadBeanDefinitions要领,以期在refresh经由中被调用,从而加载BeanDefintion

5、ClassPathXmlApplicationContext: 同上

从子类的情况不错看出,子类的不同之处在于怎样加载BeanDefiniton, AnnotationConfigApplicationContext是通过设置类处理器(ConfigurationClassPostProcessor)加载的,而AnnotationConfigWebApplicationContext与ClassPathXmlApplicationContext则是通过我方已矣loadBeanDefinitions要领,其他经由则十足一致

米6体育app官网客服QQ:865083652

Spring的经由

以上,咱们也曾潜入了Spring中的主要扮装以及作用,当今咱们尝试把它们组合起来,构建一个Spring的启动经由

雷同以咱们常用的AnnotationConfigApplicationContext为例

图中只画出了Spring中的部分大略经由,详备内容咱们会在背面的章节伸开

小结

所谓万事发轫难,本文初志等于能让大家以轮回渐进的方式意识Spring,初步成立Spring的阐明体系,赫然Spring的里面架构,对Spring的阐明不再浮于名义。

当今头也曾开了,肯定背面内容的学习也将水到渠来。

本篇著述既讲是Spring的架构设计,也但愿能成为咱们以后温习Spring举座内容时使用的手册。

临了,看完著述之后,肯定对以下口试常问的问题讲演起来亦然举手之劳

上次我们深入讲解了 Ribbon 的架构原理,这次我们再来看下 Feign 远程调用的架构原理。

1、什么是BeanDefinition?

2、BeanFactory与ApplicationContext的关系?

3、后置处理器的分类与作用?

4、Spring的主要经由是奈何样的?

淌若小伙伴以为没主义很好讲演上来的话就再望望著述,或者在指摘区留住我方的观点吧

好啦,我是敖丙,你潜入的越多,你不潜入的越多,咱们下期见。