继续的深入到FeignClientFactoryBean
@Override
public Object getObject() throws Exception {
return getTarget();
}
继续的跟下去
FeignContext context = applicationContext.getBean(FeignContext.class);
Feign.Builder builder = feign(context);
可以看到,我们根据FeignContext创建了一个feign
继续的跟代码
protected Feign.Builder feign(FeignContext context) {
FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
Logger logger = loggerFactory.create(this.type);
// @formatter:off
Feign.Builder builder = get(context, Feign.Builder.class)
// required values
.logger(logger)
.encoder(get(context, Encoder.class))
.decoder(get(context, Decoder.class))
.contract(get(context, Contract.class));
// @formatter:on
configureFeign(context, builder);
return builder;
}
可以看到,里面有个方法
configureFeign(context, builder);
继续的跟进去
protected void configureFeign(FeignContext context, Feign.Builder builder) {
FeignClientProperties properties = applicationContext.getBean(FeignClientProperties.class);
if (properties != null) {
if (properties.isDefaultToProperties()) {
configureUsingConfiguration(context, builder);
configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
configureUsingProperties(properties.getConfig().get(this.name), builder);
} else {
configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
configureUsingProperties(properties.getConfig().get(this.name), builder);
configureUsingConfiguration(context, builder);
}
} else {
configureUsingConfiguration(context, builder);
}
}
然后可以看到
protected void configureUsingConfiguration(FeignContext context, Feign.Builder builder) {
Logger.Level level = getOptional(context, Logger.Level.class);
if (level != null) {
builder.logLevel(level);
}
Retryer retryer = getOptional(context, Retryer.class);
if (retryer != null) {
builder.retryer(retryer);
}
ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class);
if (errorDecoder != null) {
builder.errorDecoder(errorDecoder);
}
Request.Options options = getOptional(context, Request.Options.class);
if (options != null) {
builder.options(options);
}
Map<String, RequestInterceptor> requestInterceptors = context.getInstances(
this.name, RequestInterceptor.class);
if (requestInterceptors != null) {
builder.requestInterceptors(requestInterceptors.values());
}
if (decode404) {
builder.decode404();
}
}
Map<String, RequestInterceptor> requestInterceptors = context.getInstances(
this.name, RequestInterceptor.class);
可以在这里面看到FeignContext的getInstances方法,会返回针对特定feignclient的拦截器
public <T> Map<String, T> getInstances(String name, Class<T> type) {
AnnotationConfigApplicationContext context = getContext(name);
if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context,
type).length > 0) {
return BeanFactoryUtils.beansOfTypeIncludingAncestors(context, type);
}
return null;
}
继续的跟进去
protected AnnotationConfigApplicationContext getContext(String name) {
if (!this.contexts.containsKey(name)) {
synchronized (this.contexts) {
if (!this.contexts.containsKey(name)) {
this.contexts.put(name, createContext(name));
}
}
}
return this.contexts.get(name);
}
这里面用到了缓存,其中name就是feignClient的名字
然后继续的的跟进去
protected AnnotationConfigApplicationContext createContext(String name) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
if (this.configurations.containsKey(name)) {
for (Class<?> configuration : this.configurations.get(name)
.getConfiguration()) {
context.register(configuration);
}
}
for (Map.Entry<String, C> entry : this.configurations.entrySet()) {
if (entry.getKey().startsWith("default.")) {
for (Class<?> configuration : entry.getValue().getConfiguration()) {
context.register(configuration);
}
}
}
context.register(PropertyPlaceholderAutoConfiguration.class,
this.defaultConfigType);
context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(
this.propertySourceName,
Collections.<String, Object> singletonMap(this.propertyName, name)));
if (this.parent != null) {
// Uses Environment from parent as well as beans
context.setParent(this.parent);
}
context.setDisplayName(generateDisplayName(name));
context.refresh();
return context;
}
所有的操作都是基于属性
private Map<String, C> configurations = new ConcurrentHashMap<>();
所以我们可以在这个configurations上面进行hack的操作。
比如我们需要对xxx这个feignClient添加configuration,只需要在configurations这个属性添加 一条信息就可以了。
代码如下
@Component
public class FeignContextPostProcessor implements BeanPostProcessor {
@Autowired
private XmlProcessLabelContextHolder xmlProcessLabelContextHolder;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface FeignClientConfiguration {
String value() default "";
Class<?>[] configuration() default {};
}
class FeignConfiguration implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
// in sync case
if(xmlProcessLabelContextHolder.getXmlProcessLabelInfo().getHeaderInfo() == null){
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
template.header(AuthInfo.HEADER_X_ID_TOKEN_PLAIN_K, AuthInfo.HEADER_X_ID_TOKEN_PLAIN_V);
template.header(HttpHeaders.HOST, HttpRequestUtils.getClientHost(request));
template.header(AuthInfo.HEADER_X_ID_TOKEN_K,request.getHeader(AuthInfo.HEADER_X_ID_TOKEN_K));
// async case
}else{
template.header(AuthInfo.HEADER_X_ID_TOKEN_PLAIN_K, xmlProcessLabelContextHolder.getXmlProcessLabelInfo().getHeaderInfo().get(AuthInfo.HEADER_X_ID_TOKEN_PLAIN_K));
template.header(HttpHeaders.HOST, xmlProcessLabelContextHolder.getXmlProcessLabelInfo().getHeaderInfo().get(HttpHeaders.HOST));
template.header(AuthInfo.HEADER_X_ID_TOKEN_K,xmlProcessLabelContextHolder.getXmlProcessLabelInfo().getHeaderInfo().get(AuthInfo.HEADER_X_ID_TOKEN_K));
}
}
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof FeignContext){
FeignContext feignContextBean = (FeignContext)bean;
FeignClientConfiguration con = AnnotationUtils.findAnnotation(FeignClientDelegate.class, FeignClientConfiguration.class);
List bffSpecificationInnerLists = Lists.newArrayList();
bffSpecificationInnerLists.add(new SpecificationInner(con.value(),con.configuration()));
feignContextBean.setConfigurations(bffSpecificationInnerLists);
return feignContextBean;
}
return bean;
}
@Data
public class SpecificationInner implements NamedContextFactory.Specification {
private String name;
private Class<?>[] configuration;
public SpecificationInner(String name,Class<?>[] configuration){
this.configuration = configuration;
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public Class<?>[] getConfiguration() {
return configuration;
}
}
}
主要的思想就是在get FeignContext这个bean之后,动态的注册一些信息。
ok完!!!!
网友评论