springcloud2020版本使用zuul和nacos服务发
2021-10-11 本文已影响0人
夜辰啊
spirngcloud版本 2020.0.3
springcloud.alibaba 2021.1
ZuulHandlerBeanPostProcessor
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.cglib.proxy.*;
import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
import org.springframework.cloud.netflix.zuul.web.ZuulController;
import org.springframework.cloud.netflix.zuul.web.ZuulHandlerMapping;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;
@Component
@Slf4j
public class ZuulHandlerBeanPostProcessor {
/**
* 自定义拦截器
*/
@Resource
private TokenHandlerInterceptor tokenHandlerInterceptor;
/**
* The path returned by ErrorContoller.getErrorPath() with Spring Boot < 2.5 (and no longer available on Spring Boot >= 2.5).
*/
private static final String ERROR_PATH = "/error";
/**
* Constructs a new bean post-processor for Zuul.
*
* @param routeLocator the route locator.
* @param zuulController the Zuul controller.
* @param errorController the error controller.
* @return the new bean post-processor.
*/
@Bean
public ZuulPostProcessor zuulPostProcessor(@Autowired RouteLocator routeLocator, @Autowired ZuulController zuulController,
@Autowired(required = false) ErrorController errorController) {
return new ZuulPostProcessor(routeLocator, zuulController, errorController, tokenHandlerInterceptor);
}
private static final class ZuulPostProcessor implements BeanPostProcessor {
private final RouteLocator routeLocator;
private final ZuulController zuulController;
private final boolean hasErrorController;
private TokenHandlerInterceptor tokenHandlerInterceptor;
ZuulPostProcessor(RouteLocator routeLocator, ZuulController zuulController, ErrorController errorController, TokenHandlerInterceptor tokenHandlerInterceptor) {
this.routeLocator = routeLocator;
this.zuulController = zuulController;
this.hasErrorController = (errorController != null);
this.tokenHandlerInterceptor = tokenHandlerInterceptor;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (hasErrorController && (bean instanceof ZuulHandlerMapping)) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(ZuulHandlerMapping.class);
enhancer.setCallbackFilter(LookupHandlerCallbackFilter.INSTANCE); // only for lookupHandler
enhancer.setCallbacks(new Callback[]{LookupHandlerMethodInterceptor.INSTANCE, NoOp.INSTANCE});
Constructor<?> ctor = ZuulHandlerMapping.class.getConstructors()[0];
ZuulHandlerMapping zuulHandlerMapping = (ZuulHandlerMapping) enhancer.create(ctor.getParameterTypes(), new Object[]{routeLocator, zuulController});
zuulHandlerMapping.setInterceptors(tokenHandlerInterceptor);
// 生成ZuulHandlerMapping代理类后需要执行initInterceptors (如果需要使用拦截器的话)
try {
Method method = null;
for (Class<?> clazz = bean.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
try {
method = clazz.getDeclaredMethod("initInterceptors");
if (Objects.nonNull(method)){
break;
}
} catch (Exception e) {
}
}
method.setAccessible(true);
method.invoke(zuulHandlerMapping);
} catch (IllegalAccessException | InvocationTargetException e) {
log.error("invoke zuulHandlerMapping initInterceptors() error ",e);
}
return zuulHandlerMapping;
}
return bean;
}
}
private enum LookupHandlerCallbackFilter implements CallbackFilter {
INSTANCE;
@Override
public int accept(Method method) {
if ("lookupHandler".equals(method.getName())) {
return 0;
}
return 1;
}
}
private enum LookupHandlerMethodInterceptor implements MethodInterceptor {
INSTANCE;
@Override
public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if (ERROR_PATH.equals(args[0])) {
/* by entering this branch we avoid the ZuulHandlerMapping.lookupHandler method to trigger the NoSuchMethodError */
return null;
}
return methodProxy.invokeSuper(target, args);
}
}
}
RibbonCusClientConfig
@Configuration(proxyBeanMethods = false)
@Lazy
public class RibbonCusClientConfig {
@Autowired
private PropertiesFactory propertiesFactory;
@Autowired
private NacosDiscoveryClient discoveryClient;
@Value("${ribbon.client.name:client}")
private String name = "client";
@Autowired
private Environment environment;
public static final int DEFAULT_CONNECT_TIMEOUT = 1000;
/**
* Ribbon client default read timeout.
*/
public static final int DEFAULT_READ_TIMEOUT = 1000;
/**
* Ribbon client default Gzip Payload flag.
*/
public static final boolean DEFAULT_GZIP_PAYLOAD = true;
@Bean
@ConditionalOnMissingBean
public IClientConfig ribbonClientConfig() {
DefaultClientConfigImpl config = new DefaultClientConfigImpl();
config.loadProperties(this.name);
config.set(CommonClientConfigKey.ConnectTimeout, getProperty(
CommonClientConfigKey.ConnectTimeout, DEFAULT_CONNECT_TIMEOUT));
config.set(CommonClientConfigKey.ReadTimeout,
getProperty(CommonClientConfigKey.ReadTimeout, DEFAULT_READ_TIMEOUT));
config.set(CommonClientConfigKey.GZipPayload, DEFAULT_GZIP_PAYLOAD);
return config;
}
private Integer getProperty(IClientConfigKey<Integer> connectTimeout,
int defaultConnectTimeout) {
return environment.getProperty("ribbon." + connectTimeout, Integer.class,
defaultConnectTimeout);
}
@Bean
@ConditionalOnMissingBean
@SuppressWarnings("unchecked")
public ServerList<Server> ribbonServerList(IClientConfig config) {
// IClientConfig config=new DefaultClientConfigImpl();
RequestContext context = RequestContext.getCurrentContext();
String serviceId = (String) context.get(SERVICE_ID_KEY);
if (this.propertiesFactory.isSet(ServerList.class, serviceId)) {
return this.propertiesFactory.get(ServerList.class, config, serviceId);
}
NacosServerList serverList = new NacosServerList(discoveryClient, serviceId);
serverList.initWithNiwsConfig(config);
return serverList;
}
}
NacosServerList
public class NacosServerList extends AbstractServerList {
private IClientConfig clientConfig;
private DiscoveryClient discoveryClient;
public String name;
public NacosServerList(DiscoveryClient discoveryClient,String name) {
this.discoveryClient = discoveryClient;
this.name = name;
}
@Override
public List<Server> getInitialListOfServers() {
return getUpdatedListOfServers();
}
@Override
public List<Server> getUpdatedListOfServers() {
List<Server> list = Lists.newArrayList();
List<ServiceInstance> instances = discoveryClient.getInstances(name);
for (ServiceInstance instance : instances) {
list.add(new Server(instance.getScheme(), instance.getHost(), instance.getPort()));
}
return list;
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
this.clientConfig = clientConfig;
}
}
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.2.9.RELEASE</version>
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <groupId>com.netflix.servo</groupId>-->
<!-- <artifactId>servo-core</artifactId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
</dependency>
<!-- https://mvnrepository.com/artifact/com.netflix.servo/servo-core -->
<dependency>
<groupId>com.netflix.servo</groupId>
<artifactId>servo-core</artifactId>
<version>0.13.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-nacos-discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>