0%

直接继承feign接口

feign注册控制

在开发过程中,对内部提供服务的时候要使用feign对自己服务进行一个包装,这样导致一个接口相同的东西需要需要编写两次

然后我就直接实现了feign的接口,将@RequestMappping直接写在feign上,这样改动也相对一致。

在启动的时候导致了一个问题,Spring会将feign的接口也作为url的mapping注入到容器中,直接启动失败。

因此,为了解决这个问题需要重写url的注册的逻辑。

将是接口的并且是包含了FeignClient注解的类不去处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

/**
* feign注册控制
* 禁止feign和Controller的URL一起注册
*
* @author tianzeng
*/
@Configuration
@ConditionalOnClass({Feign.class})
@Slf4j
public class FeignRegisterConfiguration extends WebMvcAutoConfiguration.EnableWebMvcConfiguration {
public FeignRegisterConfiguration(ObjectProvider<WebMvcProperties> mvcPropertiesProvider, ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ListableBeanFactory beanFactory) {
super(mvcPropertiesProvider, mvcRegistrationsProvider, beanFactory);
}

@Override
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
return new RequestMappingHandlerMapping() {
@Override
protected boolean isHandler(Class<?> beanType) {
boolean isController = isController(beanType);
if (!isController) {
log.info("没有注册上去的URL {}", beanType.getName());
}
return super.isHandler(beanType) && isController;
}
};
}

/**
* 判断是否是货真价实的Controller
*
* @param beanType
* @return
*/
private boolean isController(Class<?> beanType) {
return beanType.getAnnotation(FeignClient.class) == null
|| !beanType.isInterface();
}

}

扩展

基于这个RequestMappingHandlerMapping能够对URL版本进行一个控制

从请求头里面指定version版本,然后在生成URL的时候通过version标识自动返回相对于的MappingHandler

核心的mapping类型CustomRequestMappingHandlerMapping

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;

/**
* 版本处理
*
* @author: tianzeng
* @date: 2018 -06-19
*/
public class CustomRequestMappingHandlerMapping extends RequestMappingHandlerMapping {

@Override
protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
VersionedResource typeAnnotation = AnnotationUtils.findAnnotation(handlerType, VersionedResource.class);
return createCondition(typeAnnotation);
}

@Override
protected RequestCondition<?> getCustomMethodCondition(Method method) {
VersionedResource methodAnnotation = AnnotationUtils.findAnnotation(method, VersionedResource.class);
return createCondition(methodAnnotation);
}

private RequestCondition<?> createCondition(VersionedResource versionMapping) {
if (versionMapping != null) {
return new VersionedResourceRequestCondition(versionMapping.media(), versionMapping.from(), versionMapping.to());
}

return null;
}

}

注解在版本上的标识

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@RequestMapping
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface VersionedResource {

String media() default "";

String from() default "";

String to() default Version.MAX_VERSION;
}

版本Version

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* 版本实例
*
* @author tianzeng
* @date 2018 -06-14
*/
public class Version implements Comparable<Version> {
public static final String MAX_VERSION = "99.99";

private final int major;
private final int minor;

/**
* Token的数据长度
*/
private static Integer TOKEN_LENGTH = 2;

public Version(String version) {
String[] tokens = version.split("\\.");

if (tokens.length != TOKEN_LENGTH) {
throw new IllegalArgumentException("Invalid version " + version + ". The version must have major and minor number.");
}

major = Integer.parseInt(tokens[0]);
minor = Integer.parseInt(tokens[1]);
}

@Override
public int compareTo(Version other) {
if (this.major > other.major) {
return 1;
} else if (this.major < other.major) {
return -1;
} else if (this.minor > other.minor) {
return 1;
} else if (this.minor < other.minor) {
return -1;
} else {
return 0;
}
}

@Override
public String toString() {
return "v" + major + "." + minor;
}
}

整体个规则处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/**
* 处理接口版本规则
*
* @author tianzeng
* @date 2018 -06-14
*/
public class VersionedResourceRequestCondition extends AbstractRequestCondition<VersionedResourceRequestCondition> {
private final Set<VersionRange> versions;
private final String acceptedMediaType;
private final String pattern = "(\\d+\\.\\d+).*";
private Logger logger = LoggerFactory.getLogger(VersionedResourceRequestCondition.class);

public VersionedResourceRequestCondition(String acceptedMediaType, String from, String to) {
this(acceptedMediaType, versionRange(from, to));
}

public VersionedResourceRequestCondition(String acceptedMediaType, Collection<VersionRange> versions) {
this.acceptedMediaType = acceptedMediaType;
this.versions = Collections.unmodifiableSet(new HashSet<>(versions));
}

private static Set<VersionRange> versionRange(String from, String to) {
HashSet<VersionRange> versionRanges = new HashSet<>();

if (StringUtils.hasText(from)) {
String toVersion = (StringUtils.hasText(to) ? to : Version.MAX_VERSION);
VersionRange versionRange = new VersionRange(from, toVersion);

versionRanges.add(versionRange);
}

return versionRanges;
}

@Override
public VersionedResourceRequestCondition combine(VersionedResourceRequestCondition other) {
logger.debug("Combining:\n{}\n{}", this, other);
Set<VersionRange> newVersions = new LinkedHashSet<>(this.versions);
newVersions.addAll(other.versions);
String newMediaType;
if (StringUtils.hasText(this.acceptedMediaType) && StringUtils.hasText(other.acceptedMediaType)
&& !this.acceptedMediaType.equals(other.acceptedMediaType)) {
throw new IllegalArgumentException("Both conditions should have the same media type. " + this.acceptedMediaType + " =!= " + other.acceptedMediaType);
} else if (StringUtils.hasText(this.acceptedMediaType)) {
newMediaType = this.acceptedMediaType;
} else {
newMediaType = other.acceptedMediaType;
}
return new VersionedResourceRequestCondition(newMediaType, newVersions);
}

@Override
public VersionedResourceRequestCondition getMatchingCondition(HttpServletRequest request) {
String accept = request.getHeader("version");
Pattern regexPattern = Pattern.compile(pattern);
Matcher matcher = regexPattern.matcher(accept);
if (versions.size() == 0) {
return this;
}
if (matcher.matches()) {
String version = matcher.group(1);
for (VersionRange versionRange : versions) {
if (versionRange.includes(version)) {
return this;
}
}
}
return null;
}

@Override
public int compareTo(VersionedResourceRequestCondition other, HttpServletRequest request) {
return 0;
}

@Override
protected Collection<?> getContent() {
return versions;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("version={");
sb.append("media=").append(acceptedMediaType).append(",");
for (VersionRange range : versions) {
sb.append(range).append(",");
}
sb.append("}");

return sb.toString();
}

@Override
protected String getToStringInfix() {
return " && ";
}
}


/**
* @author tianzeng
* @date 2018 -06-14
*/
public class VersionRange {
private Version from;
private Version to;

public VersionRange(String from, String to) {
this.from = new Version(from);
this.to = new Version(to);
}

public boolean includes(String other) {
Version otherVersion = new Version(other);

if (from.compareTo(otherVersion) <= 0 && to.compareTo(otherVersion) >= 0) {
return true;
}

return false;
}

@Override
public String toString() {
return "range[" + from + "-" + to + "]";
}

@Override
public int hashCode() {
return super.hashCode();
}

@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
}