springcloud是目前比較成熟的微服務的完整方案,所謂微服務就是基于SOA基礎之上,将服務進一步拆分,使得粒度更細化。比如原有的服務可能包含多個功能子產品,而微服務則是每個服務代表一個功能。由于粒度細化,那麼會涉及到服務之間的互相調用,那麼就涉及到服務提供者和服務消費者。所謂服務提供者就是表示該服務提供給其他服務調用,服務消費者則是調用其他服務的服務,每個服務既可以是服務提供者又可以是服務消費者。本文通過一個簡單的例子來說明服務提供者和服務消費者的關系,為了更加明顯,本文消費者調用的方式采用寫死的形式。
1.服務提供者---學生微服務
作為服務提供者,就跟普通的springboot項目一緻,通過controller層的REST風格的http接口對外提供調用。本文介紹的服務提供者是一個學生基本資訊的微服務。首先還是通過IDEA上建立基于Maven管理的spring inittializr的項目,然後選擇相應的依賴。
1.1 pom檔案
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.carson</groupId>
<artifactId>microservice-student</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>microservice-student</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.2entity包中的Student類
Student類作為實體類,就是與存入jpa資料庫的每條記錄映射的對象,具體如下:
import javax.persistence.*;
/**
* ClassName Student
*建立學生實體類
* @author carson
* @description
* @Version V1.0
* @createTime 2019-09-01 20:06
*/
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long studentid;
@Column
private String studentname;
@Column
private String grade;
@Column
private Integer age;
@Column
private String sex;
public Long getStudentid() {
return studentid;
}
public void setStudentid(Long studentid) {
this.studentid = studentid;
}
public String getStudentname() {
return studentname;
}
public void setStudentname(String studentname) {
this.studentname = studentname;
}
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
1.3 dao層的StudentRepository類
import com.carson.microservicestudent.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* InterfaceName StudentRepository
*spring JPA操作的dao操作類
* @author carson
* @description
* @Version V1.0
* @createTime 2019-09-01 20:11
*/
public interface StudentRepository extends JpaRepository<Student,Long> {
}
該類實作了JpaRepository接口,用于對jpa資料庫操作,其中JpaRepository接口中對jpa資料庫操作的功能比較強大。是以,隻要構造一個實作JpaRepository接口的StudentRepository類來對student資料庫進行操作。
1.4 controller層的StudentController類
StudentController類是學生服務對外調用的http接口。
import com.carson.microservicestudent.dao.StudentRepository;
import com.carson.microservicestudent.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* ClassName StudentController
*
* @author carson
* @description
* @Version V1.0
* @createTime 2019-09-01 20:23
*/
@RestController
public class StudentController {
@Autowired
private StudentRepository studentRepository;
@RequestMapping(value = "/{studentid}",method = RequestMethod.GET)
public Student findById(@PathVariable Long studentid){
Student student = this.studentRepository.findById(studentid).get();
return student;
}
}
1.5 application.yaml檔案
server:
port: 8081
spring:
jpa:
generate-ddl: false
show-sql: true
hibernate:
ddl-auto: none
datasource:
platform: h2
schema: classpath:schema.sql
data: classpath:data.sql
logging:
level:
root: INFO
org.hibernate: INFO
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
org.hibernate.type.descriptor.sql.BasicExtractor: TRACE
1.6 sql檔案
資料表建立的sal:
drop table student if exists ;
create table student(studentid bigint generated by default as identity,studentname varchar(40),grade varchar(20),age int(3),sex varchar(20),primary key(studentid))
表中資料初始化的sql:
insert into student (studentid,studentname,grade,age,sex) values (10001,'Carson','third',25,'male');
insert into student (studentid,studentname,grade,age,sex) values (10002,'Amy','sixth',25,'female');
insert into student (studentid,studentname,grade,age,sex) values (10003,'Bob','five',25,'male');
insert into student (studentid,studentname,grade,age,sex) values (10004,'Cuz','second',25,'male');
insert into student (studentid,studentname,grade,age,sex) values (10005,'Max','fourth',25,'female');
以上schema.sql建立了student表,該表中的字段以及類型都是與Student實體類一一對應的。data.sql則是在student表中插入了幾條資料進行初始化。
1.7 服務啟動類
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MicroserviceStudentApplication {
public static void main(String[] args) {
SpringApplication.run(MicroserviceStudentApplication.class, args);
}
}
1.8 啟動服務
在浏覽器中輸入http://localhost:8081/10001 檢視運作結果,結果運作如下:
2.服務消費者---老師服務
比如有個服務是老師服務,該服務中如果需要擷取學生的資訊,則會需要調用學生服務,是以這裡老師服務就是服務消費者。
2.1 Student類
該類在服務提供者中需要作為實體類與資料庫進行映射,而在這不需要映射,而是對資料庫操作的結果進行1封裝,是以不需要與之前相同的注釋。
/**
* ClassName Student
*此類作為一個pojo類,作為服務消費者對資料庫操作時的記錄所對應的對象
* @author carson
* @description
* @Version V1.0
* @createTime 2019-09-01 23:05
*/
public class Student {
private Long studentid;
private String studentname;
private String grade;
private Integer age;
private String sex;
public Long getStudentid() {
return studentid;
}
public void setStudentid(Long studentid) {
this.studentid = studentid;
}
public String getStudentname() {
return studentname;
}
public void setStudentname(String studentname) {
this.studentname = studentname;
}
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
2.2 TeacherController 類
該類用RestTemplate請求服務提供者的API,并且需要在啟動類對RestTemplate進行執行個體化。然後在Controller中的接口中通過RestTemplate進行對Student服務的調用。具體如下:
import com.carson.microserviceteacher.pojo.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* ClassName TeacherController
* 老師controller類
* @author carson
* @description
* @Version V1.0
* @createTime 2019-09-01 23:05
*/
@RestController
public class TeacherController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/student/{studentid}",method = RequestMethod.GET)
public Student findStudentInfo(@PathVariable Long studentid){
return this.restTemplate.getForObject("http://localhost:8081/"+studentid,Student.class);
}
}
2.3 啟動類
上述controller類中用到了RestTemplate,是以在啟動類中需要執行個體化,具體如下:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class MicroserviceTeacherApplication {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(MicroserviceTeacherApplication.class, args);
}
}
2.4 application.yaml
server:
port: 8082
2.5 啟動服務
啟動服務後,浏覽器中輸入:http://localhost:8082/student/10001可以看到如下結果:
3.小結
老師服務通過RestTemplate進行對學生服務的調用進行操作student資料庫,進而擷取學生的資訊。這就是簡單的服務消費者與服務提供者之間的關系。但我們也會發現,這個例子中通過寫死的形式調用服務可能會使耦合度過高,如果學生服務換了url,則需要對老師服務的代碼進行修改再釋出,這不便于後期維護。這在後面會講到springcloud生态中一些功能來降低寫死帶來的耦合度問題。