回目录 《spring分布式微服务入门》

我们今天来梳理归纳一下java的开发框架,首先为什么需要框架?

  1. 节约成本

不可能所有东西都从零造起,成本太高,spring融合了市场上大部分的开源项目,可以直接‘免费’利用

  1. 安全考虑

当前网络环境复杂,攻击无处不在,成熟的框架已经被主流公司接受使用,很多坑已经被前人踩过,站在巨人的肩膀上是明智之选,不用交额外的智商税

  1. 业务发展

spring boot不只是框架,还是spring cloud的一部分,spring cloud是微服务架构的一套完整是有序框架集合, spring是建筑材料,spring boot是脚手架,spring cloud就是行业规范,采用行业规范的开发模式有利于IT更好的服务business和业务拓展

# 1. Overview

# 1.1 SOA?微服务?

我们常说用spring boot构建微服务,又说spring cloud构建微服务,他们到底是什么关系?

引用我在微服务架构一章中关于微服务的解释:

首先微服务是啥,微服务首先是一种架构思想, 首先最初的很多产品都是单体monolithic架构,所有的服务都紧紧耦合在一个解决方案中,难以扩展,只能通过加cpu加内存的方式扩展,举例一个电商平台, 刚开始所有功能都放在一个解决方案,比如托管在Apache的一个war或者托管在iis的一个.net mvc程序, 随着项目的发展,团队的壮大,单体会变得庞大而难以维护,我们需要将功能拆分开,比如商家系统、买家系统、管理后台系统等,面向业务或者叫服务切分,分而治之,这种粒度的就是SOA架构, 其显著缺点: 1.从技术的角度,其实业务的切分在技术层面上仍然会有大面积的重叠,因此如果业务切割的不好,形成各种依赖,有可能在修改时牵一发而动全身 2.从业务角度来说,由于是业务的切分,所以当需要发展新的业务时就需要重新构建一个完全新的服务,不利于基于业务创新和发现 所以引入微服务的概念,微服务进一步将服务自底向上或自上到下做更细的切分,最下面是基础系统服务(短信、邮件、存储、缓存、消息推送等),中间是共享服务(支付系统、订单系统、仓储系统等), 最上面则是业务层(零售系统、团购系统、采购系统),比如我们要加一个闪购业务也是很轻松的,不用从底到上再来一遍,只需要基于基础服务和共享服务做业务开发

# 1.2 SpringBoot SpringCloud

Rod Johnson创建的开源框架interface21是 Spring的前身,随着spring从小框架发展为大而全的企业级框架,spring对市面上主流的开源软件都有了对应的组件支持, 人们发现使用spring项目开发变得难用,往往需要引入很多配置,难以维护容易出错,spring因此冠名配置地狱;

Spring boot是基于spring抽象出来的开发框架,是快速开发的scaffold脚手架,spring boot丧心病狂的运用依赖注入DI的思想,配置文件可以auto config,用户只需要定义好需要的bean, spring boot的大容器会进行管理,丰富的starter让开发者可以集中精力在业务逻辑上而不是依赖的配置管理;

依赖注入的思想简单来说就比如小孩要从冰箱拿吃的,但是不应该自己拿,应该交由家长来处理,因为小孩可能会忘记关冰箱门,可能会打乱冰箱里面其他东西,总之小孩这个组件应该只关心自己的事情,不要做这些大人才能做好的事情, 所以从冰箱拿东西吃要交由家长处理,在spring boot中,小孩可以采用构造函数注入或者setter based如autowired方式来使用家长组件;

spring-cloud是一套完整的微服务解决方案,是一系列框架的有序集合,提供了分布式的各种解决方案: 服务开发(springBoot spring springMVC)、服务配置中心(SpringCloudConfig Chef)、服务发现(eureka zookeeper)、服务调用(rest rpc)、负载均衡(ribbon nginx)、服务熔断器、服务监控、服务部署(docker kubernetes)、消息队列(kafka rabbitmq)

所以可见一个个具体的微服务(这里说的微服务就是具体的一个个应用了)是用spring boot开发,spring cloud又提供了服务配置中心、服务注册发现等所谓微服务治理的解决方案

1.spring boot是一个快速开发框架,应该说是spring系列的集大成者。我们可以简单的把spring boot理解成是一个快速开发的脚手架。 2.微服务往往是指Spring Cloud,微服务是一个框架。 3.如果把基于微服务架构的软件比作是一个大厦,钢筋混凝土结构就是spring cloud,而砖头瓦块等就是spring boot。微服务的一个一个服务是用spring boot开发的,spring cloud提供服务注册与发现、负载均衡、API网管、熔断路由、配置中心等框架性服务,当然一个完整的微服务系统有很多其他的内容,例如服务拆分、监控、限流降级等等。

dubbo常常拿来跟spring cloud对比,实际目前已经不具有可比性了,Dubbo现在只是一款高性能的Java RPC框架,只能跟spring cloud集合中的服务调用部分REST RPC做对比

spring cloud alibaba是spring cloud的其中一个微服务解决方案

# 2. Spring Framework

https://docs.spring.io/spring/docs/current/spring-framework-reference/ Project generator https://start.spring.io/ https://www.tutorialspoint.com/spring/spring_quick_guide.htm https://docs.spring.io/spring/docs/5.1.6.RELEASE/spring-framework-reference/ (spring boot 2.1.4 depend on spring 5.1.6)

** architecture**

** Spring AOP **

AOP是aspect oriented programing的简称,意为面向切面编程。 spring aop使用了动态代理技术在运行期织入增强的代码,使用了两种代理机制,一种是基于jdk的动态代理,另一种是基于CGLib的动态代理。 详细请看深入理解代理模式设计模式:代理模式 https://www.baeldung.com/spring-aop

managed components & proxy(jdk proxy&cglib)

Whenever you declare a bean in XML or use @Component, @Service, or @Repository on a class targeted by Spring’s annotation component scanning (which is enabled by default for Spring Boot), that class is instantiated and managed as a singleton bean by the Spring framework. However, Spring doesn’t actually provide a literal reference to the original bean when it’s injected—it wraps the bean in a proxy class to give Spring a chance to weave in AOP code if needed. https://docs.spring.io/spring/docs/2.5.x/reference/aop.html

https://www.credera.com/blog/technology-insights/open-source-technology-insights/aspect-oriented-programming-in-spring-boot-part-2-spring-jdk-proxies-vs-cglib-vs-aspectj/

通过aop拦截mybatis接口dao https://blog.csdn.net/zkn_CS_DN_2013/article/details/52798447 Spring / MyBatis——插件机制(AOP) https://blog.csdn.net/qq_22078107/article/details/85781594 https://blog.csdn.net/u012525096/article/details/82389240

** 代理 动态代理 静态代理 cglib 通过使用proxy设计模式 远程调用看起来像本地调用 增强类 如mybatis,fastclassbyspringcglib

保存生成的动态代理类或者增强类
@EnableAsync
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
    	System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"C:\\Workspace\\debug");
        SpringApplication.run(Application.class, args);
    }

# 3.SpringBoot Framework

springboot原理解析在这里

While the Spring framework focuses on providing flexibility to you, Spring Boot aims to shorten the code length and provide you with the easiest way to develop a web application. With annotation configuration and default codes, Spring Boot shortens the time involved in developing an application. https://www.tutorialspoint.com/spring_boot/index.htm

https://spring.io/tools3/sts/all

guides: https://spring.io/guides#gs https://spring.io/guides/gs/spring-boot/ Starters samples code: https://docs.spring.io/spring-boot/docs/2.1.4.RELEASE/reference/htmlsingle/#using-boot-starter https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples Docs: https://docs.spring.io/spring-boot/docs/2.1.4.RELEASE/reference/htmlsingle/ Unit test: https://stackabuse.com/how-to-test-a-spring-boot-application/ https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html

Spring Boot中如何干掉过多的if else! https://mp.weixin.qq.com/s/Uf8KGTbNcuDtwIlpMJnaXg

Spring boot web default web server: Asp.net default is IIS Express, how about spring boot web? Tomcat vs. Jetty vs. Undertow: Comparison of Spring Boot Embedded Servlet Containers https://examples.javacodegeeks.com/enterprise-java/spring/tomcat-vs-jetty-vs-undertow-comparison-of-spring-boot-embedded-servlet-containers/

# 3.1 Plugins

** spring-boot-maven-plugin

<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<version>${spring-boot-maven-plugin.version}</version>
				<executions>
					<execution>
						<goals>
							<goal>repackage</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>

这个plugin很重要,其中的repackage是把java程序打包成为executable程序,否则就只是普通的jar包(纠正:实际测试即使没用这个plugin,pom parent继承了org.springframework.boot,一样可以生成可执行程序,原因见后面关于这个包的解释),不能直接执行,比如hello world,需要javac之后生成的class,用java *.class才能执行,而且如果java程序比较负责,依赖了外部的包,还要给出classpath或libpath,极其麻烦,maven本身就是包管理器,最基本的职责就是mvn package打成普通的jar包,然后mvn install到本地.m2 repository,然后mvn deploy到远程的repository,当需要运行的时候就是用前面提到的java命令执行,当然也可以直接用mvn执行,好处是mvn会自动去.m2下面找到依赖的包, mvn exec:java -Dexec.mainClass="com.example.Main" -Dexec.args="arg0 arg1",可以看到mvn实际也就是调用java命令 首先使用这个plugin的情况下,正常的mvn clean package,生成XXX-0.0.1-SNAPSHOT.jar和XXX-0.0.1-SNAPSHOT.jar.origninal: 可以重命名一下orignial为jar,反编译对比下:

对比可以看到,普通的jar包里面的东西被再次包入了BOOT-INF,然后增加了一个org.springframework.boot.loader的启动包 执行方法: project里:mvn spring-boot:run 打成包后:java -server -jar XXXX.jar --spring.config.location=/config/

这里居然还有个比较傻逼的比较 https://www.baeldung.com/spring-boot-run-maven-vs-executable-jar 有点意思,还有人这么较真

然后我好奇测试了下mvn最原始的打包plugin,看打成一个fat jar会如何 无法运行,估计是缺少springboot的上下文,spring boot的程序自然真正的入口应该是spring boot那个loader,加了annotation的那个所谓的入口main实际只是为spring boot loader准备的入口;

** maven-enforcer-plugin 这个是用来检查依赖问题的 mvn enforcer:enforce

# 3.2 Dependencies

Parent org.springframework.boot https://www.baeldung.com/spring-boot-dependency-management-custom-parent

继承两种方式: 直接写在parent里面; 写在dependencymanagement里面

<dependencyManagement>
     <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>1.5.6.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

如果没有继承org.springframework.boot,如果有多个入口方法,在pom中指定:

<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<mainClass>com.lyhistory.rce.shiro.WebApp</mainClass>
				</configuration>
				<executions>
					<execution>
						<goals>
							<goal>repackage</goal>
						</goals>
					</execution>
				</executions>
			</plugin>

如果继承org.springframework.boot,如果有多个入口方法,就多一种方式,在pom中指定:

<parent>
   	 <groupId>org.springframework.boot</groupId>
   	 <artifactId>spring-boot-starter-parent</artifactId>
   	 <version>1.5.9.RELEASE</version>
   	 <relativePath /> <!-- lookup parent from repository -->
</parent>

<properties>
  <start-class>com.xx.xx</start-class>
</properties>

# 3.3 Integration

# 3.3.1 redis

@Autowired Private RedisTemplate redisTemplate; https://github.com/spring-projects/spring-boot/issues/7238

一文搞定 Spring Data Redis 详解及实战 https://cloud.tencent.com/developer/article/1349818 SpringBoot下Redis相关配置是如何被初始化的 https://my.oschina.net/u/3866531/blog/1858069

Which type of injection?? 深度解析SpringBoot2.x整合Spring-Data-Redis https://www.itcodemonkey.com/article/13627.html

# 3.3.2 Shiro

# more

Thymeleaf https://www.baeldung.com/thymeleaf-in-spring-mvc

# 4. Spring Cloud

spring cloud定义了接口标准,然后各家各组件做了不同实现;

从总体上看:

  • 从入口开始,DNS动态解析 - -> 机房内负载均衡(LVS+Keepalived) 动静分离可以放这里做,

静态找FastDFS集群(便宜)或cdn服务(贵); 动态则进入下面流量网关

LVS的virtual ip概念,大概是一个数据包发送给192.168.1.1这个服务器,但是负载均衡给了192.168.1.2这个服务器,按照TCP协议,参考我在network的讲解,2这个服务器应该拒绝这个包,因此才引入了VIP的概念;
  • 然后进入流量网关(强调性能)=路由+waf+负载 不是用纯的nginx,一般是用基于netty的nginx做负载均衡,拦截无效非法流量/定向流量分发(挡爬虫、攻击、频控),此处可以放WAF Kona Openresty(nginx+lua) 定向流量分发(一致性哈希) 数亿万个文件 item.jd.com/1234.html hash(1234) mod 服务器个数 引入流量倾斜问题,秒杀(水平扩展热门产品所在的服务器)

  • 然后进入业务网关(强调功能) 一般是基于filter的Netfix zuul和spring cloud gateway,权限认证比如spring security+jwt或者CAS也可以放这里

    netty的性能比filter高,所以一般nginx放前面,zuul放后面,当然zuul和spring cloud gateway也可以作为流量网关;

  • 最后到具体微服务内部 基于servlet的springmvc(内置tomcat服务器); 更高性能的基于netty的spring reactive webflux(内置netty服务器); 页面渲染有 Thymleaf Eniov FreeMaker JSON; 微服务内部一般都有Acurator用于上报健康信息给比如springcloud admin; 微服务之间调用:先通过服务治理的注册中心获取服务列表到本地 =>经过断路器用hystrix,sentinel(限流,服务降级)

    ​ hystrix 降级(从try catch升级为面向切面编程AOP )熔断 隔离(线程池[远程服务]/信号量[本地服务] 线程池之间隔离) ​ =>经过负载均衡用netflix ribbon或springcloud loadbanlancer, ​ =>最后通过封装的http或者tcp client端调用远程服务,一般用Feigin或者其底层的restTemplate,

    ​ open-feign可以识别spring-mvc接口,直接调用接口就可以调用对应的服务;

    ​ feign必须在代码里显示写出调用哪一个服务才能调用;

  • 服务治理 springcloud admin; 服务注册中心eureka nacos zookeeper

​ 前面网关部分,假如业务网关有多个节点,流量网关的nginx可以通过访问注册中心获得业务网关列表,从而对业务网关进行负载均衡;然后业务网关访问注册中心可以获取对应的微服务;当然所有的业务网关和微服务都是注册到注册中心的;

企业消息总线springcloud bus,kafka
  • 分布式事务及微服务之间链路 => 先走分布式事务alibaba seata => 再连接微服务链路追踪 springcloud-sleuth,zokin,skvwalking => 最后获取分布式锁 zookeeper acurator,redlock

从厂家看:

  • netflix全家桶:

全局外部流量入口:zuul 动态路由 Hystrix熔断降级 微服务内部负载均衡:feign https://blog.csdn.net/zhou920786312/article/details/84982290 feign和ribbon都属于客户端负载均衡(正向代理,当然这里意图并不是说要隐藏客户端,而是反而客户端通过使用feignClient,feiginclient调用微服务B[多个节点在注册中心注册为B服务],从而隐藏具体的调用过程,比如怎么动态选择哪个节点的B服务,通过什么协议等等),nginx属于服务端负载均衡(反向代理),nginx不易于剔除非健康节点;

  • spring cloud alibaba全家桶: https://github.com/alibaba/spring-cloud-alibaba

spring cloud gateway 网关代替zuul+hystrix,既有路由又有熔断降级

nacos代替了spring boot的properties或者yml配置,并且可以用于dns注册和rpc服务的注册和服务发现;

Feign 默认采用http,用于微服务的数据共享,微服务可以像调用自己的服务一样调用其他微服务提供的服务,类似于dubbo等rpc框架(rpc+动态代理)

bpm-business process management比如工单流程等: activiti or flowable

Spring Cloud 万字总结,真不错! https://mp.weixin.qq.com/s/YGtKoKBE1jxFaEUpEFSaLg

Azure Spring Cloud workshop https://docs.microsoft.com/en-us/learn/modules/azure-spring-cloud-workshop/

https://github.com/macrozheng/mall https://github.com/zhangdaiscott/jeecg-boot

https://github.com/ZhongFuCheng3y/msc-Demo https://github.com/forezp/SpringCloudLearning https://github.com/zhoutaoo/SpringCloud

todo: Mvc Thymeleaf Realm


ref 为什么说 Java 程序员到了必须掌握 Spring Boot 的时候? 聊一聊Spring中的代理 Spring Cloud spring boot 和微服务的关系? 重新理解微服务 架构设计漫步:从单体架构、SOA到微服务 Microservices