栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Feign

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Feign

依赖管理

统一依赖版本号


	org.springframework.boot
	spring-boot-starter-parent
	2.4.2
	 



	1.8
	2.1.0
	6.0.6
	2020.0.1
	2.2.0.RELEASE
	2021.1



	
		
			org.springframework.cloud
			spring-cloud-dependencies
			${spring-cloud.version}
			pom
			import
		
		
			org.springframework.cloud
			spring-cloud-netflix-dependencies
			${spring-cloud-netflix.version}
			pom
			import
		
		
			com.alibaba.cloud
			spring-cloud-alibaba-dependencies
			${spring-cloud-alibaba.version}
			pom
			import
		
		
			org.mybatis.spring.boot
			mybatis-spring-boot-starter
			${mybatis.version}
		
		
			mysql
			mysql-connector-java
			${mysql.connector.version}
		
	

前提

说Feign之前,得先说说RestTemplate,RestTemplate用于访问远程http接口,比如A服务需要调用B方服务的方法,就可以使用RestTemplate,使用方式:

微服务使用nacos注册发现,这里需要加入ribbon作为负载均衡,添加依赖


	org.springframework.cloud
	spring-cloud-netflix-ribbon

Java代码

Application:

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.example.feign.client")
@MapperScan("com.example.service.order.dao")
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

    @LoadBalanced
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

}

Service:

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderDao orderDao;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private UserClient userClient;

    @Override
    public Order getOrderById(int id) {
        Order order = orderDao.selectById(id);
        // RestTemplate调用
        User user = getUser(order.getUserId());
        order.setUser(user);
        return order;
    }

    private User getUser(int userId) {
		// service-user是用户服务的服务名称,已经注册到nacos,这里不用写IP地址和端口号直接,使用服务名称即可
        String url = "http://service-user/user/get/" + userId;
        return restTemplate.getForObject(url, User.class);
    }

}

注意:用服务名称代替服务地址和端口号这种方式一定要加@LoadBalanced服务均衡注解和ribbon依赖,本人尝试不用这个注解,不加依赖,出现service-user服务找不到错误,这里踩了个坑!!!

以上是RestTemplate使用方式,看起来已经很简单了,但还是有点缺点:需要在代码上拼接URL地址,用起来不够优雅,来,我们们看看Feign优雅的做法

Feign使用

Feign也是远程服务调用的框架,它可以让我们使用接口一样调用远程服务,具体使用方法:

依赖

	org.springframework.cloud
	spring-cloud-starter-openfeign

Application代码:
@SpringBootApplication
@EnableDiscoveryClient
// 允许使用Feign远程调用
@EnableFeignClients
@MapperScan("com.example.service.order.dao")
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

//    @LoadBalanced
//    @Bean
//    public RestTemplate getRestTemplate() {
//        return new RestTemplate();
//    }

}
创建user服务FeignClient
// service-user是在nacos注册的服务名称
@FeignClient(value = "service-user")
public interface UserClient {

	// 只要把User服务的Controller对应的方法copy过来即可,不用实现
	// Feign会通过动态代理的方式帮我们调用Http请求
    @GetMapping("/user/get/{id}")
    User getUser(@PathVariable("id") int userId);

}
Service:
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderDao orderDao;

//    @Autowired
//    private RestTemplate restTemplate;

    @Autowired
    private UserClient userClient;

    @Override
    public Order getOrderById(int id) {
        Order order = orderDao.selectById(id);
        // RestTemplate调用
        // User user = getUser(order.getUserId());
        // Feign调用
        User user = userClient.getUser(order.getUserId());
        order.setUser(user);
        return order;
    }

//    private User getUser(int userId) {
//        String url = "http://service-user/user/get/" + userId;
//        return restTemplate.getForObject(url, User.class);
//    }

}

是不是变得更加优雅?!

性能优化

Feign默认底层使用URLConnection方式进行Http请求,这种方式是没有连接池的,调用一次连接一次,性能上可以优化,我们一般是使用HttpClient或OkHttp。

这里我使用OkHttp作为访问Http的方式,如下:

添加依赖

	io.github.openfeign
	feign-okhttp

application.yml修改
feign:
  httpclient:
    enabled: false
  okhttp:
    enabled: true

这样我们就允许使用OkHttp进行Http请求,如果需要设置最大连接数、单个服务最大连接数、连接超时时间等简单参数,只要添加配置

feign:
  httpclient:
    enabled: false
    max-connections: 200
    max-connections-per-route: 50
  okhttp:
    enabled: true

但是我们要一些复杂的配置,则需要添加配置类,这里注意了,我们不能简简单单弄一个@Bean出来,否则okhttp会失效。

我们需要copy一份OkHttpFeignConfiguration的代码,对其进行修改即可。

参考链接:https://blog.csdn.net/eric520zenobia/article/details/103547552

最佳实践

生产环境中,会出现A服务和B服务都调用C服务的方法,如果A服务和B服务都定义C服务的FeignClient,是不是很多余,我们可以把C服务的FeignClient抽取出来,作为公共模块使用。

所以一般会新建一个模块(feign-api),把C服务的FeignClient挪到这个模块,A服务和B服务依赖这个模块就行。

这里会出现一个情况,我们在Service使用Autowire注入的方式使用FeignClient:

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderDao orderDao;

    @Autowired
    private UserClient userClient;

    @Override
    public Order getOrderById(int id) {
        Order order = orderDao.selectById(id);
        User user = userClient.getUser(order.getUserId());
        order.setUser(user);
        return order;
    }

}

因为UserClient被我挪到了feign-api模块,包名不一样,也不在OrderApplication所在的包,所以会扫描不到,userClient会是空的

所以我们还要在Application代码修改一下:

@SpringBootApplication
@EnableDiscoveryClient
// 添加包名,这样SpringBoot才能扫描
@EnableFeignClients(basePackages = "com.example.feign.client")
// 还可以使用这种方式,用哪一个加哪一个
// @EnableFeignClients(clients = {UserClient.class})
@MapperScan("com.example.service.order.dao")
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/318473.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号