一、概念
基于springboot基础上用于快速构建分布式系统的通用模式的工具集。
二、特点
1、约定优于配置;
2、隐藏组件复杂性;
3、轻量级组件;
4、组件丰富,功能齐全,例如:服务发现、断路器、微服务网关等;
5、选型中立、丰富;
6、灵活。
三、服务消费者与服务提供者
在微服务架构中有两种角色:服务消费者与服务提供者,二者关系如下:
服务提供者:服务的被调用者
服务消费者:服务的调用者
例如,在电影系统中,用户购买电影票票之前,电影服务需要调用用户服务的接口获取用户信息,此时的电影服务就是调用方,即服务消费者,用户服务为被调用方,即服务提供者。
四、微服务实践
1、服务提供者:用户服务
项目结构如下:
这个demo主要是为了演示服务与服务之间的通信,因此不再配置数据源。
User.java
package com.my.user.entity;
import lombok.Data;
/**
* @author 垃圾美少女
*/
@Data
public class User {
private Integer id;
private String name;
private Integer age;
private String username;
private Integer balance;
}
IUserService.java
package com.my.user.service;
import com.my.user.entity.User;
/**
* @author 垃圾美少女
*/
public interface IUserService {
User getByUserId(Integer userId);
}
UserServiceImpl.java
package com.my.user.service.impl;
import com.my.user.entity.User;
import com.my.user.service.IUserService;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @author 垃圾美少女
*/
@Service
public class UserServiceImpl implements IUserService {
@Override
public User getByUserId(Integer userId) {
List<User> userList = getUserList();
userList = userList.stream()
.filter(user -> Objects.equals(user.getId(), userId))
.collect(Collectors.toList());
if (userList != null && userList.size() > 0) {
return userList.get(0);
}
return null;
}
/**
* 由于没有配置数据源,在此设置虚拟数据
*
* @return list
*/
private List<User> getUserList() {
List<User> list = new ArrayList<>(5);
for (int i = 0; i < 5; i++) {
User user = new User();
user.setAge(12 + 1);
user.setId(1 + i);
user.setName("用户" + i);
user.setUsername("用户名" + i);
user.setBalance(123 + i);
list.add(user);
}
return list;
}
}
UserController.java
package com.my.user.controller;
import com.my.user.Util.ReturnUtil;
import com.my.user.entity.User;
import com.my.user.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* @author 垃圾美少女
*/
@RestController
@Slf4j
public class UserController {
@Autowired
private IUserService userService;
/**
* 根据id获取用户信息
*
* @param userId 用户id
* @return map
*/
@RequestMapping(value = "/user/getUserInfo", method = RequestMethod.GET)
public Map getUserInfo(Integer userId) {
try {
log.info("/user/getUserInfo被访问,参数:userId=" + userId);
User user = userService.getByUserId(userId);
return ReturnUtil.succe***esult(user, "获取成功");
} catch (Exception e) {
log.error(e.getMessage(), e);
return ReturnUtil.errorResult(null, "获取失败");
}
}
}
ReturnUtil.java
package com.my.user.Util;
import java.util.HashMap;
import java.util.Map;
/**
* @author 垃圾美少女
*/
public class ReturnUtil {
public static Map succe***esult(Object data, String msg) {
Map<String, Object> map = new HashMap<>(3);
map.put("code", 1);
map.put("msg", msg);
map.put("data", data);
return map;
}
public static Map errorResult(Object data, String msg) {
Map<String, Object> map = new HashMap<>(3);
map.put("code", -1);
map.put("msg", msg);
map.put("data", data);
return map;
}
}
application.yml
server:
port: 8010 #指定端口为 8010
启动项目后访问:http://localhost:8010/user/getUserInfo?userId=1
得到相应:
{
"msg": "获取成功",
"data": {
"id": 1,
"name": "用户0",
"age": 13,
"username": "用户名0",
"balance": 123
},
"code": 1
}
表示接口已通。
2、服务消费者:电影服务
项目架构如下:
User.java和ReturnUtil.java与上例相同在此不再展示。
MovieApplicaiton.java
package com.my.movie;
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 MovieApplication {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(MovieApplication.class, args);
}
}
MovieController.java
package com.my.movie.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
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;
import java.util.HashMap;
import java.util.Map;
/**
* @author 垃圾美少女
*/
@RestController
@Slf4j
public class MovieController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/movie/findById", method = RequestMethod.GET)
public Map findById(Integer userId) {
log.info("/movie/findById被访问,参数:userId=" + userId);
ResponseEntity<HashMap> forEntity =
this.restTemplate.getForEntity("http://localhost:8010/user/getUserInfo?userId=" + userId, HashMap.class);
return forEntity.getBody();
}
}
application.yml
server:
port: 8020
此时启动项目,访问:http://localhost:8020/movie/findById?userId=1
得到响应:
{
"msg": "获取成功",
"code": 1,
"data": {
"id": 1,
"name": "用户0",
"age": 13,
"username": "用户名0",
"balance": 123
}
}
至此,一个简单的电影微服务就完成了。
五、上述例子中存在的问题
1、在代码中写死访问路径
在电影服务中,可以将user服务的访问路径写到yml配置文件中,使代码更清爽:
yml:
server: port: 8020 userService: domain: http://localhost:8010/user/ getUserByIdUrl: http://localhost:8010/user/getUserInfo?userId=
MovieController.java
package com.my.movie.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
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;
import java.util.HashMap;
import java.util.Map;
/**
* @author 垃圾美少女
*/
@RestController
@Slf4j
public class MovieController {
@Autowired
private RestTemplate restTemplate;
@Value("${userService.domain}")
private String userServiceDomain;
@Value("${userService.getUserByIdUrl}")
private String findByUserIdUrl;
@RequestMapping(value = "/movie/findById", method = RequestMethod.GET)
public Map findById(Integer userId) {
log.info("/movie/findById被访问,参数:userId=" + userId);
ResponseEntity<HashMap> forEntity =
this.restTemplate.getForEntity(findByUserIdUrl + userId, HashMap.class);
return forEntity.getBody();
}
}
2、适用场景有限:当用户服务的地址或端口号发生改变时,需要修改电影服务的配置文件并且重新部署,这显然是不可取的。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。