一、概念
基于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、适用场景有限:当用户服务的地址或端口号发生改变时,需要修改电影服务的配置文件并且重新部署,这显然是不可取的。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。