- 创建父工程
- 创建服务提供者
- 创建服务调用者
- 存在的问题
学了黑马的SpringCloud后,整个项目工程结构:
先创建一个父工程,然后后续的工程都以这个工程为父。在实际开发中,每个微服务可独立一个工程。
工程目录结构:
在pom文件中添加对应依赖:
4.0.0 com.itheima heima-springcloud pom 1.0-SNAPSHOT org.springframework.boot spring-boot-starter-parent 2.1.5.RELEASE 1.8 Greenwich.SR1 2.1.5 8.0.22 org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import tk.mybatis mapper-spring-boot-starter ${mapper.starter.version} mysql mysql-connector-java ${mysql.version} org.springframework.cloud spring-cloud-starter-config org.projectlombok lombok org.springframework.boot spring-boot-maven-plugin
这里已经对大部分要用到的依赖的版本进行了 管理,方便后续使用
创建服务提供者新建一个项目user-service,对外提供查询用户的服务。
对应pom文件:
heima-springcloud com.itheima 1.0-SNAPSHOT 4.0.0 user-service 8 8 org.springframework.boot spring-boot-starter-web tk.mybatis mapper-spring-boot-starter ${mapper.starter.version} mysql mysql-connector-java ${mysql.version}
编写配置文件:
创建 user-servicesrcmainresourcesapplication.yml 属性文件,这里我们采用了yaml语法,而不是properties
server:
port: 9091
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springcloud?serverTimezone=UTC
username: root
password: 123456@root
mybatis:
type-aliases-package: com.itheima.user.pojo
使用mysql图形界面工具创建 springcloud 数据库,创建tb_user表
USE springcloud;
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for tb_user
-- ----------------------------
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`user_name` VARCHAR(100) DEFAULT NULL COMMENT '用户名',
`password` VARCHAR(100) DEFAULT NULL COMMENT '密码',
`name` VARCHAR(100) DEFAULT NULL COMMENT '姓名',
`age` INT(10) DEFAULT NULL COMMENT '年龄',
`sex` TINYINT(1) DEFAULT NULL COMMENT '性别,1男性,2女性',
`birthday` DATE DEFAULT NULL COMMENT '出生日期',
`note` VARCHAR(255) DEFAULT NULL COMMENT '备注',
`created` DATETIME DEFAULT NULL COMMENT '创建时间',
`updated` DATETIME DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`user_name`)
) ENGINE=INNODB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tb_user
-- ----------------------------
INSERT INTO `tb_user` VALUES ('1', 'zhangsan', '123456', '张三', '30', '1', '1964-08-08', '张三同学在学Java', '2014-09-19 16:56:04', '2014-09-21 11:24:59');
INSERT INTO `tb_user` VALUES ('2', 'lisi', '123456', '李四', '21', '2', '1995-01-01', '李四同学在传智学Java', '2014-09-19 16:56:04', '2014-09-19 16:56:04');
INSERT INTO `tb_user` VALUES ('3', 'wangwu', '123456', '王五', '22', '2', '1994-01-01', '王五同学在学php', '2014-09-19 16:56:04', '2014-09-19 16:56:04');
INSERT INTO `tb_user` VALUES ('4', 'zhangliu', '123456', '张六', '20', '1', '1996-09-01', '张六同学在传智播客学Java', '2014-09-19 16:56:04', '2014-09-19 16:56:04');
INSERT INTO `tb_user` VALUES ('5', 'lina', '123456', '李娜', '28', '1', '1988-01-01', '李娜同学在传智播客学Java', '2014-09-19 16:56:04', '2014-09-19 16:56:04');
INSERT INTO `tb_user` VALUES ('6', 'lilei', '123456', '李雷', '23', '1', '1993-08-08', '李雷同学在传智播客学Java', '2014-09-20 11:41:15', '2014-09-20 11:41:15');
INSERT INTO `tb_user` VALUES ('7', 'hanmeimei', '123456', '韩梅梅', '24', '2', '1992-08-08', '韩梅梅同学在传智播客学php', '2014-09-20 11:41:15', '2014-09-20 11:41:15');
INSERT INTO `tb_user` VALUES ('8', 'itcast', '123456', '传智播客', '21', '2', '2008-07-08', '传智播客搞IT教育', '2014-09-20 11:41:15', '2014-09-20 11:41:15');
INSERT INTO `tb_user` VALUES ('9', 'heima', '123456', '黑马', '18', '2', '2012-08-08', '黑马是传智播客高端品牌', '2014-09-20 11:41:15', '2014-09-20 11:41:15');
INSERT INTO `tb_user` VALUES ('10', 'linus', '123456', '林纳斯', '45', '2', '1971-08-08', '林纳斯搞了linux又搞git', '2014-09-20 11:41:15', '2014-09-20 11:41:15');
INSERT INTO `tb_user` VALUES ('11', 'leijun', '123456', '雷布斯', '33', '2', '1983-08-08', '小爱同学;are you ok', '2014-09-20 11:41:15', '2014-09-20 11:41:15');
INSERT INTO `tb_user` VALUES ('12', 'madaye', '123456', '马大爷', '46', '2', '1980-08-08', '马大爷花呗可以不还吗', '2014-09-20 11:41:15', '2014-09-20 11:41:15');
编写 user-servicesrcmainjavacomitheimauserUserApplication.java 启动类:
package com.itheima.user;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import tk.mybatis.spring.annotation.MapperScan;
@SpringBootApplication
@MapperScan(basePackages = "com.itheima.user.mapper")//扫描通用mapper所在包
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
编写 user-servicesrcmainjavacomitheimauserpojoUser.java 实体类:
package com.itheima.user.pojo;
import lombok.Data;
import tk.mybatis.mapper.annotation.KeySql;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
@Data
@Table(name = "tb_user")
public class User{
// id
@Id
//开启主键自动回填
@KeySql(useGeneratedKeys = true)
private Long id;
// 用户名
private String userName;
// 密码
private String password;
// 姓名
private String name;
// 年龄
private Integer age;
// 性别,1男性,2女性
private Integer sex;
// 出生日期
private Date birthday;
// 创建时间
private Date created;
// 更新时间
private Date updated;
// 备注
private String note;
}
编写 user-servicesrcmainjavacomitheimausermapperUserMapper.java
package com.itheima.user.mapper; import com.itheima.user.pojo.User; import tk.mybatis.mapper.common.Mapper; public interface UserMapper extends Mapper{ }
编写 user-servicesrcmainjavacomitheimauserserviceUserService.java
package com.itheima.user.service;
import com.itheima.user.mapper.UserMapper;
import com.itheima.user.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
UserMapper userMapper;
public User queryById(Long id){
return userMapper.selectByPrimaryKey(id);
}
}
添加一个对外查询的接口处理器
user-servicesrcmainjavacomitheimausercontrollerUserController.java
package com.itheima.user.controller;
import com.itheima.user.pojo.User;
import com.itheima.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
UserService userService;
@GetMapping("/{id}")
public User queryById(@PathVariable Long id){
return userService.queryById(id);
}
}
创建完成后项目结构图:
启动 user-service 项目,访问接口:http://localhost:9091/user/8
与上面类似,这里不再赘述,需要注意的是,我们调用 user-service 的功能,因此不需要mybatis相关依赖了。
consumer-demo对应pom文件:
heima-springcloud com.itheima 1.0-SNAPSHOT 4.0.0 consumer 8 8 org.springframework.boot spring-boot-starter-web
编写启动类 consumer-demosrcmainjavacomitheimaconsumerConsumerApplication.java 并在其中注入 RestTemplate 具体如下:
package com.itheima.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
创建实体类
consumer-demosrcmainjavacomitheimaconsumerpojoUser.java
package com.itheima.consumer.pojo;
import lombok.Data;
import java.util.Date;
@Data
public class User{
// id
private Long id;
// 用户名
private String userName;
// 密码
private String password;
// 姓名
private String name;
// 年龄
private Integer age;
// 性别,1男性,2女性
private Integer sex;
// 出生日期
private Date birthday;
// 创建时间
private Date created;
// 更新时间
private Date updated;
// 备注
private String note;
}
编写 consumer-demosrcmainjavacomitheimaconsumercontrollerConsumerController.java ,在controller中直接调用RestTemplate,远程访问 user-service 的服务接口:
package com.itheima.consumer.controller;
import com.itheima.consumer.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("{id}")
public User queryById(@PathVariable Long id){
String url = "http://localhost:9091/user/" + id;
return restTemplate.getForObject(url, User.class);
}
}
启动测试
启动 consumer-demo 引导启动类;因为 consumer-demo 项目没有配置端口,那么默认就是8080,我们访问:http://localhost:8080/consumer/8
user-service:对外提供了查询用户的接口
consumer-demo:通过RestTemplate访问 http://locahost:9091/user/{id} 接口,查询用户数据
存在什么问题?
- 在consumer中,我们把url地址硬编码到了代码中,不方便后期维护
- consumer需要记忆user-service的地址,如果出现变更,可能得不到通知,地址将失效
- consumer不清楚user-service的状态,服务宕机也不知道
- user-service只有1台服务,不具备高可用性
- 即便user-service形成集群,consumer还需自己实现负载均衡
其实上面说的问题,概括一下就是分布式服务必然要面临的问题: - 服务管理
如何自动注册和发现
如何实现状态监管
如何实现动态路由 - 服务如何实现负载均衡
- 服务如何解决容灾问题
- 服务如何实现统一配置
以上的问题,都将在SpringCloud中得到解决。



