@Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        Map<String, Object> attachments = invocation.getObjectAttachments();
        if (attachments != null) {
            Map<String, Object> newAttach = new HashMap<>(attachments.size());
            for (Map.Entry<String, Object> entry : attachments.entrySet()) {
                String key = entry.getKey();
                if (!UNLOADING_KEYS.contains(key)) {
                    newAttach.put(key, entry.getValue());
                }
            }
            attachments = newAttach;
        }

        RpcContext.getServiceContext().setInvoker(invoker).setInvocation(invocation);

        RpcContext context = RpcContext.getServerAttachment();
        //                .setAttachments(attachments)  // merged from dubbox
        if (context.getLocalAddress() == null) {
            context.setLocalAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort());
        }

        String remoteApplication = invocation.getAttachment(REMOTE_APPLICATION_KEY);
        if (StringUtils.isNotEmpty(remoteApplication)) {
            RpcContext.getServiceContext().setRemoteApplicationName(remoteApplication);
        } else {
            RpcContext.getServiceContext().setRemoteApplicationName(context.getAttachment(REMOTE_APPLICATION_KEY));
        }

        long timeout = RpcUtils.getTimeout(invocation, -1);
        if (timeout != -1) {
            // pass to next hop
            RpcContext.getServerAttachment()
                    .setObjectAttachment(
                            TIME_COUNTDOWN_KEY, TimeoutCountDown.newCountDown(timeout, TimeUnit.MILLISECONDS));
        }

        // merged from dubbox
        // we may already add some attachments into RpcContext before this filter (e.g. in rest protocol)
        if (CollectionUtils.isNotEmptyMap(attachments)) {
            if (context.getObjectAttachments().size() > 0) {
                context.getObjectAttachments().putAll(attachments);
            } else {
                context.setObjectAttachments(attachments);
            }
        }

        if (invocation instanceof RpcInvocation) {
            RpcInvocation rpcInvocation = (RpcInvocation) invocation;
            rpcInvocation.setInvoker(invoker);
        }

        try {
            context.clearAfterEachInvoke(false);
            return invoker.invoke(invocation);
        } finally {
            context.clearAfterEachInvoke(true);
            if (context.isAsyncStarted()) {
                removeContext();
            }
        }
    }
@Test
    void testWithAttachments() {
        URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1");
        Invoker<DemoService> invoker = new MyInvoker<DemoService>(url);
        Invocation invocation = new MockInvocation();
        Result result = contextFilter.invoke(invoker, invocation);
        assertNotNull(RpcContext.getServiceContext().getInvoker());
    }