demo(四)eureka&feign----声明式服务注册、提供与消费

一、使用介绍:

1、背景:feign整合了ribbon和hystrix:

(1)ribbon调用服务需要使用RestTemplate,不够简洁,而feign对此进行了封装,使用注解就可以实现轻松调用。

(2)ribbon需要对RestTemplate加@LoadBalanced注解才能实现负载均衡,feign对此也进行了封装,自带负载均衡;

(3)ribbon使用hystrix需要单独引入,feign则整合了hystrix。

2、feign主要注解:

(1)@EnableFeignClients类注解:启动类加上@EnableFeignClients注解即开启feign;

(2)@FeignClient类注解:替代RestTemplate实现服务调用,如果服务提供者(即eureka-client组件)在application配置文件里面配置了server.context-path,feign调用就需要指明path,如:@FeignClient(value = "my-service",path = "/myService");

注意这里的value值不分大小写,my-service和MY-SERVICE都可以。

3、feign调用eureka-client接口传参问题:

   (1)引用型参数:如Integer、String等,适用于get、post请求。调用方feign需要加@RequestParam注解,且括号中一定要有值(参数的别名)和被调用方erueka-client的参数名保持一致,被调用方可加@RequestParam也可不加;

(2)对象参数:javaBean,map,list等,只适用于post请求,被调用方eureka-client加@RequestBody注解,调用方feign可加可不加;

(3)参数位于路径中:用@PathVariable(),调用方需要指定别名。被调用方加注解即可。

(4)header头部参数:使用@RequestHeader注解,且value指明参数别名

@RequestMapping("/testToken")
    public UserDTO testToken(String username ,@RequestHeader("token") String token){
        return userService.testToken(username,token);
    }

二、下面实现消费者feign:

 在之前demo(一)eureka----服务注册与提供-CSDN博客的基础上,

和之前验证ribbon一样,先启动注册中心,再将eureka服务提供者启动两个节点2222、2223,

(idea工具点击edit configurations,选中allow parallel run允许一个项目启动多个实例)

下面创建feign工程:

1、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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.demo.cloud.feign</groupId>
    <artifactId>myspringcloud-feign</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!-- springBoot -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
    </properties>
    <dependencies>

        <!--不加此依赖,注册不到eureka上-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>com.demo.cloud.api</groupId>
            <artifactId>myspringcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>

        <!--解决启动报错Unregistering JMX-exposed beans on shutdown-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <!--<scope>provided</scope>-->
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

2、application.properties:

eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
spring.application.name=my-feign

server.port=4444
server.context-path=/feignDemo

3、启动类:

package com.demo.cloud;

import javafx.application.Application;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class MyFeignApplication {
    public static void main(String args[]){
        SpringApplication.run(MyFeignApplication.class,args);
    }
}

4、feign服务,调用服务提供者eureka-client:

(1)RoleService:

//如果eureka-client配置了application,则feign需要加上path
@FeignClient(value = "my-service",path = "/myService")
public interface RoleService {

    @RequestMapping("/role/findRoleByUserId")
    public List<RoleDTO> findRoleByUserId(@RequestParam("id") Integer id);
}

(2)UserService:

//如果eureka-client配置了context-path,则feign需要加上path;这里服务名称不区分大小写,my-service和MY-SERVICE都可以
@FeignClient(value = "my-service",path = "/myService")
public interface UserService {

    @RequestMapping(value = "/user/findByUserName")
    UserDTO findByUserName(@RequestParam("username") String userAccount);

    @RequestMapping(value = "/user/getAllUsers")
    List<UserDTO> getAllUsers();

    @RequestMapping("/user/getAuthortiesByUserId")
    List<AuthorityDTO> getAuthortiesByUserId(@RequestParam("userId") Integer userId);

    @RequestMapping("/user/addUser")
    void addUser1(UserDTO userDTO);

}

(3)TestService:

@FeignClient(value = "my-service",path = "/myService")
public interface TestService {

    @RequestMapping("/test/testList")
    void testList( List<UserDTO> userDTOS);

    @RequestMapping("/test/complexTest")
    String complexTest(@RequestParam("port") String port, @RequestParam("host") String host,
                      List<String> ids);
}

5、对外controller接口:

package com.demo.cloud.controller;

import com.demo.cloud.dto.UserDTO;
import com.demo.cloud.feign.TestService;
import com.demo.cloud.feign.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private UserService userService;

    @Autowired
    private TestService testService;

    @Value("${server.port}")
    private String port;

    //1、无参调用
    @RequestMapping("/getAllUsers")
    public List<UserDTO> getAllUsers(){
        return userService.getAllUsers();
    }

    //2、单个引用参数
    @RequestMapping("/findByUserName")
    public UserDTO findByUserName(String username){
        return userService.findByUserName(username);
    }

    //3、对象参数
    @RequestMapping("/addUser")
    public void addUser1(@RequestBody UserDTO userDTO){
        userService.addUser1(userDTO);
    }

    //4、集合参数
    @RequestMapping("/testList")
    public void testList(){
        List<UserDTO> userDTOS = new ArrayList<>();
        UserDTO userDTO = new UserDTO();
        userDTO.setUserName("name1");
        userDTOS.add(userDTO);
        userDTO = new UserDTO();
        userDTO.setUserName("name2");
        userDTOS.add(userDTO);
        testService.testList(userDTOS);
    }

    //5、组合参数
    @RequestMapping("/complexTest")
    public String complexTest(){

        String host = "localhost";
        List<String> ids = new ArrayList<>();
        ids.add("1");
        ids.add("2");
        String currPort = testService.complexTest(port,host,ids);
        return currPort;
    }
}

启动,看下feign也注册到注册中心了:

验证服务调用和负载均衡:

(1)无参

以这个接口为例查看两个服务提供者的节点均有访问记录:

       

(2)引用类型参数:

(3)对象参数

三、继承特性:

上面的例子可以看到client服务提供者的controller接口和feign服务消费者@FeignClient接口

有大段相似的代码,可以抽象到api里面。以/user用户接口为例改造后的代码:

1、api:改造后重新打包

   (1)pom添加web依赖

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.demo.cloud.api</groupId>
    <artifactId>myspringcloud-api</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    <build>
        <finalName>my-api</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <configuration>
                    <nonFilteredFileExtensions>
                        <nonFilteredFileExtension>xls</nonFilteredFileExtension>
                        <nonFilteredFileExtension>xlsx</nonFilteredFileExtension>
                    </nonFilteredFileExtensions>
                </configuration>
            </plugin>
        </plugins>
    </build>
   <!-- <build>
        <finalName>my-api</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-release-plugin</artifactId>

            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.2.1</version>
                <configuration>
                    <descriptors>
                        <descriptor>src/main/assemble/package.xml</descriptor>
                    </descriptors>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <excludes>
                        <exclude>**/*.properties</exclude>
                        <exclude>**/*.xml</exclude>
                        <exclude>**/*.html</exclude>
                        <exclude>config</exclude>
                    </excludes>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>-->

</project>

(2) 新增抽象的User服务

package com.demo.cloud.api.service;

import com.demo.cloud.api.dto.AuthorityDTO;
import com.demo.cloud.api.dto.UserDTO;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;
@RequestMapping("/user")
public interface CenterUserService {

    @RequestMapping("/findByUserName")
    UserDTO findByUserName(@RequestParam("username") String userAccount);

    @RequestMapping("/getAllUsers")
    List<UserDTO> getAllUsers();

    @RequestMapping("/getAuthortiesByUserId")
    List<AuthorityDTO> getAuthortiesByUserId(@RequestParam("userId") Integer userId);

    @RequestMapping("/addUser")
    void addUser(@RequestBody UserDTO userDTO);

    @RequestMapping("/getHeader")
    void getHeader(@RequestHeader("token") String token);
}

2、eureka-client服务提供者改动Controller接口:

package com.demo.cloud.controller;

import com.demo.cloud.api.dto.AuthorityDTO;
import com.demo.cloud.api.dto.UserDTO;
import com.demo.cloud.api.service.CenterUserService;
import com.demo.cloud.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
public class UserApiController implements CenterUserService {

    @Autowired
    private UserService userService;

    @Value("${server.port}")
    private String port;

    @Override
    public UserDTO findByUserName(String username){
        return userService.findByUserName(username);
    }

    @Override
    public List<UserDTO> getAllUsers(){
        System.out.println(port);
        return userService.getAllUsers();
    }

    @Override
    public List<AuthorityDTO> getAuthortiesByUserId(Integer userId){
        return userService.getAuthortiesByUserId(userId);
    }

    @Override
    public void addUser(@RequestBody UserDTO userDTO){
        userService.addUser(userDTO);
    }

    @Override
    public void getHeader(@RequestHeader("token")String token) {
        System.out.println("头部token:"+token);
    }

}

通过继承,controller中不再需要请求映射注解@RequestMapping,而参数的注解在重写时会自动带过来。这个Controller类只需要加个@RestController注解使其成为一个REST接口类,然后实现接口业务逻辑就可以了。

3、feign服务消费者改动feign服务:

package com.demo.cloud.api.feign;

import com.demo.cloud.api.service.CenterUserService;
import org.springframework.cloud.netflix.feign.FeignClient;

//如果eureka-client配置了context-path,则feign需要加上path;这里服务名称不区分大小写,my-service和MY-SERVICE都可以
@FeignClient(value = "my-service",path = "/myService")
public interface UserService extends CenterUserService {

}

先启动eureka-service,再启动clicent和feign,

测试:

(1)无参调用:localhost:4444/feignDemo/test/getAllUsers

(2)单参调用:localhost:4444/feignDemo/test/findByUserName?username=zhangsan

(3)对象参数调用:

(4)头部参数调用:localhost:4444/feignDemo/test/getHeader

四、分布式部署:

1、单独部署eurake-service:修改eureka-service配置文件的注册地址为

http://172.31.244.126:8091/eureka/,

并把urake-service注册中心部署到这台远程机器172.31.244.126上:

服务提供者和feign部署在本地,把eureka注册中心地址都修改为 http://172.31.244.126:8091/eureka/,

可以看到远程机器上可以监听到我本地机器的连接:

测试所有接口访问正常;

2、单独部署eureka-service和client:在上面的基础上,eureka-client也远程部署,如我部署到xxx.xx.xxx.151上 :

在本地只启动feign:

单独调用151的服务,访问成功:

但是通过feign来调用失败:

可能跟机器有关:

点击访问不了:

3、单独部署eureka-service、eureka-client和feign:

 在上面的基本上,把feign单独部署到xxx.xx.xxx.141机器上:

此时的三个组件分别 部署在三台机器上:eurake-service部署在126上,eurake-client部署在151上, feign部署在141上,所有接口访问成功:

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

w_t_y_y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值