目錄導航
前言
前面的章節我們講了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架構師成長之路