Springcloud:
搭建第一个springcloud程序
Maven项目创建(父工程):
pom文件导入相关依赖。(父依赖)
<!--配置打包方式--> <packaging>pom</packaging> <dependencyManagement> <dependencies> <!--添加springcloud依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <!--<version>Finchley.SR2</version>--> <version>Edgware.SR5</version> <type>pom</type> <scope>import</scope> </dependency> <!--添加springboot依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.2.1.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <!--配置数据库--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--配置数据源--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <!--springboot启动器--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.20</version> </dependency> </dependencies> </dependencyManagement>
创建一个module写实体类,
(数据库--实体类属性。一一映射)。
pom文件导入依赖
<!--导入当前module中自己需要的依赖,父类中有的依赖 就不需要写版本了--> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies>
创建实体类
/** * 实体类,必须实现序列化 */ @Data @NoArgsConstructor//无参构造 @Accessors(chain = true)//链式写法 public class Dept implements Serializable{ private long deptno;//主键 private String dname;//部门名字 //这个 数据是表示 数据在那个数据库;微服务 一个服务对应一个数据库 同一个信息可能存在不同的数据库 private String db_source; public Dept(String dname) { this.dname = dname; } /* 一般写法: dept dept = new dept dept.setdeptno(); dept.setdeptname(); 链式写法:dept dept =new dept dept.setdeptno().setdeptname(); */ }
创建第二个module
配置pom文件
<packaging>pom</packaging> <dependencies> <!--拿到我们写的实体类--> <dependency> <groupId>com.guo</groupId> <artifactId>springcloud-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
配置application.yml. 和mybatis.配置
resources文件夹下创建application.yml 并配置 端口、mybatis、Spring配置
server: port: 8001 #端口号 #mybatis配置 mybatis: type-aliases-package: com.guo.springcloud.pojo #mybatis别名 config-location: classpath:mybatis/mybatis-config.xml mapper-locations: classpath:mapper/*.xml #Spring的配置 spring: application: name: springcloud-provider-dept datasource: type: com.alibaba.druid.pool.DruidDataSource #配置数据源 driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/springcloud-api?useUnicode=true&characterEncoding=utf-8 username: root password: yang.3602
在resource下创建mapper包->>deptMapper.xml
mybatis包->>mybatis-config.xml
并配置mybatis-config.xml文件:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <!--开启二级缓存--> <setting name="cacheEnabled" value="true"/> </settings> </configuration>
创建接口(mapper 也就是dao层)
java->>com->>duo->>spring cloud->>mapper->>deptMapper(接口)
@Mapper @Repository//为了托管给spring public interface deptMapper { public boolean addDept(pojo pojo); public pojo queryById(long id); public List<pojo> queryAll(); }
配置 mapper.xml文件
resources->>mapper->>deptMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.guo.springcloud.mapper.deptMapper"> <insert id="addDept" parameterType="com.guo.springcloud.pojo.Dept"> insert into dept (dname,db_source) values (#{dname},DATABASE()); </insert> <select id="queryById" parameterType="Long" resultType="com.guo.springcloud.pojo.Dept"> select * from dept where deptno = #{deptno}; </select> <select id="queryAll" resultType="com.guo.springcloud.pojo.Dept"> select * from dept; </select> </mapper>
service层
service接口
public interface deptService { public boolean addDept(Dept dept); public Dept queryById(long id); public List<Dept> queryAll(); }
service实现类
@Service public class deptServiceImpl implements deptService { @Autowired private deptMapper deptMapper; public boolean addDept(Dept dept) { return deptMapper.addDept(dept); } public Dept queryById(long id) { return deptMapper.queryById(id); } public List<Dept> queryAll() { return deptMapper.queryAll(); } }
创建controller层
@RestController public class DeptController { @Autowired private deptService deptService; // @Autowired // private deptService deptService; // 相等于 //private deptService deptService = new deptServiceImpl; @GetMapping("/dept/add") public boolean addDept(Dept dept){ return deptService.addDept(dept); } @GetMapping("/dept/get/{id}") public Dept get(@PathVariable("id") Long id){ //@PathVariable("id") :动态接收参数 直接 把 参数 当成链接的一部分了,然后接受这个 参数 就用 这个 注解 接受 就能 收到了 return deptService.queryById(id); } @GetMapping("/dept/list") public List<Dept> queryAll(){ return deptService.queryAll(); } }
创建springboot启动类
(DeptProvider_8001.java)
@SpringBootApplication public class DeptProvider_8001 { public static void main(String[] args) { SpringApplication.run(DeptProvider_8001.class,args); } }
注解说明:
@PathVariable("id") :
动态接收参数 直接 把 参数 当成链接的一部分了,然后接受这个参数就用这个注解接受就能收到了
@Repository :
接口上 都 有 这个注解,这个是 把 这个 接口 放到容器里去 管理,用@Autowired 注解 就可以 获取到 这个 接口 实例,这个 是 spring 依赖注入 的原理
@Autowired :
@Autowired private deptService deptService;
相等于private deptService deptService = new deptServiceImpl;
创建第三个module(模拟前端服务)
创建module(springcloud-consumer-dept-80)
导入pom文件
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>springcloud</artifactId> <groupId>com.guo</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>springcloud-consumer-dept-80</artifactId> <!--实体类+web--> <!--该module相当于前端页面--> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.guo</groupId> <artifactId>springcloud-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
配置端口:
server: port: 80
配置RestTemplate
创建config包->>ConfigBean类
@Configuration public class ConfigBean {//@Configuration 相当于 spring的 applicationContext.xml(配置bean的) @Bean public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
创建controller来访问 其他服务
controller->>DeptConsumerController类
@RestController public class DeptConsumerController { //理解: 消费者(前端)不应该有service层 用RestTemplate 通过url调用 //RestTemplate 供我们直接调用就可以了 注入到spring中 //参数 (url, 实体:Map,Class<T> responseType ) @Autowired private RestTemplate restTemplate; // private RestTemplate restTemplate =new RestTemplate();// 提供多种便捷访问http远程服务的方法,简单的restful服务模版~ private static final String REST_URL_PREFIX ="http://localhost:8001"; @RequestMapping("consumer/dept/add") public Boolean add(Dept dept){ return restTemplate.getForObject(REST_URL_PREFIX + "/dept/add", boolean.class); } @RequestMapping("consumer/dept/get/{id}") public Dept get(@PathVariable("id") Long id){ return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class); } @RequestMapping("/consumer/dept/list") public List<Dept> list(){ return restTemplate.getForObject(REST_URL_PREFIX+ "/dept/list",List.class); } }
创建springcloud-consumer-dept-80服务的启动类
(DeptConsumer_80)
@SpringBootApplication public class DeptConsumer_80 { public static void main(String[] args) { SpringApplication.run(DeptConsumer_80.class,args); } }
两个服务启动后。通过访问消费者(模拟前端)的controller。就可以获取数据
注解及新内容说明:
@Configuration:
相当于 spring的 applicationContext.xml(配置bean的)
RestTemplate:
先在配置类中配置RestTemplate (以bean形式配置)(访问其他项目 其他服务)就是你写了一个 restcontroller 访问应该写localhost+端口 +请求路径然后 这个 controller就给你 返回数据 RestTemplate可以调用一个方法 就可以获取别的项目的controller的数据, 理解: 消费者(前端)不应该有service层 用RestTemplate 通过url调用 RestTemplate 供我们直接调用就可以了 注入到spring中
创建eureka服务
导入eureka依赖。 (eureka相当于。zookeeper)
<!--导包--> <dependencies> <!--eureka依赖 相当于zookeeper--> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> <version>1.4.6.RELEASE</version> </dependency> </dependencies>
编写配置文件application.yml
server: port: 7001 #Eureka配置 eureka: instance: hostname: localhost #服务端的实力化名称 client: register-with-eureka: false #表示是否向eureka注册自己 fetch-registry: false #为false时 表示自己为注册中心 service-url: #监控页面(页面的URL) defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
创建启动类
@SpringBootApplication @EnableEurekaServer// 服务端的启动类 可以接收别人注册进来 public class EurekaServer_7001 { public static void main(String[] args) { SpringApplication.run(EurekaServer_7001.class,args); } }
启动服务后 访问 http://localhost:7001/
注解说明:
@EnableEurekaServer
启动Eureka服务。 服务端的启动类 可以接收别人注册进来
将服务注册到eureka中
(将springcloud-provider-dept-8001)
在springcloud-provider-dept-8001的pom文件中。导入eureka依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency>
修改application.yml文件配置
#Eureka配置 服务注册到哪里 eureka: client: service-url: defaultZone: http://localhost:7001/eureka/
在启动类中添加注解
@EnableEurekaClient//在服务启动后 自动注册到eureka中
注解说明:
@EnableEurekaClient
在服务启动后 自动注册到eureka中
Eureka配置集群
CAP原则及Eureka与Zookeeper对比
负载均衡及Ribbon
(客户端去注册中心拿地址,所以肯定是去配置消费者(相当于前端)的服务)
客户端(消费者服务)集成Ribbon
配置 80服务的 pom文件(导入ribbon依赖 和eureka依赖)
<!--导入ribbon依赖--> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--导入eureka 依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency> </dependencies>
编写配置:
#eureka配置 eureka: client: register-with-eureka: false #不向注册中心注册自己 service-url: defaultZone: http://localhost1:7001/eureka/,http://localhost2:7002/eureka/,http://localhost3:7003/eureka/
在主启动类上添加eureka的启动注解 @EnableEurekaClient
在RestTemplate配置中。加上注解@LoadBalanced 配置负载均衡。通过 @LoadBalanced 实现了RestTemplate去不同地址上拿服务
//配置负载均衡 实现RestTemplate @LoadBalanced//ribbon
在controller里边 配置url
// ribbon 我们这里的地址 应该是个变量, 通过服务名来访问 // private static final String REST_URL_PREFIX ="http://localhost:8001"; private static final String REST_URL_PREFIX ="http://SPRINGCLOUD-PROVIDER-DEPT";
结论:
Ribbon 和 Eureka 整合以后,客户端可以直接调用, 不用关心IP地址和端口号
Feign(服务之间的调用)接口调用
- Feign能干什么?
- feign只在编写Java Http客户端变得更方便
- 在Feign的实现下,我们只需要创建一个接口并使用@Feign注解的方式配置他(类似于以前的Dao接口上标注Mapper注解,现在是一个为服务接口上面标注一个Feign注解即可)
- Feign的使用
- 1、创建Feign接口
@Component @FeignClient(name = "需要调用的服务名") @RequestMapping(value = "被调用服务的Controller") public interface SysUserServiceClient { @RequestMapping( value = "/byBaseUserId/{id}", method = RequestMethod.GET) ControllerDataBo<SysUserDetailBo> view(@PathVariable("id") Long id);
- 2、在需要的service层实例化该Feign接口
@Autowired private SysUserServiceClient sysUserServiceClient;
- 3、通过实力化对象访问接口下的方法(相当于访问了被调用服务的相应controller)
ControllerDataBo<SysUserDetailBo> ControllerDataBo = sysUserServiceClient.view(Long.parseLong(detailsBo.getId()));
- 实例
@Component @FeignClient(name = "${bd2.fegin.sysService:sysService}") @RequestMapping(value = "/user") public interface SysUserServiceClient { @RequestMapping( value = "/byBaseUserId/{id}", method = RequestMethod.GET) ControllerDataBo<SysUserDetailBo> view(@PathVariable("id") Long id); @RequestMapping( method = RequestMethod.GET) ControllerDataBo<List<SysUserSimpleBo>> list(@RequestParam("baseUserIds") List<Long> baseUserIds, @RequestParam("userName") String userName, @RequestParam("name") String name, @RequestParam("enabledFlag") Boolean enabledFlag, @RequestParam("page") Integer page, @RequestParam("limit") Integer limit, @RequestParam("start") Integer start);