微服务属于分布式系统,微服务之间通过网络通信,服务之间的关系可以有很多种,其中一种是服务-消费。
比如购票时,用户直接调用的是购票微服务,而购票微服务需要调用用户微服务来获取用户信息以及余额信息等等,在这个场景下,用户微服务是服务提供者,电影微服务是一个服务消费者。
以上面的情景为例,创建一个用户微服务。
Spring Initialzr 创建一个Springboot项目(本文是2.7.10版本),预装 Springboot Web, lombok, Mysql Driver, Mybatis Framework四个工具包。
micro-example1
数据库# MySQL
# 驱动
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据库名
spring.datasource.name=defaultDataSource
# 数据库连接
spring.datasource.url=jdbc:mysql://localhost:3306/micro-example1?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT
# 用户名密码
spring.datasource.username=root
spring.datasource.password=root
# 数据初始化
spring.sql.init.schema-locations=classpath:db/schema.sql
spring.sql.init.data-locations=classpath:db/data.sql
spring.sql.init.mode=always
server.port=8081
spring.application.name=user-service
DROP TABLE IF EXISTS `user`;
CREATE TABLE user (
`id` INTEGER AUTO_INCREMENT,
`username` VARCHAR(40),
`name` VARCHAR(20),
`age` INTEGER(3),
`balance` DECIMAL(10,2) COMMENT '余额',
PRIMARY KEY (`id`)
);
INSERT INTO user VALUES (1, 'user1', '用户1', 21, 100.00);
INSERT INTO user VALUES (2, 'user2', '用户2', 22, 200.00);
INSERT INTO user VALUES (3, 'user3', '用户3', 23, 300.00);
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String username;
private String name;
private Integer age;
private BigDecimal balance;
}
定义一个根据id查询user记录的方法
import com.evanpatchouli.example1.model.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface UserMapper {
@Select("select * from user where id=#{id}")
User selById(Integer id);
}
import com.evanpatchouli.example1.model.User;
public interface UserService {
User selById(Integer id);
}
import com.evanpatchouli.example1.mapper.UserMapper;
import com.evanpatchouli.example1.model.User;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class UserServiceImpl implements UserService{
@Resource
private UserMapper userMapper;
@Override
public User selById(Integer id) {
return userMapper.selById(id);
}
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Result<T> {
int code;
String msg;
T data;
}
public class Resp {
public static <T> Result ok(String msg, T data) {
return new Result(200,msg,data);
}
public static <T> Result fail(String msg, T data) {
return new Result(200,msg,data);
}
}
import com.evanpatchouli.example1.model.Result;
import com.evanpatchouli.example1.model.User;
import com.evanpatchouli.example1.service.UserService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
@CrossOrigin
@RequestMapping("/user")
public class UserController<T> {
@Resource
private UserService userService;
@GetMapping("/{id}")
public Result<User> findById(@PathVariable Integer id) {
User user = userService.selById(id);
return new Result<>(200, "查找成功", user);
}
}
这里创建电影票微服务,准备工作类似,只安装Springboot Web和lombok即可。
写在配置文件里的意图是便于管理和更改地址
server.port=8080
spring.application.name=ticket-service
api.user-service=http://127.0.0.1:8081/user/
入口类内创建一个创建RestTemplate的Bean,作为rest-api客户端
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 TicketApplication {
@Bean
public RestTemplate rest() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(TicketApplication.class, args);
}
}
创建一个UserApi组件,使用rest客户端调用user服务的查询接口
import com.example.ticket.model.Result;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@Component
public class UserApi {
@Value("${api.user-service}")
private String baseUrl;
@Resource
private RestTemplate rest;
public Result findUserById(Integer id) {
//http://localhost:8081/user/:id
return rest.getForObject(baseUrl+id, Result.class);
}
}
定义一个查询能不能买下票的接口,传入2参数,票价和用户id。在接口内调用UserApi查询用户信息,进行一系列的判断(用户存在?余额充足?),最后返回结果
import com.example.ticket.api.UserApi;
import com.example.ticket.model.Resp;
import com.example.ticket.model.Result;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.HashMap;
@RestController
@CrossOrigin
@RequestMapping("/ticket")
public class TicketController {
@Resource
private UserApi userApi;
@GetMapping("/canibuy")
public Result canIBuy(@RequestParam Double price, @RequestParam Integer id) {
Result resp = userApi.findUserById(id);
HashMap user = (HashMap) resp.getData();
if (user==null){
return Resp.fail("用户不存在",user);
}
if (price.compareTo((Double) user.get("balance")) > 0){
return Resp.fail("余额不足",user);
}
return Resp.ok("余额充足", user);
}
}
这是一个最简单的微服务之间的调用,甚至都用不上SpringCloud,但很简洁得为我们展示了服务提供者和消费者之间的关系。