1.先单独搭建一个微服务,这个微服务不需要配置文件,专门用来存放实体类与一些公用的配置类
package cn.xrj.springcloud.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class Qcpage extends Model implements Serializable{
/**
* 主键id
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 职位
*/
private String job;
/**
* 公司
*/
private String company;
/**
* 工作地点
*/
private String place;
/**
* 薪水
*/
private String salar;
/**
* 发布时间
*/
private String data;
/**
* 标记数据来自或存储到哪个数据库
*/
private String dbsource;
}
注意:@AllArgsConstructor注解表示全参构造方法,@NoArgsConstructor注解表示无参构造方法,@Accessors(chain = true)注解表示允许链式写法。dbsource属性用于标记数据库(微服务架构一般为分布式系统,所以记录数据的来源与去处),后面测试负载均衡时可见效果。
JobInfoService接口与ServiceFallBackFactory实现类用于Feign远程调用与服务降级时使用,目前不说明。
2.服务提供者
pom:
4.0.0
cn.microsoft
springcloud
1.0-SNAPSHOT
cn.xrj.springcloud
springcloud-provider-jobinfo-8001
0.0.1-SNAPSHOT
springcloud-provider-jobinfo-8001
1.8
org.springframework.cloud
spring-cloud-starter-eureka
1.4.6.RELEASE
org.springframework.boot
spring-boot-starter-actuator
cn.xrj.springcoud
springcloud-api
0.0.1-SNAPSHOT
org.springframework.boot
spring-boot-starter-jdbc
org.springframework.boot
spring-boot-starter-web
com.baomidou
mybatis-plus-boot-starter
org.springframework.boot
spring-boot-devtools
runtime
true
mysql
mysql-connector-java
org.springframework.boot
spring-boot-starter-test
test
com.baomidou
mybatis-plus-generator
org.apache.velocity
velocity-engine-core
junit
junit
test
src/main/java
**/*.xml
src/main/resources
**/*.yml
**/*.properties
**/*.xml
**/*.*
org.springframework.boot
spring-boot-maven-plugin
配置文件:
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 199654
url: jdbc:mysql://localhost:3306/pachong?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
application:
name: springcloud-provider-jobinfo //微服务名
mybatis-plus: //mybatis-plus配置
mapper-locations: classpath:cn/xrj/springcloud/mapper/*/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
type-aliases-package: cn.xrj.springcloud.pojo
server:
port: 8001 //端口号
eureka:
client:
service-url:
defaultZone://需要注册到的eureka集群 http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: springcloud-provider-jobinfo:8001 //微服务实例名
hostname: localhost
prefer-ip-address: true //是否显示IP地址
info: //这里配置,当点击eureka里的微服务时,跳到相应的info界面,而保护出现error页面
app.name: springcloud-provider-jobinfo
company.name: richinfo
author.name: xingrenjie
Controller层:
package cn.xrj.springcloud.controller;
import cn.xrj.springcloud.service.QcpageService;
import cn.xrj.springcloud.pojo.Qcpage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
*
* 51job招聘信息表 前端控制器
*
*
* @author xrj
* @since 2019-12-13
*/
@RestController
public class QcpageProviderController {
@Autowired
QcpageService qcpageService;
@Autowired
DiscoveryClient client;
@GetMapping("/qcpage/getAll")
public List getAll(){
List list= qcpageService.list();
return list;
}
@GetMapping("/qcpage/getById/{id}")
public Qcpage getById(@PathVariable("id")Integer id){
Qcpage qcpage=qcpageService.getById(id);
return qcpage;
}
@DeleteMapping("/qcpage/deleteById/{id}")
public boolean deleteById(@PathVariable("id")Integer id){
boolean flag=qcpageService.removeById(id);
return flag;
}
//获取注册进来的微服务,可以获得一些微服务信息,服务发现
@GetMapping("/qcpage/getservice")
public Object getService(){
List service=client.getServices();
System.out.println("service:"+service);
List instances=client.getInstances("springcloud-provider-jobinfo");
for (ServiceInstance instance : instances) {
System.out.println("serviceId:"+instance.getServiceId());
System.out.println("InstanceId:"+instance.getInstanceId());
System.out.println("host:"+instance.getHost());
System.out.println("port:"+instance.getPort());
}
return this.client;
}
}
启动类:
@SpringBootApplication
@MapperScan("cn.xrj.springcloud.mapper")
@EnableEurekaClient
@EnableDiscoveryClient //服务发现~
public class SpringcloudProviderJobinfo8001Application {
public static void main(String[] args) {
SpringApplication.run(SpringcloudProviderJobinfo8001Application.class, args);
}
}
其中:@EnableEurekaClient注解开启eureka客户端,@EnableDiscoveryClient注解开启服务发现,服务提供者跟普通的controller没什么区别!!,如果做集群,那么复制一份即可,如果不同服务器则端口需改!!!
3.服务消费者,开启Ribbon负载均衡,http远程调用服务
pom:
4.0.0
cn.microsoft
springcloud
1.0-SNAPSHOT
cn.xrj.springcloud
springcloud-consumer-jobinfo-80
0.0.1-SNAPSHOT
springcloud-consumer-jobinfo-80
1.8
org.springframework.cloud
spring-cloud-starter-eureka
1.4.6.RELEASE
org.springframework.cloud
spring-cloud-starter-ribbon
cn.xrj.springcoud
springcloud-api
0.0.1-SNAPSHOT
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-devtools
org.springframework.boot
spring-boot-starter-test
test
junit
junit
test
src/main/java
**/*.xml
src/main/resources
**/*.yml
**/*.properties
**/*.xml
**/*.*
org.springframework.boot
spring-boot-maven-plugin
配置文件:
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
Controller层:
package cn.xrj.springcloud.controller;
import cn.xrj.springcloud.pojo.Qcpage;
import org.springframework.beans.factory.annotation.Autowired;
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;
import java.util.List;
@RestController
public class QcpageConsumerController {
@Autowired
private RestTemplate restTemplate;
//以下注释常量为未使用ribbon负载均衡时配置的,只能调用某个微服务的一个实例,真实场景是某个微服务做了集群配置,所以此方法不用
// private static final String PRIFIX="http://localhost:8001";
//开启负载均衡后,主机名与端口号使用服务名代替,在调用时,则轮询调用某微服务下所有集群实例
private static final String PRIFIX="http://SPRINGCLOUD-PROVIDER-JOBINFO";
@RequestMapping("/consumer/jobinfo/getById/{id}")
public Qcpage getById(@PathVariable("id")Integer id){
return restTemplate.getForObject(PRIFIX+"/qcpage/getById/"+id,Qcpage.class);
}
@RequestMapping("/consumer/jobinfo/getAll")
public List getAll(){
return restTemplate.getForObject(PRIFIX+"/qcpage/getAll",List.class);
}
@RequestMapping("/consumer/jobinfo/deleteById/{id}")
public void deleteById(@PathVariable("id")Integer id){
restTemplate.delete(PRIFIX+"/qcpage/deleteById/{id}",id);
}
}
Ribbon配置及开启(默认配置轮询机制,可自定义配置,后续加上):
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced //此注解开启请求时使用ribbon负载均衡
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
启动类:
@SpringBootApplication( exclude= {DataSourceAutoConfiguration.class})配置此属性为了避免自动配置数据源,因为此服务为消费者,本身不需要数据源
@EnableEurekaClient//开启eureka客户端
public class SpringcloudConsumerJobinfo80Application {
public static void main(String[] args) {
SpringApplication.run(SpringcloudConsumerJobinfo80Application.class, args);
}
}
如此,启动eureka集群,启动服务提供者和消费者,访问消费者接口,则会远程调用服务提供者接口获取数据,因为开启了ribbon客户端负载均衡,所以,获取的数据的dbsource属性会有不同的值,表示来自不同的数据库。
4.服务消费者改用Feign接口方式调用服务(更符合面向接口编程,底层集成了Ribbon来实现负载均衡)
消费者的pom文件和api服务里导入依赖:
org.springframework.cloud
spring-cloud-starter-feign
1.4.6.RELEASE
由于底层集成了ribbon,所以ribbon还是要开启,配置简单。
然后在上面搭建的api这个微服务里新建service包,里面新建一个接口:
package cn.xrj.springcloud.service;
import cn.xrj.springcloud.pojo.Qcpage;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
@FeignClient(value = "springcloud-provider-jobinfo")
@Component
public interface JobInfoService {
@GetMapping("/qcpage/getAll")
List getAll();
@GetMapping("/qcpage/getById/{id}")
Qcpage getById(@PathVariable("id")Integer id);
@DeleteMapping("/qcpage/deleteById/{id}")
boolean deleteById(@PathVariable("id")Integer id);
}
此接口使用@FeignClient(value = "springcloud-provider-jobinfo")注解,表示此接口是一个Feign客户端,并调用的服务为名为springcloud-provider-jobinfo的微服务,里面包含三个抽象方法,对应了springcloud-provider-jobinfo微服务下的三个接口。注意,方法名可以不同,但返回值和参数类型必须相同,且接口路径和请求方式必须一一对应,用于标识哪个方法对应哪个接口。
消费者controller调用:
package cn.xrj.springcloud.controller;
import cn.xrj.springcloud.pojo.Qcpage;
import cn.xrj.springcloud.service.JobInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class QcpageConsumerController {
@Autowired
JobInfoService jobInfoService;
@RequestMapping("/consumer/jobinfo/getById/{id}")
public Qcpage getById(@PathVariable("id")Integer id){
return jobInfoService.getById(id);
}
@RequestMapping("/consumer/jobinfo/getAll")
public List getAll(){
return jobInfoService.getAll();
}
@RequestMapping("/consumer/jobinfo/deleteById/{id}")
public boolean deleteById(@PathVariable("id")Integer id){
return jobInfoService.deleteById(id);
}
}
到此,feign远程调用服务结束,是不是更加符合面向接口编程的思想!!也更方便实用!也很容易理解。