springcloudベースのサービス階調パブリケーション(二)

14537 ワード

グレースケールリンクテスト


文書ディレクトリ

  • グレースケールリンクテスト
  • テストインタフェース実装
  • 2測定インタフェースブロック
  • を迂回する.
  • 2.1 filterまたはHandlerInterceptorエージェント
  • を作成する.
  • 2.2ブロック
  • をスキップするか否かの処理

    1テストインタフェース実装


    すべてのサービスがグレーjarにアクセスした後、リンク効果をテストするのは便利ではありません.したがって、すべてのサービスアクセス依存性の後、リンクテストインタフェース側を予め設定して、全体のリンク効果が予想されるかどうかをテストする.
    /**
     *  
     *
     * @author xie
     */
    @RestController
    @RequestMapping("/gray/test")
    public class GrayRouteTestController {
    
        private Logger logger = LoggerFactory.getLogger(GrayRouteTestController.class);
    
        @Resource
        private EurekaDiscoveryClient discoveryClient;
    
        @Resource()
        private ApplicationInfoManager applicationInfoManager;
    
        @Resource
        private RestTemplate restTemplate;
    
        /**
         * @param nodes   
         * @return
         */
        @RequestMapping(value = "linksTest", method = RequestMethod.POST)
        public TestResult nodeTest(@RequestBody List nodes) {
            InstanceInfo startNodeServer = applicationInfoManager.getInfo();
            String currentServiceId = startNodeServer.getAppName().toLowerCase();
            if (!nodes.get(0).equals(currentServiceId)) {
                nodes.add(0,currentServiceId);
            }
            // 
            RequestNode requestNode = convert2RequestNode(nodes);
            List resultNodes = internalNodeTest(requestNode);
            ResultNode startNode = new ResultNode();
            startNode.setServiceId(startNodeServer.getAppName().toLowerCase());
            startNode.setHost(startNodeServer.getHostName());
            startNode.setPort(startNodeServer.getPort());
            String serverStatus = startNodeServer.getMetadata().get(Constant.INSTANCE_STATUS);
            startNode.setInstanceStatus(serverStatus);
            resultNodes.add(startNode);
            Comparator tComparator = Collections.reverseOrder();
            resultNodes.sort(tComparator);
            TestResult testResult = new TestResult();
            ResultNode resultNode = resultNodes.get(resultNodes.size() - 1);
            testResult.setSuccess(resultNode.isSuccess());
            testResult.setMessage(resultNode.getMessage());
            testResult.setNodeList(resultNodes);
            testResult.setTotal(nodes.size());
            testResult.setRoute2Gray(GrayUtils.isGray());
            testResult.setFailureCount(resultNode.isSuccess() ? 0 : nodes.size() - (resultNodes.size() - 1));
            return testResult;
    
        }
    
    
        @RequestMapping(value = "internalNodeTest", method = RequestMethod.POST)
        public List internalNodeTest(@RequestBody RequestNode requestNode) {
            // 
            RequestNode next = requestNode.getNext();
            if (next == null) {
                logger.info("request is end");
                List list = new ArrayList<>();
                return list;
            }
    
            GrayUtils.currentSelectServer.set(new Server(next.getServiceId()));
            try {
                ResultNode nextNodeServer = new ResultNode();
                nextNodeServer.setIndex(next.getIndex());
                nextNodeServer.setServiceId(next.getServiceId());
                List resultNodes = new ArrayList<>();
                // url
                String serverUrl = getServerUrl(next.getServiceId());
                if (StringUtils.isEmpty(serverUrl)) {
                    nextNodeServer.setMessage(" " + next.getServiceId() + " ");
                    nextNodeServer.setSuccess(false);
                    resultNodes.add(nextNodeServer);
                    return resultNodes;
                }
                HttpHeaders requestHeaders = new HttpHeaders();
                // 
                requestHeaders.add(Constant.ROUTE_TO_GRAY, String.valueOf(GrayUtils.isGray()));
                HttpEntity requestEntity = new HttpEntity<>(next, requestHeaders);
    
                try {
                    ResponseEntity response = restTemplate.postForEntity(serverUrl, requestEntity, String.class);
                    // , 
                    resultNodes = JSON.parseArray(response.getBody(), ResultNode.class);
                    Server testServer = GrayUtils.getTestServer();
                    nextNodeServer.setHost(testServer.getHost());
                    nextNodeServer.setPort(testServer.getPort());
                    if (testServer instanceof DiscoveryEnabledServer) {
                        DiscoveryEnabledServer enabledServer = (DiscoveryEnabledServer) testServer;
                        InstanceInfo instanceInfo = enabledServer.getInstanceInfo();
                        String serverStatus = instanceInfo.getMetadata().get(Constant.INSTANCE_STATUS);
                        nextNodeServer.setInstanceStatus(serverStatus);
                        nextNodeServer.setIndex(next.getIndex());
                    }
                } catch (Exception ex) {
                    // 
                    logger.warn("links test failure:{}", ex.getMessage());
                    nextNodeServer.setMessage("[route_to_gray:" + GrayUtils.isGray() + "]" + ex.getMessage() + serverUrl);
                    nextNodeServer.setSuccess(false);
                    resultNodes.add(nextNodeServer);
                }
    
                resultNodes.add(nextNodeServer);
                return resultNodes;
            } finally {
                GrayUtils.removeTestServer();
            }
        }
    
    
        private RequestNode convert2RequestNode(List nodes) {
            RequestNode nextNode = null;
            for (int i = nodes.size() - 1; i >= 0; i--) {
                if (nextNode == null) {
                    nextNode = new RequestNode(nodes.get(i), i);
                } else {
                    RequestNode tNextNode = new RequestNode(nodes.get(i), i);
                    tNextNode.setNext(nextNode);
                    nextNode = tNextNode;
                }
            }
            return nextNode;
        }
    
        /**
         *  url
         * @param nextNodeId
         * @return
         */
        private String getServerUrl(String nextNodeId) {
            List instances = discoveryClient.getInstances(nextNodeId);
            if (instances.isEmpty()) {
                return null;
            }
            ServiceInstance serviceInstance = instances.get(0);
            String contextPath = serviceInstance.getMetadata().get(CONTEXT_PATH);
            String temContextPath = contextPath == null ? "/" : contextPath;
            String url = "http://" + nextNodeId.toLowerCase() + temContextPath + "/gray/test/internalNodeTest";
            return url;
        }
    }
    

    2測定インタフェースを迂回してブロックする


    通常、サービスインタフェースへのアクセスにはログインが必要であり、ログインしていないインタフェースはブロック結果が実際にあり、通常、アクセスブロックの実装はfilter実装するか、HandlerInterceptor(mvcプロジェクト)でテストインタフェースがブロックされないようにするには、これらのブロックを迂回する方法が必要である.ビジネスコードを変更しない場合、ブロックを迂回して、エージェントはよく使われる方法です.結果springエージェントの特徴は、簡単に実現できます.

    2.1 filterまたはHandlerInterceptorエージェントの作成

    public class InterceptorBeanProcessor implements BeanPostProcessor {
    
        protected final Logger logger = LoggerFactory.getLogger(getClass());
    
        private static final Map baseTypes = new HashMap<>();
    
        private Enhancer enhancer = new Enhancer();
    
        private boolean filterClassExist;
    
        private boolean interceptorClassExist;
    
        private GrayProperties grayProperties;
    
        public InterceptorBeanProcessor(GrayProperties grayProperties){
            this.grayProperties = grayProperties;
        }
    
        static {
            baseTypes.put("int", 0);
            baseTypes.put("short", 0);
            baseTypes.put("long", 0L);
            baseTypes.put("double", 0d);
            baseTypes.put("float", 0f);
            baseTypes.put("boolean", false);
            baseTypes.put("char", (char) 0);
            baseTypes.put("byte", Byte.valueOf((byte) 0));
        }
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName)
                throws BeansException {
            // filter  
            Object filterProxy = createFilterProxy(bean);
            if(bean.equals(filterProxy)){
                // Interceptor  
               return createInterceptorProxy(bean);
            }else {
              return filterProxy;
            }
        }
        
        private Object createFilterProxy(Object bean){
            if(!filterClassExist()) {
                return bean;
            }
            if (bean instanceof Filter) {
                Class> clazz = bean.getClass();
                try {
                    return cglibProxy(clazz, new FilterMethodInterceptor(bean,grayProperties));
                } catch (Throwable e) {
                    logger.warn("create {} filter proxy failure :{}", clazz.getName(), e.getMessage());
                    return bean;
                }
            }
            return bean;
        }
        private Object createInterceptorProxy(Object bean){
            if(!interceptorClassExist()) {
                return bean;
            }
            if (bean instanceof HandlerInterceptor) {
                Class> clazz = bean.getClass();
                try {
                    return cglibProxy(clazz, new HandlerInterceptorMethodInterceptor(bean,grayProperties));
                } catch (Throwable e) {
                    logger.warn("create {} interceptor proxy failure:{}", clazz.getName(), e.getMessage());
                    return bean;
                }
            }
            return bean;
        }
    
        /**
         *  servlet ,filter  
         * @return
         */
        private boolean filterClassExist() {
            if(filterClassExist){
                return true;
            }
            try {
                Class clzz =  Filter.class;
                filterClassExist = true;
            }catch (Throwable e){
                filterClassExist = false;
            }
            return false;
        }
    
        private boolean interceptorClassExist() {
            if(interceptorClassExist){
                return true;
            }
            try {
                Class clzz =  HandlerInterceptor.class;
                interceptorClassExist = true;
            }catch ( Throwable e){
                interceptorClassExist = false;
            }
            return false;
        }
    
        /**
         * final  (cglib , final )
         *
         * @param clazz
         * @return
         */
        private Object cglibProxy(Class clazz, Callback callback) {
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(callback);
            Constructor>[] constructors = clazz.getConstructors();
            Parameter[] parameters = constructors[0].getParameters();
            Object[] arguments = new Object[parameters.length];
            Class[] paramsTypes = new Class[parameters.length];
            for (int i = 0; i < arguments.length; i++) {
                Class> type = parameters[i].getType();
                arguments[i] = baseTypes.get(type.getSimpleName().toLowerCase());
                paramsTypes[i] = type;
            }
            return enhancer.create(paramsTypes, arguments);
        }
    
    }
    
    

    2.2ブロックをスキップするかどうかの処理

    public  class InterceptorAdapter implements Callback {
    
        protected final Logger logger = LoggerFactory.getLogger(getClass());
    
        private final String FILTER_METHOD="doFilter";
    
        private final String INTERCEPTOR_METHOD="preHandle";
    
        PathMatcher pathMatcher = new AntPathMatcher();
    
        private Object target;
    
        private GrayProperties grayProperties;
    
        public InterceptorAdapter(Object target, GrayProperties grayProperties) {
            this.target = target;
            this.grayProperties = grayProperties;
        }
    
    
    
        /**
         *  , filter
         * @param proxy
         * @param method
         * @param args
         * @return
         * @throws InvocationTargetException
         * @throws IllegalAccessException
         * @throws IOException
         * @throws ServletException
         */
        protected Object doFilter(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException, IOException, ServletException {
            // doFilter  
            if (FILTER_METHOD.equals(method.getName())) {
                HttpServletRequest servletRequest = (HttpServletRequest) args[0];
                ServletResponse servletResponse = (ServletResponse) args[1];
                FilterChain filterChain = (FilterChain) args[2];
                String servletPath = servletRequest.getServletPath();
                // , filter
                if (skipCurrentPath(servletPath)) {
                    logger.debug("[{}] is gray test path ,skip filter of {}",servletPath,target.getClass().getSimpleName());
                    filterChain.doFilter(servletRequest, servletResponse);
                } else {
                    method.invoke(target, args);
                }
            } else {
                method.setAccessible(true);
                return method.invoke(target, args);
            }
            return null;
        }
    
    
        private boolean skipCurrentPath(String servletPath){
    
            Set skipPaths = grayProperties.getSkipPaths();
            for(String pattern :skipPaths){
                if(pathMatcher.match(pattern,servletPath)){
                    return true;
                }
            }
            return false;
        }
    
        /**
         *  , interceptor
         * @param proxy
         * @param method
         * @param args
         * @return
         * @throws Exception
         */
        protected Object preHandle(Object proxy, Method method, Object[] args)
                throws Exception {
            // preHandle  
            if (INTERCEPTOR_METHOD.equals(method.getName())) {
                HttpServletRequest servletRequest = (HttpServletRequest) args[0];
                String servletPath = servletRequest.getServletPath();
                // , 
                if (skipCurrentPath(servletPath)) {
                    logger.debug("[{}] is gray test path ,skip interceptor of {}", servletPath, target.getClass().getSimpleName());
                    return true;
                } else {
                    return method.invoke(target, args);
                }
            } else {
                method.setAccessible(true);
                return method.invoke(target, args);
            }
        }
    
        /**
         *  , 
         * @param proxy
         * @param method
         * @param args
         * @param methodProxy
         * @return
         * @throws Throwable
         */
        @Override
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            return doFilter(proxy,method,args);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return doFilter(proxy,method,args);
        }
    }