Spring知识点

Spring是什么

Spring是一个轻量级Java开发框架,目的是为了解 决企业级应用开发的业务逻辑层和其他各层的耦合问题;它为企业级开发提供给了丰富的功能,但是这些功能 的底层都依赖于它的两个核心特性,也就是依赖注入(dependency injection,DI)和面向切面编程(aspect-oriented programming, AOP)

IoC是什么?

对于Spring框架来说,就是由Spring来负责控制对象的生命周期和对象间的关系。

DI是什么?

IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的

IoC和DI的区别是什么?

IoC是要达成的目标;DI是实现IoC的一种方式。

IoC主要的实现方式有两种:依赖查找,依赖注入。依赖注入是一种更可取的方式。

依赖查找需要去查找创建Bean所需的依赖;而依赖注入则让Bean自己定义它创建所需的依赖。很明显,依赖注入的效率更高,所以依赖注入是一种更可取的方式。

Spring启动的大致流程(IoC容器加载过程)

IoC容器开始加载通常开始于如下一段代码:

ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");

然后开始执行IoC容器的加载,首先将提供的路径加载成配置文件数组,然后开始执行refresh方法来初始化ApplicationContext。

image-20220220103405913

    @Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
				contextRefresh.end();
			}
		}
	}

整个IOC容器的启动过程就在这个方法里。启动流程如下:

  1. 加锁;首先是使用synchronized关键字加锁,确保refresh方法只会调用一次
  2. prepareRefresh;为容器启动做准备工作,主要包括记录容器的启动时间、标记“已启动”状态和处理配置文件中的占位符等
  3. 注册BeanDefinition到BeanFactory;把配置文件解析成一个个Bean,并且注册到BeanFactory中(此处只是注册,这些Bean并没有初始化)
    1. BeanDefinition (Bean定义)
    2. BeanDefinitionRegistry(Bean注册器)
    3. BeanDefinitionReader(Bean定义读取)
  4. prepareBeanFactory(beanFactory);设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean,这里都是spring里面的特殊处理
  5. postProcessBeanFactory(beanFactory);提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化,具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类,来完成一些其他的操作
  6. invokeBeanFactoryPostProcessors(beanFactory);调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
  7. registerBeanPostProcessors(beanFactory);注册 BeanPostProcessor 的实现类
  8. initMessageSource();初始化当前 ApplicationContext 的 MessageSource,国际化处理
  9. initApplicationEventMulticaster();方法初始化当前 ApplicationContext 的事件广播器
  10. onRefresh();方法初始化一些特殊的 Bean(在初始化 singleton beans 之前)
  11. registerListeners();方法注册事件监听器,监听器需要实现 ApplicationListener 接口
  12. finishBeanFactoryInitialization(beanFactory);初始化所有的 singleton beans(单例bean),懒加载(non-lazy-init)的除外(spring默认不是懒加载,如果设定了懒加载,则bean的初始化由getbean方法触发)
  13. finishRefresh();最后一步,广播事件,ApplicationContext 初始化完成

简化的加载过程如下:

  1. 刷新预处理
  2. 将配置信息解析,注册到BeanFactory
  3. 设置bean的类加载器
  4. 如果有第三方想再bean加载注册完成后,初始化前做点什么(例如修改属性的值,修
    改bean的scope为单例或者多例。),提供了相应的模板方法,后面还调用了这个方
    法的实现,并且把这些个实现类注册到对应的容器中
  5. 初始化当前的事件广播器
  6. 初始化所有的bean。(懒加载不执行这一步)
  7. 广播applicationcontext初始化完成。

Spring中后置处理器(BeanPostProcessor)的作用

如果我们想在Spring容器中完成bean实例化、配置以及其他初始化方法前后要添加一些自己逻辑处理。我们需要定义一个或多个BeanPostProcessor接口实现类,然后注册到Spring IoC容器中。

Bean的生命周期

  1. Spring Bean 元信息配置阶段,可以通过面向资源(XML 或 Properties)、面向注解、面向 API 进行配置
  2. Spring Bean 元信息解析阶段,对上一步的配置元信息进行解析,解析成 BeanDefinition 对象,该对象包含定义 Bean 的所有信息,用于实例化一个 Spring Bean
  3. Spring Bean 元信息注册阶段,将 BeanDefinition 配置元信息 保存至 BeanDefinitionRegistry 的 ConcurrentHashMap 集合中
  4. Spring BeanDefinition 合并阶段,定义的 Bean 可能存在层次性关系,则需要将它们进行合并,存在相同配置则覆盖父属性,最终生成一个 RootBeanDefinition 对象
  5. Spring Bean 的实例化阶段,首先的通过类加载器加载出一个 Class 对象,通过这个 Class 对象的构造器创建一个实例对象,构造器注入在此处会完成。在实例化阶段 Spring 提供了实例化前后两个扩展点(InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation、postProcessAfterInstantiation 方法)
  6. Spring Bean 属性赋值阶段,在 Spring 实例化后,需要对其相关属性进行赋值,注入依赖的对象。首先获取该对象所有属性与属性值的映射,可能已定义,也可能需要注入,在这里都会进行赋值(反射机制)。提示一下,依赖注入的实现通过 CommonAnnotationBeanPostProcessor(@Resource、@PostConstruct、@PreDestroy)和 AutowiredAnnotationBeanPostProcessor(@Autowired、@Value)两个处理器实现的。
  7. Aware 接口回调阶段,如果 Spring Bean 是 Spring 提供的 Aware 接口类型(例如 BeanNameAware、ApplicationContextAware),这里会进行接口的回调,注入相关对象(例如 beanName、ApplicationContext)
  8. Spring Bean 初始化阶段,这里会调用 Spring Bean 配置的初始化方法,执行顺序:@PostConstruct 标注方法、实现 InitializingBean 接口的 afterPropertiesSet() 方法、自定义初始化方法。在初始化阶段 Spring 提供了初始化前后两个扩展点(BeanPostProcessor 的 postProcessBeforeInitialization、postProcessAfterInitialization 方法)
  9. Spring Bean 初始化完成阶段,在所有的 Bean(不是抽象、单例模式、不是懒加载方式)初始化后,Spring 会再次遍历所有初始化好的单例 Bean 对象,如果是 SmartInitializingSingleton 类型则调用其 afterSingletonsInstantiated() 方法,这里也属于 Spring 提供的一个扩展点
  10. Spring Bean 销毁阶段,当 Spring 应用上下文关闭或者你主动销毁某个 Bean 时则进入 Spring Bean 的销毁阶段,执行顺序:@PreDestroy 注解的销毁动作、实现了 DisposableBean 接口的 Bean 的回调、destroy-method 自定义的销毁方法。这里也有一个销毁前阶段,也属于 Spring 提供的一个扩展点,@PreDestroy 就是基于这个实现的
  11. Spring 垃圾收集(GC)

BeanDefinition 是什么?

BeanDefinition 是 Spring Bean 的“前身”,其内部包含了初始化一个 Bean 的所有元信息,在 Spring 初始化一个 Bean 的过程中需要根据该对象生成一个 Bean 对象并进行一系列的初始化工作。

Spring中的Bean是线程安全的吗?(往JUC引导)

Spring本身并没有针对Bean做线程安全处理,因此一个Bean是否是线程安全的,取决于当前Bean的内部实现。

说一下Spring中的事务机制

  1. Spring事务底层是基于数据库事务和AOP机制来实现的。对于方法上使用了@Transactional注解的类,Spring会创建一个代理对象;当调用代理对象的方法时,如果加了@Transactional注解,则利用事务管理器创建一个数据库连接,并且设置autocommit为FALSE,禁止此连接的自动提交;然后执行当前方法,方法中执行SQL,方法执行完毕,如果没有异常,则直接提交事务,如果出现了异常,并且异常是@Transactional的属性rollbackFor指定的异常,就回滚事务,否则仍然提交事务。
  2. Spring事务的隔离级别对应的就是数据库的隔离级别。
  3. Spring事务的传播机制是Spring内部实现的;本质是基于数据库连接来完成;一个数据库连接对应一个事务,如果传播机制需要新打开一个事务,那么实际上就是先建立一个数据库连接,在新建立的连接上执行新的事务。

说说常用的SpringBoot注解及其实现

  1. @SpringBootApplication注解:这个注解标识了一个SpringBoot工程;它实际上是另外三个注解的组合:
    • @SpringBootConfiguration:标识当前启动类也是一个配置类
    • @EnableAutoConfiguration:向Spring容器中导入一个Selector,用来加载ClassPath下SpringFactories路径中所定义的类,将这些类自动加载为配置类
    • @ComponentScan:标识扫描路径,默认扫描启动类所在的当前目录
  2. @Bean注解:在配置类中用来定义Bean,因为第三方包中类是无法直接定义为Bean的
  3. @Autowired注解:用来自动配置类
  4. @Controller、@Service、@Mapper和@Component等注解:用来注册Bean,他们主要不同就是标识各个Bean的职责不同
  5. @RestController、@ResponseBody、@PostMapping等注解:在前后端分离时,web接口用来返回JSON数据时使用

实现:TODO

Bean的作用范围

通过 scope属性指定Bean的作用范围,有如下几种:

  • singleton:单例模式,是默认作用域,不管收到多少 Bean 请求每个容器中只有一个唯一的Bean实例。
  • prototype:原型模式,和singleton相反,每次 Bean请求都会创建一个新的实例。
  • request:每次 HTTP 请求都会创建一个新的 Bean 并把它放到 request 域中,在请求完成后 Bean 会失效并被垃圾收集器回收。
  • session:和 request 类似,确保每个 session 中有一个 Bean 实例,session 过期后 bean 会随之失效。
  • global session:当应用部署在 Portlet 容器时,如果想让所有 Portlet 共用全局存储变量,那么该变量需要存储在 global session 中。

BeanFactory、FactoryBean 和 ApplicationContext 的区别?

  • BeanFactory 是一个 Bean 工厂,使用简单工厂模式,是 Spring IoC 容器顶级接口,可以理解为含有 Bean 集合的工厂类,作用是管理 Bean,包括实例化、定位、配置对象及建立这些对象间的依赖。BeanFactory 实例化后并不会自动实例化 Bean,只有当 Bean 被使用时才实例化与装配依赖关系,属于延迟加载,适合多例模式。

  • FactoryBean 是一个工厂 Bean,使用了工厂方法模式,作用是生产其他 Bean 实例,可以通过实现该接口,提供一个工厂方法来自定义实例化 Bean 的逻辑。FactoryBean 接口由 BeanFactory 中配置的对象实现,这些对象本身就是用于创建对象的工厂,如果一个 Bean 实现了这个接口,那么它就是创建对象的工厂 Bean,而不是 Bean 实例本身。

  • ApplicationConext 是 BeanFactory 的子接口,扩展了 BeanFactory 的功能,提供了支持国际化的文本消息,统一的资源文件读取方式,事件传播以及应用层的特别配置等。容器会在初始化时对配置的 Bean 进行预实例化,Bean 的依赖注入在容器初始化时就已经完成,属于立即加载,适合单例模式,一般推荐使用。

BeanFactory和ApplicationContext谁才是 Spring IoC 容器?

BeanFactory 是 Spring 底层 IoC 容器,ApplicationContext 是 BeanFactory 的子接口,是 BeanFactory 的一个超集,提供 IoC 容器以外更多的功能。ApplicationContext 除了扮演 IoC 容器角色,还提供了这些企业特性:面向切面(AOP)、配置元信息、资源管理、事件机制、国际化、注解、Environment 抽象等。我们一般称 ApplicationContext 是 Spring 应用上下文,BeanFactory 为 Spring 底层 IoC 容器。

Spring如何实现AOP?项目中哪些地方会用到AOP?

  1. Spring利用动态代理技术来实现AOP,包括JDK动态代理和Cglib动态代理;

  2. 项目中,在数据库事务、权限控制、统一执行日志等都可以通过AOP来实现,这样做的好处是可以做到统一处理且业务无侵入。

JDK动态代理底层原理

JDK的动态代理是基于反射实现。JDK通过反射,生成一个代理类,这个代理类实现了原来那个类的全部接口,并对接口中定义的所有方法进行了代理。当我们通过代理对象执行原来那个类的方法时,代理类底层会通过反射机制,回调我们实现的InvocationHandler接口的invoke方法。并且这个代理类是Proxy类的子类(记住这个结论,后面测试要用)。这就是JDK动态代理大致的实现方式。

优点:

  1. JDK动态代理是JDK原生的,不需要任何依赖即可使用
  2. 通过反射机制生成代理类的速度要比CGLib操作字节码生成代理类的速度更快

缺点:

  1. 如果要使用JDK动态代理,被代理的类必须实现了接口,否则无法代理;
  2. JDK动态代理无法为没有在接口中定义的方法实现代理,假设我们有一个实现了接口的类,我们为它的一个不属于接口中的方法配置了切面,Spring仍然会使用JDK的动态代理,但是由于配置了切面的方法不属于接口,为这个方法配置的切面将不会被织入。
  3. JDK动态代理执行代理方法时,需要通过反射机制进行回调,此时方法执行的效率比较低;

CGLib动态代理底层原理

CGLib实现动态代理的原理是,底层采用了ASM字节码生成框架,直接对需要代理的类的字节码进行操作,生成这个类的一个子类,并重写了类的所有可以重写的方法,在重写的过程中,将我们定义的额外的逻辑(简单理解为Spring中的切面)织入到方法中,对方法进行了增强。而通过字节码操作生成的代理类,和我们自己编写并编译后的类没有太大区别。

优点:

  1. 使用CGLib代理的类,不需要实现接口,因为CGLib生成的代理类是直接继承自需要被代理的类;
  2. CGLib生成的代理类是原来那个类的子类,这就意味着这个代理类可以为原来那个类中,所有能够被子类重写的方法进行代理;
  3. CGLib生成的代理类,和我们自己编写并编译的类没有太大区别,对方法的调用和直接调用普通类的方式一致,所以CGLib执行代理方法的效率要高于JDK的动态代理;

缺点:

  1. 由于CGLib的代理类使用的是继承,这也就意味着如果需要被代理的类是一个final类,则无法使用CGLib代理;
  2. 由于CGLib实现代理方法的方式是重写父类的方法,所以无法对final方法,或者private方法进行代理,因为子类无法重写这些方法;
  3. CGLib生成代理类的方式是通过操作字节码,这种方式生成代理类的速度要比JDK通过反射生成代理类的速度更慢;

Spring默认使用的动态代理是什么?

  1. Spring 中的 AOP,有接口就用 JDK 动态代理,没有接口就用 Cglib 动态代理。
  2. Spring Boot 中的 AOP,2.0 之前和 Spring 一样;2.0 之后首选 Cglib 动态代理,如果用户想要使用 JDK 动态代理,需要自己手动配置。

Spring注解事务不生效的情况(AOP相关)

循环依赖和三级缓存

首先循环依赖指的是单例模式下的 Bean 字段注入时出现的循环依赖。构造器注入对于 Spring 无法自动解决(应该考虑代码设计是否有问题),可通过延迟初始化来处理。Spring 只解决单例模式下的循环依赖。

在 Spring 底层 IoC 容器 BeanFactory 中处理循环依赖的方法主要借助于以下 个 Map 集合:

  1. (一级 Map),里面保存了所有已经初始化好的单例 Bean,也就是会保存 Spring IoC 容器中所有单例的 Spring Bean;
  2. (二级 Map),里面会保存从 三级 Map 获取到的正在初始化的 Bean
  3. (三级 Map),里面保存了正在初始化的 Bean 对应的 ObjectFactory 实现类,调用其 getObject() 方法返回正在初始化的 Bean 对象(仅实例化还没完全初始化好),如果存在则将获取到的 Bean 对象并保存至 二级 Map,同时从当前 三级 Map 移除该 ObjectFactory 实现类。

当通过 getBean 依赖查找时会首先依次从上面三个 Map 获取,存在则返回,不存在则进行初始化,这三个 Map 是处理循环依赖的关键。

为什么需要上面的 二级 Map ?

因为通过 三级 Map获取 Bean 会有相关 SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference(..) 的处理,避免重复处理,处理后返回的可能是一个代理对象

例如在循环依赖中一个 Bean 可能被多个 Bean 依赖, A -> B(也依赖 A) -> C -> A,当你获取 A 这个 Bean 时,后续 B 和 C 都要注入 A,没有上面的 二级 Map的话,三级 Map 保存的 ObjectFactory 实现类会被调用两次,会重复处理,可能出现问题,这样做在性能上也有所提升

为什么不直接调用这个 ObjectFactory#getObject() 方法放入 二级Map 中,而需要上面的 三级 Map?

对于不涉及到 AOP 的 Bean 确实可以不需要 (三级 Map),但是 Spring AOP 就是 Spring 体系中的一员,如果没有(三级 Map),意味着 Bean 在实例化后就要完成 AOP 代理,这样违背了 Spring 的设计原则。Spring 是通过 这个后置处理器在完全创建好 Bean 后来完成 AOP 代理,而不是在实例化后就立马进行 AOP 代理。如果出现了循环依赖,那没有办法,只有给 Bean 先创建代理对象,但是在没有出现循环依赖的情况下,设计之初就是让 Bean 在完全创建好后才完成 AOP 代理。

提示: 是一个 后置处理器,在它的 getEarlyBeanReference(..) 方法中可以创建代理对象。所以说对于上面的问题二,如果出现了循环依赖,如果是一个 AOP 代理对象,那只能给 Bean 先创建代理对象,设计之初就是让 Bean 在完全创建好后才完成 AOP 代理。

为什么 Spring 的设计是让 Bean 在完全创建好后才完成 AOP 代理?

因为创建的代理对象需要关联目标对象,在拦截处理的过程中需要根据目标对象执行被拦截的方法,所以这个目标对象最好是一个“成熟态”,而不是仅实例化还未初始化的一个对象。

Spring 中几种初始化方法的执行顺序?

有以下初始化方式:

  • Aware 接口:实现了 Spring 提供的相关 XxxAware 接口,例如 BeanNameAware、ApplicationContextAware,其 setXxx 方法会被回调,可以注入相关对象@PostConstruct 注解:该注解是 JSR-250 的标准注解,Spring 会调用该注解标
  • 注的方法
  • InitializingBean 接口:实现了该接口,Spring 会调用其 afterPropertiesSet() 方法
  • 自定义初始化方法:通过 init-method 指定的方法会被调用

在 Spring 初始 Bean 的过程中上面的初始化方式的执行顺序如下:

  1. 接口的回调
  2. JSR-250 标注的方法的调用
  3. 方法的回调
  4. 初始化方法的调用

如何简单实现一个IOC容器

  1. 配置文件和包扫描路径
  2. 递归扫描包获取.class文件
  3. 通过反射确定需要交给IOC容器管理的类
  4. 对需要注入IOC容器的类进行依赖注入

Spring框架中用到的设计模式有哪些?

  • 简单工厂;又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类。Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。
  • 工厂方法(Factory Method);定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。
  • 单例(Singleton);保证一个类仅有一个实例,并提供一个访问它的全局访问点。Spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例,这是因为Spring管理的是是任意的Java对象。
  • 适配器(Adapter);将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
  • 包装器(Decorator);动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。Spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。基本上都是动态地给一个对象添加一些额外的职责。
  • 代理(Proxy);为其他对象提供一种代理以控制对这个对象的访问。从结构上来看和Decorator模式类似,但Proxy是控制,更像是一种对功能的限制,而Decorator是增加职责。Spring的Proxy模式在aop中有体现,比如JdkDynamicAopProxy和Cglib2AopProxy。
  • 观察者(Observer);定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。Spring中Observer模式常用的地方是listener的实现。如ApplicationListener。
  • 策略(Strategy);定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。Spring中在实例化对象的时候用到Strategy模式;
  • 模板方法(Template Method);定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

描述一下DispatcherServlet的工作流程

面试题--SpringMVC的工作流程_【SpringMVC】

  1. 用户发送请求至前端控制器DispatcherServlet
  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器。
  3. 处理器映射器找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
  4. DispatcherServlet调用HandlerAdapter处理器适配器
  5. HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
  6. Controller执行完成返回ModelAndView
  7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
  8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器
  9. ViewReslover解析后返回具体View
  10. DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
  11. DispatcherServlet响应用户

说说SpringCloud各组件功能及其与Dubbo的区别

img

SpringCloud与Dubbo的区别:

  • 初始定位不同:SpringCloud定位为微服务架构下的一站式解决方案;Dubbo 是 SOA 时代的产物,它的关注点主要在于服务的调用和治理
  • 生态环境不同:SpringCloud依托于Spring平台,具备更加完善的生态体系;而Dubbo一开始只是做RPC远程调用,生态相对匮乏,现在逐渐丰富起来。
  • 调用方式:SpringCloud是采用Http协议做远程调用,接口一般是Rest风格,比较灵活;Dubbo是采用Dubbo协议,接口一般是Java的Service接口,格式固定。但调用时采用Netty的NIO方式,性能较好。
  • 组件差异比较多,例如SpringCloud注册中心一般用Eureka,而Dubbo用的是Zookeeper

SpringCloud与Dubbo的生态对比:

SpringCloud与Dubbo的生态对比.jpg

Spring Cloud 的功能很明显比 Dubbo 更加强大,涵盖面更广,而且作为 Spring 的旗舰项目,它也能够与 Spring Framework、Spring Boot、Spring Data、Spring Batch 等其他 Spring 项目完美融合,这些对于微服务而言是至关重要的。

使用 Dubbo 构建的微服务架构就像组装电脑,各环节选择自由度很高,但是最终结果很有可能因为一条内存质量不行就点不亮了,总是让人不怎么放心,但是如果使用者是一名高手,那这些都不是问题。

而 Spring Cloud 就像品牌机,在 Spring Source 的整合下,做了大量的兼容性测试,保证了机器拥有更高的稳定性,但是如果要在使用非原装组件外的东西,就需要对其基础原理有足够的了解。

当然SpringCloud是兼容Dubbo的,两者可以优劣势互补。

参考资料