Spring-cloud-openfeign3.0服务单元化动态指定服务名

背景

上次写了一篇关于Spring-cloud-openfeign 2.x版本的单元化动态指定服务名的方法,那个方法是由于Spring-cloud-openfeign的Targeter是package范围的接口,不允许自行实现,不得已而变通的方法。后来我又直接和Spring-cloud-openfeign开发团队联系,让他们改了一些东西,最近发现他们已经按我的建议修改了,而且已经发布到了Spring-cloud-openfeign 3.0.0.M2版本里面了。所以今天就按照新的方法来优雅地实现单元化动态指定服务名。
废话不多说,直接上示例

示例代码

1. 在Service Client中API的URL中定义一个特殊的变量标记,如:
@FeignClient("customer-service-CLUSTER-ID")
public interface CustomerService {
	@GetMapping("/echo/{customer}")
	public String customerInfo(@PathVariable("customer") String customer);
}

上述示例中的,FeignClient的服务名称,以“CLUSTER-ID”结尾,用来标识本服务是单元化的,运行时,要把“CLUSTER-ID”替换为实际定位到的单元ID。(本来想用“%CLUSTER-ID%”特殊符号作为变量place-holder,但Spring-cloud-openfeign会在启动校验服务名,判定为非法域名,所以只能用合法的域名允许的字符。)

2. 以HardCodedTarget为基础,实现Targeter
public class RouteTargeter implements Targeter {
	/**
	 * 服务名以本字符串结尾的,会被置换为实现定位到的单元号
	 */
	public static final String CLUSTER_ID_SUFFIX = "CLUSTER_ID";

	@Override
	public <T> T target(FeignClientFactoryBean factory, Builder feign, FeignContext context,
			HardCodedTarget<T> target) {

		return feign.target(new RouteTarget<>(target));
	}

	public static class RouteTarget<T> implements Target<T> {
		Logger log = LoggerFactory.getLogger(getClass());
		private Target<T> realTarget;

		public RouteTarget(Target<T> realTarget) {
			super();
			this.realTarget = realTarget;
		}

		@Override
		public Class<T> type() {
			return realTarget.type();
		}

		@Override
		public String name() {
			return realTarget.name();
		}

		@Override
		public String url() {
			String url = realTarget.url();
			if (url.endsWith(CLUSTER_ID_SUFFIX)) {
				url = url.replace(CLUSTER_ID_SUFFIX, locateCusterId());
				log.debug("url changed from {} to {}", realTarget.url(), url);
			}
			return url;
		}

		/**
		 * @return 定位到的实际单元号
		 */
		private String locateCusterId() {
			// TODO 你的路由算法在这里
			return "001";
		}

		@Override
		public Request apply(RequestTemplate input) {
			if (input.url().indexOf("http") != 0) {
				input.target(url());
			}
			return input.request();

		}

	}
}
3. 使用自定义的Targeter实现代替缺省的实现

在XXX应用中,自己写一个XXXOpenfeignConfiguration,加入如下Bean

    @Bean
	public RouteTargeter getRouteTargeter() {
		return new RouteTargeter();
    }

这样,在运行时,我们的“RouteTargeter”就能根据服务名后缀判断到需要动态定位单元时,实现动态定位单元。

现在已经有了Spring-cloud 3.0.0M3版本了,有网友反应下载不到,大家可以在pom.xml中添加一个库就行了:

	<repositories>
		<repository>
			<id>spring-milestonesid>
			<name>Spring Milestonesname>
			<url>https://repo.spring.io/milestoneurl>
		repository>
	repositories>

你可能感兴趣的:(spring-cloud,java)