微服务架构
本文案例来自 周立博客跟我学Spring-Cloud系列
什么是微服务
微服务其实是一种风格,是将单体应用(所有功能在一个jar包里的应用程序)分为好几各部分,每个部分可以独立运行在不同的服务器中,每个部分还可以用不同的语言开发,服务间的通信采用轻量级通信机制(通常用HTTP资源API)
这种风格有什么优点呢
- 易于开发
- 单个服务启动快
- 技术栈不受限制
- 按需伸缩
怎么实现微服务架构呢
要想实现微服务,我们就先得解决各个服务间的通信问题,某个节点压力过大怎么办,服务挂了怎么解决,认证授权怎么解决等等问题。
铺垫这么多主角要登场啦,那就是SpringCould
,就算有它解决不了的,还可以整合其他框架来解决
第一个springcloud应用
首先了解,服务提供者和服务消费者,简明字意提,提供服务的(如服务器),和使用服务的(如客户端),当然了,所谓的服务消费者和服务生成者是相对而言的,谁提供服务谁就是服务提供者,也有服务器给服务器提供服务的。
如下的案例,来实现上面这张图,用户微服务为服务提供者,电影微服务为服务消费者,小案例到最后可以用电影微服务查到用户微服务的用户信息
先来写个服务提供者(项目名自己起)
先到入依赖
<?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.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.txz</groupId>
<artifactId>microservice-simple-provider-user</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>microservice-simple-provider-user</name>
<description>服务提供给</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 数据库 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
<!--springcloud依赖-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR2</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>
这个简单案例使用的H2数据库不知道H2数据库没关系,跟着做先就行。
这里使用lombok
,IDEA里要导入lombok的插件,它可以帮助我们自动生成getset
方法
编写实体类,注解千万不要忘记,包也不要导错
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
private String username;
@Column
private String name;
@Column
private Integer age;
@Column
private BigDecimal bigDecimal;
}
编写Dao
@Repository
public interface UserDao extends JpaRepository<User,Long> {
}
编写controller
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserDao userDao;
@GetMapping("/{id}")
public Optional<User> findById(@PathVariable Long id){
return this.userDao.findById(id);
}
}
编写Springboot的启动类,Spring Boot2不能像1.x一样,用spring.datasource.schema/data指定初始化SQL脚本,否则与actuator不能共存,所有手动添加
@SpringBootApplication
public class MicroserviceSimpleProviderUserApplication {
public static void main(String[] args) {
SpringApplication.run(MicroserviceSimpleProviderUserApplication.class, args);
}
@Bean
ApplicationRunner init(UserDao userDao){
return args -> {
User user1 = new User(1L,"xiaoming","小明",20,new BigDecimal(1000.00));
User user2 = new User(2L,"xiaohong","小红",20,new BigDecimal(1000.00));
User user3 = new User(3L,"xiaogang","小刚",20,new BigDecimal(1000.00));
Stream.of(user1,user2,user3).forEach(userDao::save);
};
}
}
配置文件
server:
port: 8000
spring:
jpa:
show-sql: true #让hibernate打印执行的SQL语句
logging:
level:
root: INFO
org.hibernate: INFO
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
org.hibernate.type.descriptor.sql.BasicExtractor: TRACE
运行测试,http://localhost:8000/user/1
,得到数据
服务消费者 电影微服务
电影微服务,只需要导入,spring web,spring cloud,的包即可
实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String username;
private String name;
private Integer age;
private BigDecimal balance;
}
编写collection,这里使用RestTemplate调用用户微服务的API,从而查询指定id的用户信息
@RequestMapping("/movies")
@RestController
public class MovieController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/users/{id}")
public User findById(@PathVariable Long id){
//这里用到了RestTemplate的占位符的能力
User forObject = restTemplate.getForObject("http://localhost:8000/user/{id}", User.class, id);
return forObject;
}
}
编写启动类
@SpringBootApplication
public class MicroserviceSimpleConsumerMovieApplication {
public static void main(String[] args) {
SpringApplication.run(MicroserviceSimpleConsumerMovieApplication.class, args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
测试
用浏览器访问http://localhost:8010/movies/users/1
,可得到数据
RestTemplate实现了基于HTTP的远程调用,事实上,Spring 5开始,WebFlux提供了Reactive的Web Client:
WebClinet
,使用方式和RestTemplate基本类似,但性能更强,吞吐更好。有兴趣的可前往https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/web-reactive.html#webflux-client-builder 了解。
如上我们完成一个简单的单点微服务的实现,该dome有很多问题,有一个http路径在代码中,如果是多个,要改变其端口号,改起来就很麻烦。还有很多比如容错之类的,在之后会 一 一 在该小dome加上