前言
前面的章节我们讲了Spring Web MVC 。本节,继续微服务专题的内容分享,共计16小节,分别是:
- 微服务专题01-Spring Application
- 微服务专题02-Spring Web MVC 视图技术
- 微服务专题03-REST
- 微服务专题04-Spring WebFlux 原理
- 微服务专题05-Spring WebFlux 运用
- 微服务专题06-云原生应用(Cloud Native Applications)
- 微服务专题07-Spring Cloud 配置管理
- 微服务专题08-Spring Cloud 服务发现
- 微服务专题09-Spring Cloud 负载均衡
- 微服务专题10-Spring Cloud 服务熔断
- 微服务专题11-Spring Cloud 服务调用
- 微服务专题12-Spring Cloud Gateway
- 微服务专题13-Spring Cloud Stream (上)
- 微服务专题14-Spring Cloud Bus
- 微服务专题15-Spring Cloud Stream 实现
- 微服务专题16-Spring Cloud 整体回顾
本节内容重点为:
- REST 理论基础:基本概念、架构属性、架构约束、使用场景、实现框架(服务端、客户端)
- REST 服务端实践:Spring Boot REST 应用、HATEOAS 应用、文档生成等
- REST 客户端实践:传统浏览器、Apache HttpClient 、Spring RestTemplate 等相关实践
REST理论基础
前面介绍过Spring的MVC结合view显示数据。那么这些数据除了在WebBrowser中用JavaScript来调用以外,还可以用远程服务器的Java程序、C#程序来调用。也就是说现在的程序不仅在BS中能调用,在CS中同样也能调用,不过你需要借助RestTemplate这个类来完成。RestTemplate有点类似于一个WebService客户端请求的模版,可以调用http请求的WebService,并将结果转换成相应的对象类型。
RPC ( Remote Procedure Call )
- 语言相关
- Java - RMI(Remote Method Invocation)
- .NET - COM+、
- 语言无关(重点)
- SOA
- Web Services
- SOAP(传输介质协议)
- HTTP、SMTP(通讯协议)
- Web Services
- 微服务(MSA)
- REST
- HTML、JSON、XML 等等
- HTTP(通讯协议)
- HTTP 1.1
- 短连接
- Keep-Alive
- 连接池
- Long Polling
- HTTP/2
- 长连接
- HTTP 1.1
- 技术
- Spring 客户端 : RestTemplate
- Spring WebMVC : @RestController =
@Controller
+@ResponseBody
+@RequestBody
- Spring Cloud :
RestTemplate
扩展 +@LoadBalanced
- REST
- SOA
REST(英文)
Cacheability(可缓存性)
@ResponseBody
-> 响应体(Response Body)
-
响应(Response)
-
响应头(Headers)
-
请求方法
- HEAD
-
元信息(Meta-Data)
- Accept-Language ->
Locale
- Connection -> Keep-Alive
- Accept-Language ->
-
实现
多值 Map
MultiValueMap
Key : Value = 1 : N
Name : Value = 1 : N
参考代码:
public class HttpHeaders implements MultiValueMap<String, String>, Serializable { ... }
-
-
响应体
- 业务信息(Business Data)
- Body:HTTP 实体、REST
-
@ResponseBody
-
HttpEntity.body
属性(泛型结构)参考代码:
-
public class HttpEntity<T> { ... private final HttpHeaders headers; @Nullable private final T body; }
- Payload : 消息 JMS、事件、SOA
-
HTTP 状态码
可以参考源码:(org.springframework.http.HttpStatus
)
关于http状态码,也是很多初级面试常考的点,日常开发中,常见的有:
-
200
org.springframework.http.HttpStatus#OK
-
304
org.springframework.http.HttpStatus#NOT_MODIFIED
-
400
org.springframework.http.HttpStatus#BAD_REQUEST
-
404
org.springframework.http.HttpStatus#NOT_FOUND
-
500
org.springframework.http.HttpStatus#INTERNAL_SERVER_ERROR
缓存验证Demo:
启动类:
@EnableAutoConfiguration
@ComponentScan(basePackages = "com.test.micro.services.mvc.controller")
public class MvcRestApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(MvcRestApplication.class)
.run(args);
}
}
CachedRestController
@Controller
public class CachedRestController {
@RequestMapping
@ResponseBody // 没有缓存 -> 304
// 服务端和客户端没有形成默契(状态码)
// HTTP 协议,REST 继承
public String helloWorld() { // 200 / 500 / 400
return "Hello,World"; // Body = "Hello,World" String
}
@RequestMapping("/cache") // Spring MVC 返回值处理
@OptionsMapping(name="")
public ResponseEntity<String> cachedHelloWorld(
@RequestParam(required = false, defaultValue = "false") boolean cached) {
if (cached) {
return new ResponseEntity(HttpStatus.NOT_MODIFIED);
} else {
return ResponseEntity.ok("Hello,World");
}
}
}
代码测试:
首次访问地址:
http://localhost:8080/cache
不加入缓存,http响应码为200
在url控制缓存,第二次请求的地址http://localhost:8080/cache?chched=ture
加入缓存后,http响应码为304
实验分析:
- 第一次完整请求,获取响应头(200),直接获取
- 第二次请求,只读取头信息,响应头(304),客户端(流量器)取上次 Body 结果
Uniform interface(统一接口)
资源定位 - URI
URI与URL的区别:
山东和河南都有一个张三,张三就是URI,具体的河南的张三或者山东的张三就是URL
URI 与 URL字段定义:
U : Uniform
R : Resource
I:鉴别
L : 定位
URI
举例:
URI = scheme:[//authority]path[?query][#fragment]
scheme 通常的实现途径为: HTTP、wechat
URL
scheme在URL中一般指的是protocol 协议
在REST中一般常用URL
资源操作 - HTTP 动词
GET
-
@GetMapping
-
- Spring Framework 4.2 引入
- Spring Boot 1.3 才可以使用
- Spring Boot 加以发展
@RequestMapping(method = RequestMethod.POST) // 注解“派生性” public @interface PostMapping { ... @AliasFor(annotation = RequestMapping.class) // 注解别名 String name() default ""; ... }
@PostMapping
是注解,@RequestMapping
是@PostMapping
的注解:@RequestMapping
是@PostMapping
的元注解@RequestMapping
元标注了@PostMapping
@AliasFor
只能标注在目标注解的属性,所annotation()
的注解必须是元注解,该注解attribute()
必须元注解的属性 - Spring Framework 4.2 引入
-
举例说明:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.OPTIONS) // 如果不增加元注解的话,会报错
public @interface OptionsMapping {
//需要重新定义属性
@AliasFor(annotation = RequestMapping.class) // 指定之后,RequestMethod 的属性
String name() default ""; // 不加的话,只是代表自己
}
然后再看看SpringBootApplication注解:
这也是为什么我们可以在启动springboot项目使用@EnableAutoConfiguration
的原因:
值得注意的是@EnableAutoConfiguration
来自于SpringFramework,而@@SpringBootApplication
则来自于springboot的jar包,说白了,就是springboot对于spring进一步的封装,所以为什么说学好springboot要学好spring,原因就在于此!
PUT
@PutMapping
POST
@PostMapping
PATCH
-
@PatchMapping
-
限制
-
Servlet API 没有规定 PATCH
-
Spring Web 对其做了扩展
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { ... protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpMethod httpMethod = HttpMethod.resolve(request.getMethod()); if (httpMethod == HttpMethod.PATCH || httpMethod == null) { processRequest(request, response); } else { super.service(request, response); } } ... }
-
DELETE
@DeleteMapping
自定义注解
基于以上的知识点,我们来模仿springboot自定义一个注解:
比如既实现注入bean也同时实现事务的注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Service // 它是 @Service 组件
@Transactional // 它是事务注解
public @interface TransactionalService { // @Service + @Transactional
@AliasFor(annotation = Service.class)
String value(); // 服务名称
@AliasFor(annotation = Transactional.class,attribute = "value")
String txName();
}
在service层调用:
@TransactionalService(value = "echoService-2020", txName = "myTxName") // @Service Bean + @Transactional
// 定义它的 Bean 名称
public class EchoService {
public void echo(String message) {
System.out.println(message);
}
}
测试类:
@ComponentScan(basePackages = "com.test.micro.services.mvc.service")
@EnableTransactionManagement
public class SpringApplication {
@Component("myTxName")
public static class MyPlatformTransactionManager implements PlatformTransactionManager {
@Override
public TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
return new DefaultTransactionStatus(
null, true, true,
definition.isReadOnly(), true, null
);
}
@Override
public void commit(TransactionStatus status) throws TransactionException {
System.out.println("Commit()....");
}
@Override
public void rollback(TransactionStatus status) throws TransactionException {
System.out.println("rollback()....");
}
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 注册 SpringApplication 扫描 com.test.micro.services.mvc.service
context.register(SpringApplication.class);
context.refresh(); // 启动
context.getBeansOfType(EchoService.class).forEach((beanName, bean) -> {
System.err.println("Bean Name : " + beanName + " , Bean : " + bean);
bean.echo("Hello,World");
});
context.close(); // 关闭
}
}
测试结果:
说明此注解生效,注入了service也实现了事务!
自描述消息
注解驱动
-
@RequestBody
JSON ->
MappingJackson2HttpMessageConverter
TEXT ->
StringHttpMessageConverter
-
@ResponseBody
JSON ->
MappingJackson2HttpMessageConverter
TEXT ->
StringHttpMessageConverter
返回值处理类:RequestResponseBodyMethodProcessor
接口编程
ResponseEntity
extends HttpEntity
RequestEntity
extends HttpEntity
返回值处理类:HttpEntityMethodProcessor
媒体类型(MediaType
)
org.springframework.http.MediaType#APPLICATION_JSON_UTF8_VALUE
- “application/json;charset=UTF-8”
HTTP 消息转换器(HttpMessageConverter
)
- application/json
MappingJackson2HttpMessageConverter
- text/html
StringHttpMessageConverter
代码导读
@EnableWebMvc
- 导入
DelegatingWebMvcConfiguration
(配置 Class)- 注册
WebMvcConfigurer
- 装配各种 Spring MVC 需要的Bean
- 注解驱动扩展点
HandlerMethodArgumentResolver
HandlerMethodReturnValueHandler
@RequestBody
和@ResponseBody
实现类RequestResponseBodyMethodProcessor
HttpEntityMethodProcessor
- 注册
实现 WebMvcConfigurer
?
WebMvcConfigurerAdapter
实现
后记
Q: 前后端分离和服务端渲染的区别
A: 服务端渲染,数据计算 + HTML 渲染均有服务端完成。
前后端:数据计算有服务端提供,JSON Web 端点(REST Web 接口),HTML 主要前端 JS 完成,以React、Vue.js(前端模板引擎)
下节预告:
- Reactive 原理
- WebFlux 使用场景
- WebFlux 整体架构
本节示例代码:https://github.com/harrypottry/microservices-project/spring-mvc-rest
更多架构知识,欢迎关注本套Java系列文章:Java架构师成长之路
转载:https://blog.csdn.net/qq_34361283/article/details/106296164