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>
上一篇下一篇

猜你喜欢

热点阅读