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生态中一些功能来降低硬编码带来的耦合度问题。