You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by wu...@apache.org on 2020/12/22 08:16:35 UTC

[servicecomb-java-chassis] branch master updated: [SCB-2169] optimize filter declare and chain config

This is an automated email from the ASF dual-hosted git repository.

wujimin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git


The following commit(s) were added to refs/heads/master by this push:
     new 76fe676  [SCB-2169] optimize filter declare and chain config
76fe676 is described below

commit 76fe676dad6d0aa12d77019246d0ea9c19eeb878
Author: wujimin <wu...@huawei.com>
AuthorDate: Tue Dec 22 10:03:16 2020 +0800

    [SCB-2169] optimize filter declare and chain config
---
 .../rest/filter/inner/RestServerCodecFilter.java   |  18 ++-
 .../src/test/resources/microservice.yaml           |   7 +-
 .../org/apache/servicecomb/core/SCBEngine.java     |   5 +-
 .../core/bootstrap/SCBEngineForTest.java           |  14 +-
 .../core/definition/ServiceRegistryListener.java   |   2 +-
 .../servicecomb/core/filter/ConsumerFilter.java    |  16 +-
 .../org/apache/servicecomb/core/filter/Filter.java |  24 ++-
 .../core/filter/FilterChainsManager.java           | 123 +++++-----------
 .../servicecomb/core/filter/FilterManager.java     | 162 ---------------------
 .../apache/servicecomb/core/filter/FilterMeta.java |  50 -------
 .../apache/servicecomb/core/filter/FilterNode.java |   2 +-
 .../{FilterProvider.java => InternalFilter.java}   |   5 +-
 .../core/filter/InvocationFilterChains.java        | 113 ++++++++++++++
 .../servicecomb/core/filter/ProducerFilter.java    |  19 ++-
 .../filter/config/AbstractFilterChainsConfig.java  |  24 +--
 .../core/filter/config/FilterChainsConfig.java     |  95 +++++++-----
 .../config/InvocationFilterChainsConfig.java       |  69 +++++++++
 ...ilterConfig.java => TransportChainsConfig.java} |  14 +-
 .../core/filter/config/TransportFiltersConfig.java |  54 -------
 ...DefaultFilterProvider.java => EmptyFilter.java} |  28 ++--
 .../core/filter/impl/ParameterValidatorFilter.java |  25 ++--
 .../core/filter/impl/ProducerOperationFilter.java  |  22 +--
 .../core/filter/impl/ScheduleFilter.java           |  20 ++-
 .../core/filter/impl/SimpleLoadBalanceFilter.java  | 110 ++++++++------
 .../core/filter/impl/TransportFilters.java         |  22 ++-
 core/src/main/resources/microservice.yaml          |  19 ++-
 .../core/filter/FilterChainsManagerTest.java       | 103 -------------
 .../servicecomb/core/filter/SimpleRetryFilter.java |  11 +-
 .../filter/impl/ParameterValidatorFilterTest.java  |   2 +-
 .../demo/pojo/client/CodeFirstPojoClient.java      |  20 +--
 .../src/test/resources/microservice.yaml           |  22 +--
 .../src/test/resources/microservice.yaml           |  22 +--
 .../tracing/zipkin/ZipkinTracingFilter.java        |  20 ++-
 .../src/test/resources/microservice.yaml           |  22 +--
 .../src/test/resources/microservice.yaml           |   2 +-
 .../src/test/resources/microservice.yaml           |  22 +--
 .../src/test/resources/microservice.yaml           |  22 +--
 .../transport/highway/HighwayClientFilter.java     |  27 +++-
 .../highway/HighwayServerCodecFilter.java          |  19 ++-
 .../src/main}/resources/microservice.yaml          |  24 +--
 .../rest/client/RestClientCodecFilter.java         |  20 ++-
 .../rest/client/RestClientFilterProvider.java      |  35 -----
 .../rest/client/RestClientSenderFilter.java        |  20 ++-
 43 files changed, 655 insertions(+), 820 deletions(-)

diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilter.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilter.java
index bcf30a5..3dd5557 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilter.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilter.java
@@ -21,12 +21,12 @@ import static com.google.common.net.HttpHeaders.CONTENT_LENGTH;
 import static com.google.common.net.HttpHeaders.TRANSFER_ENCODING;
 import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
 import static org.apache.servicecomb.core.exception.Exceptions.exceptionToResponse;
-import static org.apache.servicecomb.swagger.invocation.InvocationType.PRODUCER;
 
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.CompletableFuture;
 
+import javax.annotation.Nonnull;
 import javax.servlet.http.Part;
 
 import org.apache.servicecomb.common.rest.HttpTransportContext;
@@ -36,20 +36,28 @@ import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor;
 import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.core.definition.OperationMeta;
-import org.apache.servicecomb.core.filter.Filter;
-import org.apache.servicecomb.core.filter.FilterMeta;
 import org.apache.servicecomb.core.filter.FilterNode;
+import org.apache.servicecomb.core.filter.ProducerFilter;
 import org.apache.servicecomb.foundation.common.utils.AsyncUtils;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
 import org.apache.servicecomb.foundation.vertx.stream.BufferOutputStream;
 import org.apache.servicecomb.swagger.invocation.Response;
+import org.springframework.stereotype.Component;
 
 import io.netty.buffer.Unpooled;
 import io.vertx.core.MultiMap;
 
-@FilterMeta(name = "rest-server-codec", invocationType = PRODUCER)
-public class RestServerCodecFilter implements Filter {
+@Component
+public class RestServerCodecFilter implements ProducerFilter {
+  public static final String NAME = "rest-server-codec";
+
+  @Nonnull
+  @Override
+  public String getName() {
+    return NAME;
+  }
+
   @Override
   public CompletableFuture<Response> onFilter(Invocation invocation, FilterNode nextNode) {
     return CompletableFuture.completedFuture(invocation)
diff --git a/common/common-rest/src/test/resources/microservice.yaml b/common/common-rest/src/test/resources/microservice.yaml
index b47bdef..5f3131b 100644
--- a/common/common-rest/src/test/resources/microservice.yaml
+++ b/common/common-rest/src/test/resources/microservice.yaml
@@ -32,4 +32,9 @@ servicecomb:
     #Provider: 
       #server: test
       #server.wrapParam: test
-        
+  filter-chains:
+    consumer:
+      default: empty
+    producer:
+      default: empty
+
diff --git a/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java b/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java
index 44a912e..39640f2 100644
--- a/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java
+++ b/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java
@@ -74,7 +74,6 @@ import com.google.common.eventbus.EventBus;
 import com.google.common.eventbus.Subscribe;
 import com.netflix.config.DynamicPropertyFactory;
 
-// TODO: should not depend on spring, that will make integration more flexible
 public class SCBEngine {
   private static final Logger LOGGER = LoggerFactory.getLogger(SCBEngine.class);
 
@@ -360,7 +359,7 @@ public class SCBEngine {
     triggerEvent(EventType.AFTER_HANDLER);
 
     triggerEvent(EventType.BEFORE_FILTER);
-    filterChainsManager.init(this);
+    filterChainsManager.init();
     triggerEvent(EventType.AFTER_FILTER);
 
     createProducerMicroserviceMeta();
@@ -393,7 +392,7 @@ public class SCBEngine {
 
     producerMicroserviceMeta = new MicroserviceMeta(this, microserviceName, false);
     producerMicroserviceMeta.setHandlerChain(producerHandlerManager.getOrCreate(microserviceName));
-    producerMicroserviceMeta.setFilterChain(filterChainsManager.createProducerFilterChain(microserviceName));
+    producerMicroserviceMeta.setFilterChain(filterChainsManager.findProducerChain(microserviceName));
     producerMicroserviceMeta.setMicroserviceVersionsMeta(new MicroserviceVersionsMeta(this, microserviceName));
   }
 
diff --git a/core/src/main/java/org/apache/servicecomb/core/bootstrap/SCBEngineForTest.java b/core/src/main/java/org/apache/servicecomb/core/bootstrap/SCBEngineForTest.java
index 2a55597..61034a5 100644
--- a/core/src/main/java/org/apache/servicecomb/core/bootstrap/SCBEngineForTest.java
+++ b/core/src/main/java/org/apache/servicecomb/core/bootstrap/SCBEngineForTest.java
@@ -19,11 +19,14 @@ package org.apache.servicecomb.core.bootstrap;
 
 import static org.apache.servicecomb.core.executor.ExecutorManager.EXECUTOR_GROUP_THREADPOOL;
 
+import java.util.Arrays;
+import java.util.List;
+
 import org.apache.servicecomb.core.SCBEngine;
 import org.apache.servicecomb.core.executor.GroupExecutor;
+import org.apache.servicecomb.core.filter.Filter;
 import org.apache.servicecomb.core.filter.FilterChainsManager;
-import org.apache.servicecomb.core.filter.FilterManager;
-import org.apache.servicecomb.core.filter.config.TransportFiltersConfig;
+import org.apache.servicecomb.core.filter.impl.EmptyFilter;
 import org.apache.servicecomb.foundation.common.event.EventManager;
 import org.apache.servicecomb.foundation.common.event.SimpleEventBus;
 import org.apache.servicecomb.foundation.common.utils.ReflectUtils;
@@ -34,9 +37,12 @@ import org.apache.servicecomb.foundation.common.utils.ReflectUtils;
 public class SCBEngineForTest extends SCBEngine {
   public SCBEngineForTest() {
     getExecutorManager().registerExecutor(EXECUTOR_GROUP_THREADPOOL, new GroupExecutor().init());
+
+    List<Filter> filters = Arrays.asList(
+        new EmptyFilter()
+    );
     setFilterChainsManager(new FilterChainsManager()
-        .setTransportFiltersConfig(new TransportFiltersConfig())
-        .setFilterManager(new FilterManager()));
+        .addFilters(filters));
   }
 
   @Override
diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/ServiceRegistryListener.java b/core/src/main/java/org/apache/servicecomb/core/definition/ServiceRegistryListener.java
index 7f0599f..61bf36a 100644
--- a/core/src/main/java/org/apache/servicecomb/core/definition/ServiceRegistryListener.java
+++ b/core/src/main/java/org/apache/servicecomb/core/definition/ServiceRegistryListener.java
@@ -76,7 +76,7 @@ public class ServiceRegistryListener {
     String microserviceName = microserviceVersion.getMicroserviceName();
     MicroserviceMeta microserviceMeta = new MicroserviceMeta(scbEngine, microserviceName, true);
     microserviceMeta.setHandlerChain(scbEngine.getConsumerHandlerManager().getOrCreate(microserviceName));
-    microserviceMeta.setFilterChain(scbEngine.getFilterChainsManager().createConsumerFilterChain(microserviceName));
+    microserviceMeta.setFilterChain(scbEngine.getFilterChainsManager().findConsumerChain(microserviceName));
 
     MicroserviceVersions microserviceVersions = microserviceVersion.getMicroserviceVersions();
     microserviceMeta.setMicroserviceVersionsMeta(getMicroserviceVersionsMeta(microserviceVersions));
diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinFilterProvider.java b/core/src/main/java/org/apache/servicecomb/core/filter/ConsumerFilter.java
similarity index 70%
rename from handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinFilterProvider.java
rename to core/src/main/java/org/apache/servicecomb/core/filter/ConsumerFilter.java
index 7e8d6c5..2ede1f0 100644
--- a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinFilterProvider.java
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/ConsumerFilter.java
@@ -14,17 +14,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.servicecomb.tracing.zipkin;
+package org.apache.servicecomb.core.filter;
 
-import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
-import org.apache.servicecomb.core.filter.Filter;
-import org.apache.servicecomb.core.filter.FilterProvider;
+import javax.annotation.Nonnull;
 
-public class ZipkinFilterProvider implements FilterProvider {
+import org.apache.servicecomb.swagger.invocation.InvocationType;
+
+public interface ConsumerFilter extends Filter {
+  @Nonnull
   @Override
-  public List<Class<? extends Filter>> getFilters() {
-    return Arrays.asList(ZipkinTracingFilter.class);
+  default List<InvocationType> getInvocationTypes() {
+    return Collections.singletonList(InvocationType.CONSUMER);
   }
 }
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/Filter.java b/core/src/main/java/org/apache/servicecomb/core/filter/Filter.java
index da6367f..6ea3631 100644
--- a/core/src/main/java/org/apache/servicecomb/core/filter/Filter.java
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/Filter.java
@@ -16,11 +16,15 @@
  */
 package org.apache.servicecomb.core.filter;
 
+import java.util.Arrays;
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
 
+import javax.annotation.Nonnull;
+
 import org.apache.servicecomb.core.Invocation;
-import org.apache.servicecomb.core.SCBEngine;
 import org.apache.servicecomb.core.provider.consumer.InvokerUtils;
+import org.apache.servicecomb.swagger.invocation.InvocationType;
 import org.apache.servicecomb.swagger.invocation.Response;
 
 /**
@@ -52,16 +56,26 @@ import org.apache.servicecomb.swagger.invocation.Response;
  * </pre>
  */
 public interface Filter {
-  default boolean enabled() {
+  default boolean isEnabled() {
     return true;
   }
 
-  default void init(SCBEngine engine) {
+  default boolean isInEventLoop() {
+    return InvokerUtils.isInEventLoop();
+  }
 
+  @Nonnull
+  default String getName() {
+    throw new IllegalStateException("must provide filter name.");
   }
 
-  default boolean isInEventLoop() {
-    return InvokerUtils.isInEventLoop();
+  /**
+   *
+   * @return can be used for the specific invocation type
+   */
+  @Nonnull
+  default List<InvocationType> getInvocationTypes() {
+    return Arrays.asList(InvocationType.CONSUMER, InvocationType.PRODUCER);
   }
 
   /**
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/FilterChainsManager.java b/core/src/main/java/org/apache/servicecomb/core/filter/FilterChainsManager.java
index 125d1f7..962e371 100644
--- a/core/src/main/java/org/apache/servicecomb/core/filter/FilterChainsManager.java
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/FilterChainsManager.java
@@ -18,132 +18,87 @@ package org.apache.servicecomb.core.filter;
 
 import static org.apache.servicecomb.foundation.common.utils.StringBuilderUtils.appendLine;
 import static org.apache.servicecomb.foundation.common.utils.StringBuilderUtils.deleteLast;
-import static org.apache.servicecomb.swagger.invocation.InvocationType.CONSUMER;
-import static org.apache.servicecomb.swagger.invocation.InvocationType.PRODUCER;
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map.Entry;
+import java.util.stream.Collectors;
 
-import org.apache.servicecomb.core.SCBEngine;
 import org.apache.servicecomb.core.filter.config.FilterChainsConfig;
-import org.apache.servicecomb.core.filter.config.TransportFiltersConfig;
+import org.apache.servicecomb.swagger.invocation.InvocationType;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
 @Component
 public class FilterChainsManager {
-  private TransportFiltersConfig transportFiltersConfig;
+  private final FilterChainsConfig chainsConfig = new FilterChainsConfig();
 
-  private FilterManager filterManager;
+  private final InvocationFilterChains consumerChains = new InvocationFilterChains();
 
-  private FilterChainsConfig consumerChainsConfig;
-
-  private FilterChainsConfig producerChainsConfig;
-
-  private boolean enabled;
+  private final InvocationFilterChains producerChains = new InvocationFilterChains();
 
   @Autowired
-  public FilterChainsManager setTransportFiltersConfig(TransportFiltersConfig transportFiltersConfig) {
-    this.transportFiltersConfig = transportFiltersConfig;
-    return this;
-  }
-
-  @Value("${servicecomb.filter-chains.enabled:false}")
-  public FilterChainsManager setEnabled(boolean enabled) {
-    this.enabled = enabled;
-    return this;
-  }
-
-  public FilterManager getFilterManager() {
-    return filterManager;
-  }
+  public FilterChainsManager addFilters(List<Filter> filters) {
+    for (Filter filter : filters) {
+      if (filter.getInvocationTypes().contains(InvocationType.CONSUMER)) {
+        consumerChains.addFilter(filter);
+      }
+
+      if (filter.getInvocationTypes().contains(InvocationType.PRODUCER)) {
+        producerChains.addFilter(filter);
+      }
+    }
 
-  @Autowired
-  public FilterChainsManager setFilterManager(FilterManager filterManager) {
-    this.filterManager = filterManager;
     return this;
   }
 
-  public FilterChainsManager init(SCBEngine engine) {
-    transportFiltersConfig.load();
-    filterManager.init(engine);
+  public FilterChainsManager init() {
+    chainsConfig.load();
 
-    consumerChainsConfig = new FilterChainsConfig(transportFiltersConfig, CONSUMER);
-    producerChainsConfig = new FilterChainsConfig(transportFiltersConfig, PRODUCER);
+    consumerChains.resolve(chainsConfig.getResolver(), chainsConfig.getConsumer());
+    producerChains.resolve(chainsConfig.getResolver(), chainsConfig.getProducer());
 
     return this;
   }
 
   public boolean isEnabled() {
-    return enabled;
-  }
-
-  public FilterChainsManager addProviders(FilterProvider... providers) {
-    return addProviders(Arrays.asList(providers));
-  }
-
-  public FilterChainsManager addProviders(Collection<FilterProvider> providers) {
-    filterManager.addProviders(providers);
-    return this;
-  }
-
-  public FilterNode createConsumerFilterChain(String microservice) {
-    return createFilterNode(consumerChainsConfig, microservice);
-  }
-
-  public FilterNode createProducerFilterChain(String microservice) {
-    return createFilterNode(producerChainsConfig, microservice);
+    return chainsConfig.isEnabled();
   }
 
-  public List<Filter> createConsumerFilters(String microservice) {
-    return createFilters(consumerChainsConfig, microservice);
+  public FilterNode findConsumerChain(String microserviceName) {
+    return consumerChains.findChain(microserviceName);
   }
 
-  public List<Filter> createProducerFilters(String microservice) {
-    return createFilters(producerChainsConfig, microservice);
+  public FilterNode findProducerChain(String microserviceName) {
+    return producerChains.findChain(microserviceName);
   }
 
   public String collectResolvedChains() {
     StringBuilder sb = new StringBuilder();
 
     appendLine(sb, "consumer: ");
-    appendLine(sb, "  filters: %s", filterManager.getConsumerFilters());
-    collectChainsByInvocationType(sb, consumerChainsConfig);
+    appendLine(sb, "  filters: %s", collectFilterNames(consumerChains));
+    collectChainsByInvocationType(sb, consumerChains);
 
     appendLine(sb, "producer: ");
-    appendLine(sb, "  filters: %s", filterManager.getProducerFilters());
-    collectChainsByInvocationType(sb, producerChainsConfig);
+    appendLine(sb, "  filters: %s", collectFilterNames(producerChains));
+    collectChainsByInvocationType(sb, producerChains);
 
     return deleteLast(sb, 1).toString();
   }
 
-  private void collectChainsByInvocationType(StringBuilder sb, FilterChainsConfig chainsConfig) {
-    appendLine(sb, "  chains:");
-    appendLine(sb, "    default: %s", chainsConfig.getDefaultChain());
-    for (Entry<String, List<Object>> entry : chainsConfig.getMicroserviceChains().entrySet()) {
-      appendLine(sb, "    %s: %s", entry.getKey(), entry.getValue());
-    }
+  public List<String> collectFilterNames(InvocationFilterChains chains) {
+    return chains.getFilters().stream()
+        .filter(filter -> !(filter instanceof InternalFilter))
+        .map(Filter::getName)
+        .collect(Collectors.toList());
   }
 
-  private FilterNode createFilterNode(FilterChainsConfig chainsConfig, String microservice) {
-    if (!enabled) {
-      return FilterNode.EMPTY;
-    }
-
-    List<Filter> filters = createFilters(chainsConfig, microservice);
-    return FilterNode.buildChain(filters);
-  }
-
-  private List<Filter> createFilters(FilterChainsConfig chainsConfig, String microservice) {
-    if (!enabled) {
-      return Collections.emptyList();
+  private void collectChainsByInvocationType(StringBuilder sb, InvocationFilterChains chains) {
+    appendLine(sb, "  chains:");
+    appendLine(sb, "    framework: %s", chains.getResolvedFrameworkConfig());
+    appendLine(sb, "    default  : %s", chains.getResolvedDefaultConfig());
+    for (Entry<String, List<Object>> entry : chains.getResolvedMicroserviceConfig().entrySet()) {
+      appendLine(sb, "    %s: %s", entry.getKey(), entry.getValue());
     }
-
-    List<Object> chain = chainsConfig.findChain(microservice);
-    return filterManager.createFilters(chain);
   }
 }
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/FilterManager.java b/core/src/main/java/org/apache/servicecomb/core/filter/FilterManager.java
deleted file mode 100644
index ce41907..0000000
--- a/core/src/main/java/org/apache/servicecomb/core/filter/FilterManager.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.servicecomb.core.filter;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.stream.Collectors;
-
-import org.apache.servicecomb.core.SCBEngine;
-import org.apache.servicecomb.core.filter.config.TransportFilterConfig;
-import org.apache.servicecomb.core.filter.impl.TransportFilters;
-import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
-import org.apache.servicecomb.swagger.invocation.InvocationType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-@Component
-public class FilterManager {
-  private static final Logger LOGGER = LoggerFactory.getLogger(FilterManager.class);
-
-  interface Factory {
-    Filter create();
-  }
-
-  private SCBEngine engine;
-
-  private final List<FilterProvider> providers = new ArrayList<>(
-      SPIServiceUtils.getOrLoadSortedService(FilterProvider.class));
-
-  private final Map<String, Factory> factoryMap = new HashMap<>();
-
-  private final List<String> consumerFilters = new ArrayList<>();
-
-  private final List<String> producerFilters = new ArrayList<>();
-
-  @Autowired(required = false)
-  public void addProviders(Collection<FilterProvider> providers) {
-    this.providers.addAll(providers);
-  }
-
-  public List<String> getConsumerFilters() {
-    return consumerFilters;
-  }
-
-  public List<String> getProducerFilters() {
-    return producerFilters;
-  }
-
-  public void init(SCBEngine engine) {
-    this.engine = engine;
-    List<Class<? extends Filter>> filterClasses = providers.stream()
-        .flatMap(provider -> provider.getFilters().stream())
-        .collect(Collectors.toList());
-
-    for (Class<? extends Filter> filterClass : filterClasses) {
-      FilterMeta meta = filterClass.getAnnotation(FilterMeta.class);
-      Factory factory = buildFactory(filterClass, meta);
-
-      if (factoryMap.put(meta.name(), factory) != null) {
-        throw new IllegalStateException(
-            String.format("duplicated filter, name=%s, class=%s", meta.name(), filterClass.getName()));
-      }
-
-      if (Arrays.binarySearch(meta.invocationType(), InvocationType.CONSUMER) >= 0) {
-        consumerFilters.add(meta.name());
-      }
-      if (Arrays.binarySearch(meta.invocationType(), InvocationType.PRODUCER) >= 0) {
-        producerFilters.add(meta.name());
-      }
-    }
-  }
-
-  public List<Filter> createFilters(List<Object> chain) {
-    return chain.stream()
-        .map(filterConfig -> {
-          Filter filter = createFilter(filterConfig);
-          filter.init(engine);
-          return filter;
-        })
-        .collect(Collectors.toList());
-  }
-
-  private Filter createFilter(Object filterConfig) {
-    if (filterConfig instanceof String) {
-      return createFilterByName((String) filterConfig);
-    }
-
-    if (filterConfig instanceof TransportFilterConfig) {
-      return createTransportFilter((TransportFilterConfig) filterConfig);
-    }
-
-    throw new IllegalStateException("not support create filter by " + filterConfig);
-  }
-
-  private Filter createTransportFilter(TransportFilterConfig config) {
-    TransportFilters transportFilters = new TransportFilters();
-    for (Entry<String, List<Object>> entry : config.getFiltersByTransport().entrySet()) {
-      List<Filter> filters = createFilters(entry.getValue());
-      transportFilters.getChainByTransport().put(entry.getKey(), FilterNode.buildChain(filters));
-    }
-    return transportFilters;
-  }
-
-  private Filter createFilterByName(String filterName) {
-    Factory factory = factoryMap.get(filterName);
-    if (factory != null) {
-      return factory.create();
-    }
-
-    throw new IllegalStateException("filter not exist, name=" + filterName);
-  }
-
-  private Factory buildFactory(Class<? extends Filter> filterClass, FilterMeta meta) {
-    if (meta.shareable()) {
-      Filter filter = createFilter(filterClass);
-      return () -> filter;
-    }
-
-    return () -> createFilter(filterClass);
-  }
-
-  private Filter createFilter(Class<? extends Filter> filterClass) {
-    try {
-      Filter filter = filterClass.newInstance();
-      injectSpringBean(filter);
-      filter.init(engine);
-      return filter;
-    } catch (Exception e) {
-      throw new IllegalStateException("failed to create filter.", e);
-    }
-  }
-
-  private void injectSpringBean(Filter filter) {
-    if (engine == null || engine.getApplicationContext() == null) {
-      LOGGER.error("engine or application context is null, only allowed when UT.");
-      return;
-    }
-
-    engine.getApplicationContext().getAutowireCapableBeanFactory().autowireBean(filter);
-  }
-}
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/FilterMeta.java b/core/src/main/java/org/apache/servicecomb/core/filter/FilterMeta.java
deleted file mode 100644
index e40aca4..0000000
--- a/core/src/main/java/org/apache/servicecomb/core/filter/FilterMeta.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.servicecomb.core.filter;
-
-import static org.apache.servicecomb.swagger.invocation.InvocationType.CONSUMER;
-import static org.apache.servicecomb.swagger.invocation.InvocationType.PRODUCER;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-import org.apache.servicecomb.swagger.invocation.InvocationType;
-
-@Documented
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-@Inherited
-public @interface FilterMeta {
-  String name();
-
-  /**
-   *
-   * @return can be used for the specific invocation type
-   */
-  InvocationType[] invocationType() default {CONSUMER, PRODUCER};
-
-  /**
-   *
-   * @return true to use same instance for all filter chains
-   */
-  boolean shareable() default true;
-}
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/FilterNode.java b/core/src/main/java/org/apache/servicecomb/core/filter/FilterNode.java
index 31ac18a..bc6bda0 100644
--- a/core/src/main/java/org/apache/servicecomb/core/filter/FilterNode.java
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/FilterNode.java
@@ -78,7 +78,7 @@ public class FilterNode {
   }
 
   public CompletableFuture<Response> onFilter(Invocation invocation) {
-    if (!filter.enabled()) {
+    if (!filter.isEnabled()) {
       return nextNode.onFilter(invocation);
     }
 
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/FilterProvider.java b/core/src/main/java/org/apache/servicecomb/core/filter/InternalFilter.java
similarity index 89%
rename from core/src/main/java/org/apache/servicecomb/core/filter/FilterProvider.java
rename to core/src/main/java/org/apache/servicecomb/core/filter/InternalFilter.java
index df14364..a79032d 100644
--- a/core/src/main/java/org/apache/servicecomb/core/filter/FilterProvider.java
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/InternalFilter.java
@@ -16,8 +16,5 @@
  */
 package org.apache.servicecomb.core.filter;
 
-import java.util.List;
-
-public interface FilterProvider {
-  List<Class<? extends Filter>> getFilters();
+public interface InternalFilter extends Filter {
 }
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/InvocationFilterChains.java b/core/src/main/java/org/apache/servicecomb/core/filter/InvocationFilterChains.java
new file mode 100644
index 0000000..c719166
--- /dev/null
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/InvocationFilterChains.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicecomb.core.filter;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.apache.servicecomb.core.filter.config.InvocationFilterChainsConfig;
+import org.apache.servicecomb.core.filter.config.TransportChainsConfig;
+import org.apache.servicecomb.core.filter.impl.TransportFilters;
+
+public class InvocationFilterChains {
+  private final Map<String, Filter> filters = new HashMap<>();
+
+  private List<Object> resolvedFrameworkConfig;
+
+  private List<Object> resolvedDefaultConfig;
+
+  private final Map<String, List<Object>> resolvedMicroserviceConfig = new HashMap<>();
+
+  private FilterNode defaultChain;
+
+  private final Map<String, FilterNode> microserviceChains = new HashMap<>();
+
+  public Collection<Filter> getFilters() {
+    return filters.values();
+  }
+
+  public void addFilter(Filter filter) {
+    filters.put(filter.getName(), filter);
+  }
+
+  public List<Object> getResolvedFrameworkConfig() {
+    return resolvedFrameworkConfig;
+  }
+
+  public List<Object> getResolvedDefaultConfig() {
+    return resolvedDefaultConfig;
+  }
+
+  public Map<String, List<Object>> getResolvedMicroserviceConfig() {
+    return resolvedMicroserviceConfig;
+  }
+
+  public void resolve(Function<List<String>, List<Object>> resolver,
+      InvocationFilterChainsConfig config) {
+    resolvedFrameworkConfig = resolver.apply(config.getFrameworkChain());
+    resolvedDefaultConfig = resolver.apply(config.getDefaultChain());
+
+    defaultChain = createChain(resolvedDefaultConfig);
+    for (Entry<String, List<String>> entry : config.getMicroserviceChains().entrySet()) {
+      List<Object> resolveConfig = resolver.apply(entry.getValue());
+
+      resolvedMicroserviceConfig.put(entry.getKey(), resolveConfig);
+      microserviceChains.put(entry.getKey(), createChain(resolveConfig));
+    }
+  }
+
+  private <T> FilterNode createChain(List<T> chain) {
+    List<Filter> filters = createFilters(chain);
+    return FilterNode.buildChain(filters);
+  }
+
+  private <T> List<Filter> createFilters(List<T> chain) {
+    return chain.stream()
+        .map(this::findFilter)
+        .collect(Collectors.toList());
+  }
+
+  private Filter findFilter(Object filterConfig) {
+    if (filterConfig instanceof TransportChainsConfig) {
+      return createTransportFilter((TransportChainsConfig) filterConfig);
+    }
+
+    Filter filter = filters.get(filterConfig);
+    if (filter == null) {
+      throw new IllegalStateException("failed to find filter, name=" + filterConfig);
+    }
+    return filter;
+  }
+
+  private Filter createTransportFilter(TransportChainsConfig config) {
+    TransportFilters transportFilters = new TransportFilters();
+    for (Entry<String, List<String>> entry : config.getChainByTransport().entrySet()) {
+      List<Filter> filters = createFilters(entry.getValue());
+      transportFilters.getChainByTransport().put(entry.getKey(), FilterNode.buildChain(filters));
+    }
+    return transportFilters;
+  }
+
+  public FilterNode findChain(String microserviceName) {
+    return microserviceChains.getOrDefault(microserviceName, defaultChain);
+  }
+}
diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayFilterProvider.java b/core/src/main/java/org/apache/servicecomb/core/filter/ProducerFilter.java
similarity index 67%
rename from transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayFilterProvider.java
rename to core/src/main/java/org/apache/servicecomb/core/filter/ProducerFilter.java
index 87c2b47..969e425 100644
--- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayFilterProvider.java
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/ProducerFilter.java
@@ -14,20 +14,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.servicecomb.transport.highway;
+package org.apache.servicecomb.core.filter;
 
-import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
-import org.apache.servicecomb.core.filter.Filter;
-import org.apache.servicecomb.core.filter.FilterProvider;
+import javax.annotation.Nonnull;
 
-public class HighwayFilterProvider implements FilterProvider {
+import org.apache.servicecomb.swagger.invocation.InvocationType;
+
+public interface ProducerFilter extends Filter {
+  @Nonnull
   @Override
-  public List<Class<? extends Filter>> getFilters() {
-    return Arrays.asList(
-        HighwayClientFilter.class,
-        HighwayServerCodecFilter.class
-    );
+  default List<InvocationType> getInvocationTypes() {
+    return Collections.singletonList(InvocationType.PRODUCER);
   }
 }
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/RestFilterProvider.java b/core/src/main/java/org/apache/servicecomb/core/filter/config/AbstractFilterChainsConfig.java
similarity index 60%
rename from common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/RestFilterProvider.java
rename to core/src/main/java/org/apache/servicecomb/core/filter/config/AbstractFilterChainsConfig.java
index b91a96e..1257245 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/RestFilterProvider.java
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/config/AbstractFilterChainsConfig.java
@@ -14,20 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.servicecomb.common.rest.filter;
+package org.apache.servicecomb.core.filter.config;
 
-import java.util.Arrays;
-import java.util.List;
+import java.util.function.Consumer;
 
-import org.apache.servicecomb.common.rest.filter.inner.RestServerCodecFilter;
-import org.apache.servicecomb.core.filter.Filter;
-import org.apache.servicecomb.core.filter.FilterProvider;
+import org.apache.commons.configuration.Configuration;
 
-public class RestFilterProvider implements FilterProvider {
-  @Override
-  public List<Class<? extends Filter>> getFilters() {
-    return Arrays.asList(
-        RestServerCodecFilter.class
-    );
+import com.netflix.config.DynamicPropertyFactory;
+
+public class AbstractFilterChainsConfig {
+  public static final String ROOT = "servicecomb.filter-chains.";
+
+  protected final Configuration config = (Configuration) DynamicPropertyFactory.getBackingConfigurationSource();
+
+  protected void loadKeys(String root, Consumer<String> loadKey) {
+    config.getKeys(root).forEachRemaining(loadKey);
   }
 }
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/config/FilterChainsConfig.java b/core/src/main/java/org/apache/servicecomb/core/filter/config/FilterChainsConfig.java
index a0e5156..db364c2 100644
--- a/core/src/main/java/org/apache/servicecomb/core/filter/config/FilterChainsConfig.java
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/config/FilterChainsConfig.java
@@ -16,63 +16,90 @@
  */
 package org.apache.servicecomb.core.filter.config;
 
-import static org.apache.servicecomb.core.filter.config.TransportFiltersConfig.FILTER_CHAINS_PREFIX;
-
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
-import org.apache.commons.configuration.Configuration;
 import org.apache.servicecomb.config.ConfigUtil;
-import org.apache.servicecomb.swagger.invocation.InvocationType;
 
-import com.netflix.config.DynamicPropertyFactory;
+public class FilterChainsConfig extends AbstractFilterChainsConfig {
+  public static final String TRANSPORT_ROOT = ROOT + "transport";
+
+  public static final String DEFINITION_ROOT = ROOT + "definition";
+
+  // key is chain name
+  private final Map<String, TransportChainsConfig> transportChains = new HashMap<>();
+
+  private final Map<String, List<String>> definitions = new HashMap<>();
+
+  private InvocationFilterChainsConfig consumer;
+
+  private InvocationFilterChainsConfig producer;
+
+  private boolean enabled;
 
-public class FilterChainsConfig {
-  private final List<Object> defaultChain;
+  public void load() {
+    enabled = config.getBoolean(ROOT + "enabled", false);
 
-  private final Map<String, List<Object>> microserviceChains = new HashMap<>();
+    loadKeys(TRANSPORT_ROOT, this::loadTransportChain);
+    loadKeys(DEFINITION_ROOT, this::loadDefinitionChain);
 
-  private final TransportFiltersConfig transportFiltersConfig;
+    consumer = new InvocationFilterChainsConfig(ROOT + "consumer");
+    producer = new InvocationFilterChainsConfig(ROOT + "producer");
+  }
 
-  public FilterChainsConfig(TransportFiltersConfig transportFiltersConfig, InvocationType type) {
-    this.transportFiltersConfig = transportFiltersConfig;
+  private void loadTransportChain(String qualifiedKey) {
+    String qualifiedName = qualifiedKey.substring(TRANSPORT_ROOT.length() + 1);
+    int dotIdx = qualifiedName.indexOf('.');
+    String chainName = qualifiedName.substring(0, dotIdx);
+    String transport = qualifiedName.substring(dotIdx + 1);
 
-    Configuration config = (Configuration) DynamicPropertyFactory.getBackingConfigurationSource();
-    String root = FILTER_CHAINS_PREFIX + type.name().toLowerCase(Locale.US);
-    defaultChain = resolve(ConfigUtil.getStringList(config, root + ".default"));
-    loadMicroserviceChains(config, root + ".policies");
+    transportChains.computeIfAbsent(chainName, key -> new TransportChainsConfig())
+        .add(transport, ConfigUtil.getStringList(config, qualifiedKey));
   }
 
-  public List<Object> getDefaultChain() {
-    return defaultChain;
+  private void loadDefinitionChain(String qualifiedKey) {
+    String chainName = qualifiedKey.substring(DEFINITION_ROOT.length() + 1);
+
+    definitions.put(chainName, ConfigUtil.getStringList(config, qualifiedKey));
   }
 
-  public Map<String, List<Object>> getMicroserviceChains() {
-    return microserviceChains;
+  public boolean isEnabled() {
+    return enabled;
   }
 
-  public List<Object> findChain(String microservice) {
-    return microserviceChains.getOrDefault(microservice, defaultChain);
+  public InvocationFilterChainsConfig getConsumer() {
+    return consumer;
   }
 
-  private void loadMicroserviceChains(Configuration config, String policiesRoot) {
-    config.getKeys(policiesRoot).forEachRemaining(qualifiedKey -> {
-      String microserviceName = qualifiedKey.substring(policiesRoot.length() + 1);
-      List<String> chain = ConfigUtil.getStringList(config, qualifiedKey);
+  public InvocationFilterChainsConfig getProducer() {
+    return producer;
+  }
 
-      microserviceChains.put(microserviceName, resolve(chain));
-    });
+  public Function<List<String>, List<Object>> getResolver() {
+    return this::resolveChain;
   }
 
-  private List<Object> resolve(List<String> rawChain) {
-    return rawChain.stream()
-        .map(value -> {
-          TransportFilterConfig config = transportFiltersConfig.getConfig(value);
-          return config == null ? value : config;
-        })
+  private List<Object> resolveChain(List<String> chain) {
+    return chain.stream()
+        .flatMap(filterOrReference -> resolveFilterOrReference(filterOrReference).stream())
         .collect(Collectors.toList());
   }
+
+  private List<Object> resolveFilterOrReference(String filterOrReference) {
+    TransportChainsConfig transportChain = transportChains.get(filterOrReference);
+    if (transportChain != null) {
+      return Collections.singletonList(transportChain);
+    }
+
+    List<String> chain = definitions.get(filterOrReference);
+    if (chain == null) {
+      return Collections.singletonList(filterOrReference);
+    }
+
+    return resolveChain(chain);
+  }
 }
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/config/InvocationFilterChainsConfig.java b/core/src/main/java/org/apache/servicecomb/core/filter/config/InvocationFilterChainsConfig.java
new file mode 100644
index 0000000..417aea5
--- /dev/null
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/config/InvocationFilterChainsConfig.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicecomb.core.filter.config;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.servicecomb.config.ConfigUtil;
+import org.springframework.util.CollectionUtils;
+
+public class InvocationFilterChainsConfig extends AbstractFilterChainsConfig {
+  private final String policiesRoot;
+
+  private final List<String> frameworkChain;
+
+  private final List<String> defaultChain;
+
+  private final Map<String, List<String>> microserviceChains = new HashMap<>();
+
+  public InvocationFilterChainsConfig(String root) {
+    frameworkChain = ConfigUtil.getStringList(config, root + ".framework");
+    defaultChain = loadDefaultChain(root);
+
+    policiesRoot = root + ".policies";
+    loadKeys(policiesRoot, this::loadPolicies);
+  }
+
+  private List<String> loadDefaultChain(String root) {
+    String defaultChainKey = root + ".default";
+    List<String> defaultChain = ConfigUtil.getStringList(config, defaultChainKey);
+    if (CollectionUtils.isEmpty(defaultChain) && config.getProperty(defaultChainKey) == null) {
+      defaultChain = frameworkChain;
+    }
+    return defaultChain;
+  }
+
+  private void loadPolicies(String qualifiedKey) {
+    String microserviceName = qualifiedKey.substring(policiesRoot.length() + 1);
+
+    microserviceChains.put(microserviceName, ConfigUtil.getStringList(config, qualifiedKey));
+  }
+
+  public List<String> getFrameworkChain() {
+    return frameworkChain;
+  }
+
+  public List<String> getDefaultChain() {
+    return defaultChain;
+  }
+
+  public Map<String, List<String>> getMicroserviceChains() {
+    return microserviceChains;
+  }
+}
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/config/TransportFilterConfig.java b/core/src/main/java/org/apache/servicecomb/core/filter/config/TransportChainsConfig.java
similarity index 72%
rename from core/src/main/java/org/apache/servicecomb/core/filter/config/TransportFilterConfig.java
rename to core/src/main/java/org/apache/servicecomb/core/filter/config/TransportChainsConfig.java
index e6b675d..5ef2dcd 100644
--- a/core/src/main/java/org/apache/servicecomb/core/filter/config/TransportFilterConfig.java
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/config/TransportChainsConfig.java
@@ -20,21 +20,21 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-public class TransportFilterConfig {
-  private Map<String, List<Object>> filtersByTransport = new HashMap<>();
+public class TransportChainsConfig {
+  private Map<String, List<String>> chainByTransport = new HashMap<>();
 
-  public Map<String, List<Object>> getFiltersByTransport() {
-    return filtersByTransport;
+  public Map<String, List<String>> getChainByTransport() {
+    return chainByTransport;
   }
 
-  public TransportFilterConfig setTransportFilters(String transport, List<Object> filters) {
-    filtersByTransport.put(transport, filters);
+  public TransportChainsConfig add(String transport, List<String> chain) {
+    chainByTransport.put(transport, chain);
 
     return this;
   }
 
   @Override
   public String toString() {
-    return filtersByTransport.toString();
+    return chainByTransport.toString();
   }
 }
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/config/TransportFiltersConfig.java b/core/src/main/java/org/apache/servicecomb/core/filter/config/TransportFiltersConfig.java
deleted file mode 100644
index ef2883d..0000000
--- a/core/src/main/java/org/apache/servicecomb/core/filter/config/TransportFiltersConfig.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.servicecomb.core.filter.config;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.configuration.Configuration;
-import org.springframework.stereotype.Component;
-
-import com.netflix.config.DynamicPropertyFactory;
-
-@Component
-public class TransportFiltersConfig {
-  public static final String FILTER_CHAINS_PREFIX = "servicecomb.filter-chains.";
-
-  public static final String ROOT = FILTER_CHAINS_PREFIX + "transport-filters";
-
-  private final Map<String, TransportFilterConfig> byName = new HashMap<>();
-
-  private final Configuration config = (Configuration) DynamicPropertyFactory.getBackingConfigurationSource();
-
-  public void load() {
-    config.getKeys(ROOT).forEachRemaining(this::loadOneChain);
-  }
-
-  private void loadOneChain(String qualifiedKey) {
-    String qualifiedName = qualifiedKey.substring(ROOT.length() + 1);
-    int dotIdx = qualifiedName.indexOf('.');
-    String name = qualifiedName.substring(0, dotIdx);
-    String transport = qualifiedName.substring(dotIdx + 1);
-
-    byName.computeIfAbsent(name, key -> new TransportFilterConfig())
-        .setTransportFilters(transport, config.getList(qualifiedKey));
-  }
-
-  public TransportFilterConfig getConfig(String name) {
-    return byName.get(name);
-  }
-}
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/impl/DefaultFilterProvider.java b/core/src/main/java/org/apache/servicecomb/core/filter/impl/EmptyFilter.java
similarity index 59%
rename from core/src/main/java/org/apache/servicecomb/core/filter/impl/DefaultFilterProvider.java
rename to core/src/main/java/org/apache/servicecomb/core/filter/impl/EmptyFilter.java
index 3cfd20e..95da754 100644
--- a/core/src/main/java/org/apache/servicecomb/core/filter/impl/DefaultFilterProvider.java
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/impl/EmptyFilter.java
@@ -16,19 +16,25 @@
  */
 package org.apache.servicecomb.core.filter.impl;
 
-import java.util.Arrays;
-import java.util.List;
+import java.util.concurrent.CompletableFuture;
 
-import org.apache.servicecomb.core.filter.Filter;
-import org.apache.servicecomb.core.filter.FilterProvider;
+import javax.annotation.Nonnull;
+
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.core.filter.FilterNode;
+import org.apache.servicecomb.core.filter.InternalFilter;
+import org.apache.servicecomb.swagger.invocation.Response;
+
+// just for test
+public class EmptyFilter implements InternalFilter {
+  @Nonnull
+  @Override
+  public String getName() {
+    return "empty";
+  }
 
-public class DefaultFilterProvider implements FilterProvider {
   @Override
-  public List<Class<? extends Filter>> getFilters() {
-    return Arrays.asList(
-        SimpleLoadBalanceFilter.class,
-        ScheduleFilter.class,
-        ParameterValidatorFilter.class,
-        ProducerOperationFilter.class);
+  public CompletableFuture<Response> onFilter(Invocation invocation, FilterNode nextNode) {
+    return CompletableFuture.completedFuture(Response.ok(null));
   }
 }
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/impl/ParameterValidatorFilter.java b/core/src/main/java/org/apache/servicecomb/core/filter/impl/ParameterValidatorFilter.java
index 08a6dda..c1d1e70 100644
--- a/core/src/main/java/org/apache/servicecomb/core/filter/impl/ParameterValidatorFilter.java
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/impl/ParameterValidatorFilter.java
@@ -16,12 +16,11 @@
  */
 package org.apache.servicecomb.core.filter.impl;
 
-import static org.apache.servicecomb.swagger.invocation.InvocationType.PRODUCER;
-
 import java.lang.reflect.Method;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 
+import javax.annotation.Nonnull;
 import javax.validation.ConstraintViolation;
 import javax.validation.ConstraintViolationException;
 import javax.validation.Validation;
@@ -30,10 +29,8 @@ import javax.validation.executable.ExecutableValidator;
 import javax.validation.groups.Default;
 
 import org.apache.servicecomb.core.Invocation;
-import org.apache.servicecomb.core.SCBEngine;
-import org.apache.servicecomb.core.filter.Filter;
-import org.apache.servicecomb.core.filter.FilterMeta;
 import org.apache.servicecomb.core.filter.FilterNode;
+import org.apache.servicecomb.core.filter.ProducerFilter;
 import org.apache.servicecomb.foundation.common.utils.AsyncUtils;
 import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation;
 import org.apache.servicecomb.swagger.invocation.Response;
@@ -43,19 +40,29 @@ import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator
 import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.stereotype.Component;
 
 import com.netflix.config.DynamicPropertyFactory;
 
-@FilterMeta(name = "validator", invocationType = PRODUCER)
-public class ParameterValidatorFilter implements Filter {
+@Component
+public class ParameterValidatorFilter implements ProducerFilter, InitializingBean {
   private static final Logger LOGGER = LoggerFactory.getLogger(ParameterValidatorFilter.class);
 
+  public static final String NAME = "validator";
+
   private static final String ENABLE_EL = "servicecomb.filters.validation.useResourceBundleMessageInterpolator";
 
-  private ExecutableValidator validator;
+  protected ExecutableValidator validator;
+
+  @Nonnull
+  @Override
+  public String getName() {
+    return NAME;
+  }
 
   @Override
-  public void init(SCBEngine engine) {
+  public void afterPropertiesSet() {
     validator = createValidatorFactory()
         .getValidator().forExecutables();
   }
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/impl/ProducerOperationFilter.java b/core/src/main/java/org/apache/servicecomb/core/filter/impl/ProducerOperationFilter.java
index 1695ba8..cb06081 100644
--- a/core/src/main/java/org/apache/servicecomb/core/filter/impl/ProducerOperationFilter.java
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/impl/ProducerOperationFilter.java
@@ -16,26 +16,30 @@
  */
 package org.apache.servicecomb.core.filter.impl;
 
-import static org.apache.servicecomb.swagger.invocation.InvocationType.PRODUCER;
-
 import java.lang.reflect.Method;
 import java.util.concurrent.CompletableFuture;
 
+import javax.annotation.Nonnull;
+
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.core.exception.Exceptions;
-import org.apache.servicecomb.core.filter.Filter;
-import org.apache.servicecomb.core.filter.FilterMeta;
 import org.apache.servicecomb.core.filter.FilterNode;
+import org.apache.servicecomb.core.filter.ProducerFilter;
 import org.apache.servicecomb.foundation.common.utils.AsyncUtils;
 import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation;
 import org.apache.servicecomb.swagger.invocation.Response;
 import org.apache.servicecomb.swagger.invocation.context.ContextUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ProducerOperationFilter implements ProducerFilter {
+  public static final String NAME = "producer-operation";
 
-@FilterMeta(name = "producer-operation", invocationType = PRODUCER)
-public class ProducerOperationFilter implements Filter {
-  private static final Logger LOGGER = LoggerFactory.getLogger(ProducerOperationFilter.class);
+  @Nonnull
+  @Override
+  public String getName() {
+    return NAME;
+  }
 
   @Override
   public CompletableFuture<Response> onFilter(Invocation invocation, FilterNode nextNode) {
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/impl/ScheduleFilter.java b/core/src/main/java/org/apache/servicecomb/core/filter/impl/ScheduleFilter.java
index 716095e..a07ff75 100644
--- a/core/src/main/java/org/apache/servicecomb/core/filter/impl/ScheduleFilter.java
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/impl/ScheduleFilter.java
@@ -16,21 +16,29 @@
  */
 package org.apache.servicecomb.core.filter.impl;
 
-import static org.apache.servicecomb.swagger.invocation.InvocationType.PRODUCER;
-
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
 
+import javax.annotation.Nonnull;
+
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.core.exception.Exceptions;
-import org.apache.servicecomb.core.filter.Filter;
-import org.apache.servicecomb.core.filter.FilterMeta;
 import org.apache.servicecomb.core.filter.FilterNode;
+import org.apache.servicecomb.core.filter.ProducerFilter;
 import org.apache.servicecomb.core.invocation.InvocationStageTrace;
 import org.apache.servicecomb.swagger.invocation.Response;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ScheduleFilter implements ProducerFilter {
+  public static final String NAME = "schedule";
+
+  @Nonnull
+  @Override
+  public String getName() {
+    return NAME;
+  }
 
-@FilterMeta(name = "schedule", invocationType = PRODUCER)
-public class ScheduleFilter implements Filter {
   @Override
   public CompletableFuture<Response> onFilter(Invocation invocation, FilterNode next) {
     invocation.getInvocationStageTrace().startSchedule();
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/impl/SimpleLoadBalanceFilter.java b/core/src/main/java/org/apache/servicecomb/core/filter/impl/SimpleLoadBalanceFilter.java
index 557cf1b..0282b95 100644
--- a/core/src/main/java/org/apache/servicecomb/core/filter/impl/SimpleLoadBalanceFilter.java
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/impl/SimpleLoadBalanceFilter.java
@@ -17,18 +17,18 @@
 package org.apache.servicecomb.core.filter.impl;
 
 import static org.apache.servicecomb.core.exception.ExceptionCodes.LB_ADDRESS_NOT_FOUND;
-import static org.apache.servicecomb.swagger.invocation.InvocationType.CONSUMER;
 
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import javax.annotation.Nonnull;
+
 import org.apache.servicecomb.core.Endpoint;
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.core.exception.Exceptions;
-import org.apache.servicecomb.core.filter.Filter;
-import org.apache.servicecomb.core.filter.FilterMeta;
+import org.apache.servicecomb.core.filter.ConsumerFilter;
 import org.apache.servicecomb.core.filter.FilterNode;
 import org.apache.servicecomb.core.handler.impl.SimpleLoadBalanceHandler;
 import org.apache.servicecomb.core.registry.discovery.EndpointDiscoveryFilter;
@@ -40,23 +40,74 @@ import org.apache.servicecomb.registry.discovery.DiscoveryTree;
 import org.apache.servicecomb.swagger.invocation.Response;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
 
 /**
  * build-in round robin LB, for demo scenes
  */
-@FilterMeta(name = "simple-load-balance", invocationType = CONSUMER, shareable = false)
-public class SimpleLoadBalanceFilter implements Filter {
+@Component
+public class SimpleLoadBalanceFilter implements ConsumerFilter {
   private static final Logger LOGGER = LoggerFactory.getLogger(SimpleLoadBalanceHandler.class);
 
-  private DiscoveryTree discoveryTree = new DiscoveryTree();
+  public static final String NAME = "simple-load-balance";
+
+  private static class Service {
+    private final String name;
+
+    private final DiscoveryTree discoveryTree = new DiscoveryTree();
+
+    // key is grouping filter qualified name
+    private final Map<String, AtomicInteger> indexMap = new ConcurrentHashMapEx<>();
+
+    public Service(String name) {
+      this.name = name;
+      discoveryTree.loadFromSPI(DiscoveryFilter.class);
+      discoveryTree.addFilter(new EndpointDiscoveryFilter());
+      discoveryTree.sort();
+    }
+
+    public String getName() {
+      return name;
+    }
+
+    public Endpoint selectEndpoint(Invocation invocation) {
+      DiscoveryContext context = new DiscoveryContext();
+      context.setInputParameters(invocation);
+      VersionedCache endpointsVersionedCache = discoveryTree.discovery(context,
+          invocation.getAppId(),
+          invocation.getMicroserviceName(),
+          invocation.getMicroserviceVersionRule());
+      if (endpointsVersionedCache.isEmpty()) {
+        String msg = "No available address found.";
+        LOGGER.error("{} microserviceName={}, version={}, discoveryGroupName={}",
+            msg,
+            invocation.getMicroserviceName(),
+            invocation.getMicroserviceVersionRule(),
+            endpointsVersionedCache.name());
+        throw Exceptions.consumer(LB_ADDRESS_NOT_FOUND, msg);
+      }
+
+      List<Endpoint> endpoints = endpointsVersionedCache.data();
+      AtomicInteger index = indexMap.computeIfAbsent(endpointsVersionedCache.name(), name -> {
+        LOGGER.info("Create loadBalancer for {}.", name);
+        return new AtomicInteger();
+      });
+      LOGGER.debug("invocation {} use discoveryGroup {}.",
+          invocation.getMicroserviceQualifiedName(),
+          endpointsVersionedCache.name());
+
+      int idx = Math.abs(index.getAndIncrement());
+      idx = idx % endpoints.size();
+      return endpoints.get(idx);
+    }
+  }
 
-  // key is grouping filter qualified name
-  private volatile Map<String, AtomicInteger> indexMap = new ConcurrentHashMapEx<>();
+  private final Map<String, Service> servicesByName = new ConcurrentHashMapEx<>();
 
-  public SimpleLoadBalanceFilter() {
-    discoveryTree.loadFromSPI(DiscoveryFilter.class);
-    discoveryTree.addFilter(new EndpointDiscoveryFilter());
-    discoveryTree.sort();
+  @Nonnull
+  @Override
+  public String getName() {
+    return NAME;
   }
 
   @Override
@@ -65,38 +116,9 @@ public class SimpleLoadBalanceFilter implements Filter {
       return nextNode.onFilter(invocation);
     }
 
-    invocation.setEndpoint(selectEndpoint(invocation));
+    Service service = servicesByName.computeIfAbsent(invocation.getMicroserviceName(), Service::new);
+    Endpoint endpoint = service.selectEndpoint(invocation);
+    invocation.setEndpoint(endpoint);
     return nextNode.onFilter(invocation);
   }
-
-  public Endpoint selectEndpoint(Invocation invocation) {
-    DiscoveryContext context = new DiscoveryContext();
-    context.setInputParameters(invocation);
-    VersionedCache endpointsVersionedCache = discoveryTree.discovery(context,
-        invocation.getAppId(),
-        invocation.getMicroserviceName(),
-        invocation.getMicroserviceVersionRule());
-    if (endpointsVersionedCache.isEmpty()) {
-      String msg = "No available address found.";
-      LOGGER.error("{} microserviceName={}, version={}, discoveryGroupName={}",
-          msg,
-          invocation.getMicroserviceName(),
-          invocation.getMicroserviceVersionRule(),
-          endpointsVersionedCache.name());
-      throw Exceptions.consumer(LB_ADDRESS_NOT_FOUND, msg);
-    }
-
-    List<Endpoint> endpoints = endpointsVersionedCache.data();
-    AtomicInteger index = indexMap.computeIfAbsent(endpointsVersionedCache.name(), name -> {
-      LOGGER.info("Create loadBalancer for {}.", name);
-      return new AtomicInteger();
-    });
-    LOGGER.debug("invocation {} use discoveryGroup {}.",
-        invocation.getMicroserviceQualifiedName(),
-        endpointsVersionedCache.name());
-
-    int idx = Math.abs(index.getAndIncrement());
-    idx = idx % endpoints.size();
-    return endpoints.get(idx);
-  }
 }
diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/impl/TransportFilters.java b/core/src/main/java/org/apache/servicecomb/core/filter/impl/TransportFilters.java
index 2170af3..40e8362 100644
--- a/core/src/main/java/org/apache/servicecomb/core/filter/impl/TransportFilters.java
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/impl/TransportFilters.java
@@ -20,19 +20,29 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 
+import javax.annotation.Nonnull;
+
 import org.apache.servicecomb.core.Invocation;
-import org.apache.servicecomb.core.filter.Filter;
-import org.apache.servicecomb.core.filter.FilterMeta;
 import org.apache.servicecomb.core.filter.FilterNode;
+import org.apache.servicecomb.core.filter.InternalFilter;
 import org.apache.servicecomb.swagger.invocation.Response;
+import org.springframework.stereotype.Component;
 
 /**
- * Internal use only, will not publish by {@link DefaultFilterProvider}
+ * Internal use only
  */
-@FilterMeta(name = "transport-filters")
-public class TransportFilters implements Filter {
+@Component
+public class TransportFilters implements InternalFilter {
+  public static final String NAME = "transport-filters";
+
   private Map<String, FilterNode> chainByTransport = new HashMap<>();
 
+  @Nonnull
+  @Override
+  public String getName() {
+    return NAME;
+  }
+
   public Map<String, FilterNode> getChainByTransport() {
     return chainByTransport;
   }
@@ -43,7 +53,7 @@ public class TransportFilters implements Filter {
     if (filterNode == null) {
       return nextNode.onFilter(invocation);
     }
-    
+
     return filterNode.onFilter(invocation);
   }
 }
diff --git a/core/src/main/resources/microservice.yaml b/core/src/main/resources/microservice.yaml
index cb2c464..8b505cd 100644
--- a/core/src/main/resources/microservice.yaml
+++ b/core/src/main/resources/microservice.yaml
@@ -20,20 +20,25 @@ servicecomb-config-order: -500
 servicecomb:
   filter-chains:
     enabled: false
-    transport-filters:
-      default-consumer-transport:
+    transport:
+      scb-consumer-transport:
         rest: rest-client-codec, rest-client-sender
-        highway: highway-client
-      default-producer-transport:
+      scb-producer-transport:
         rest: rest-server-codec
-        highway: highway-server-codec
+    definition:
+      scb-consumer: simple-load-balance, scb-consumer-transport
+      scb-producer: scb-producer-transport, schedule, producer-operation
     consumer:
-      default: simple-load-balance, default-consumer-transport
+      framework: scb-consumer
+      # when there is no "default" chains, will read framework chains as "default" chains
+      #default: scb-consumer
       # samples for customize microservice filter chain
       #policies:
       #  ms-1: retry, load-balance, transport-client, ms-1-consumer-transport
     producer:
-      default: default-producer-transport, schedule, producer-operation
+      framework: scb-producer
+      # when there is no "default" chains, will read framework chains as "default" chains
+      #default: scb-producer
       # samples for customize microservice filter chain
       #policies:
       #  ms-1: qps-limiter, ms-1-producer-transport, schedule, producer-operation
\ No newline at end of file
diff --git a/core/src/test/java/org/apache/servicecomb/core/filter/FilterChainsManagerTest.java b/core/src/test/java/org/apache/servicecomb/core/filter/FilterChainsManagerTest.java
deleted file mode 100644
index 1a42497..0000000
--- a/core/src/test/java/org/apache/servicecomb/core/filter/FilterChainsManagerTest.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.servicecomb.core.filter;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.servicecomb.core.filter.config.TransportFiltersConfig;
-import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.Test;
-
-public class FilterChainsManagerTest {
-  @Before
-  public void setUp() {
-    ArchaiusUtils.resetConfig();
-  }
-
-  @AfterClass
-  public static void afterAll() {
-    ArchaiusUtils.resetConfig();
-  }
-
-  private void default_chain(String filters) {
-    ArchaiusUtils.setProperty("servicecomb.filter-chains.consumer.default", filters);
-  }
-
-  private void microservice_chain(String microservice, String filters) {
-    String key = String.format("servicecomb.filter-chains.consumer.policies.%s", microservice);
-    ArchaiusUtils.setProperty(key, filters);
-  }
-
-  private FilterChainsManager createFilterChains() {
-    return new FilterChainsManager()
-        .setEnabled(true)
-        .setTransportFiltersConfig(new TransportFiltersConfig())
-        .setFilterManager(new FilterManager())
-        .addProviders(() -> Collections.singletonList(SimpleRetryFilter.class))
-        .init(null);
-  }
-
-  @Test
-  public void should_allow_not_share_filter_instance() {
-    default_chain("simple-load-balance");
-
-    FilterChainsManager filterChains = createFilterChains();
-    List<Filter> aFilters = filterChains.createConsumerFilters("a");
-    List<Filter> bFilters = filterChains.createConsumerFilters("b");
-
-    assertThat(aFilters.get(0)).isNotSameAs(bFilters.get(0));
-  }
-
-  @Test
-  public void should_allow_share_filter_instance() {
-    default_chain("simple-retry");
-
-    FilterChainsManager filterChains = createFilterChains();
-    List<Filter> aFilters = filterChains.createConsumerFilters("a");
-    List<Filter> bFilters = filterChains.createConsumerFilters("b");
-
-    assertThat(aFilters).hasSameElementsAs(bFilters);
-  }
-
-  @Test
-  public void should_allow_mix_share_and_not_share_filter_instance() {
-    default_chain("simple-load-balance, simple-retry");
-
-    FilterChainsManager filterChains = createFilterChains();
-    List<Filter> aFilters = filterChains.createConsumerFilters("a");
-    List<Filter> bFilters = filterChains.createConsumerFilters("b");
-
-    assertThat(aFilters.get(0)).isNotSameAs(bFilters.get(0));
-    assertThat(aFilters.get(1)).isSameAs(bFilters.get(1));
-  }
-
-  @Test
-  public void microservice_scope_should_override_default_scope() {
-    default_chain("simple-load-balance");
-    microservice_chain("a", "simple-retry");
-
-    FilterChainsManager filterChains = createFilterChains();
-    List<Filter> filters = filterChains.createConsumerFilters("a");
-
-    assertThat(filters.get(0)).isInstanceOf(SimpleRetryFilter.class);
-  }
-}
diff --git a/core/src/test/java/org/apache/servicecomb/core/filter/SimpleRetryFilter.java b/core/src/test/java/org/apache/servicecomb/core/filter/SimpleRetryFilter.java
index 061356d..ce54faf 100644
--- a/core/src/test/java/org/apache/servicecomb/core/filter/SimpleRetryFilter.java
+++ b/core/src/test/java/org/apache/servicecomb/core/filter/SimpleRetryFilter.java
@@ -19,14 +19,21 @@ package org.apache.servicecomb.core.filter;
 import java.io.IOException;
 import java.util.concurrent.CompletableFuture;
 
+import javax.annotation.Nonnull;
+
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.core.exception.Exceptions;
 import org.apache.servicecomb.swagger.invocation.Response;
 
-@FilterMeta(name = "simple-retry")
-public class SimpleRetryFilter implements Filter {
+public class SimpleRetryFilter implements ConsumerFilter {
   protected int maxRetry = 3;
 
+  @Nonnull
+  @Override
+  public String getName() {
+    return "simple-retry";
+  }
+
   public SimpleRetryFilter setMaxRetry(int maxRetry) {
     this.maxRetry = maxRetry;
     return this;
diff --git a/core/src/test/java/org/apache/servicecomb/core/filter/impl/ParameterValidatorFilterTest.java b/core/src/test/java/org/apache/servicecomb/core/filter/impl/ParameterValidatorFilterTest.java
index ef7db5e..d21e9a9 100644
--- a/core/src/test/java/org/apache/servicecomb/core/filter/impl/ParameterValidatorFilterTest.java
+++ b/core/src/test/java/org/apache/servicecomb/core/filter/impl/ParameterValidatorFilterTest.java
@@ -96,7 +96,7 @@ public class ParameterValidatorFilterTest {
 
   @BeforeClass
   public static void beforeClass() throws Exception {
-    filter.init(null);
+    filter.afterPropertiesSet();
   }
 
   @Before
diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/CodeFirstPojoClient.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/CodeFirstPojoClient.java
index ee91f31..e9c55a1 100644
--- a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/CodeFirstPojoClient.java
+++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/CodeFirstPojoClient.java
@@ -22,7 +22,6 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
 
 import javax.inject.Inject;
@@ -98,18 +97,19 @@ public class CodeFirstPojoClient {
       InvocationContext context = new InvocationContext();
       context.addContext("k", "v");
       ContextUtils.setInvocationContext(context);
-      CompletableFuture<String> future = ((CodeFirstPojoClientIntf) codeFirst).sayHiAsync("someone");
 
-      future.thenCompose(result -> {
-        TestMgr.check("someone sayhi, context k: v", result);
+      ((CodeFirstPojoClientIntf) codeFirst).sayHiAsync("someone")
+          .thenCompose(result -> {
+            TestMgr.check("someone sayhi, context k: v", result);
 
-        TestMgr.check(true, context == ContextUtils.getInvocationContext());
+            TestMgr.check(true, context == ContextUtils.getInvocationContext());
 
-        return ((CodeFirstPojoClientIntf) codeFirst).sayHiAsync("someone 1");
-      }).whenComplete((r, e) -> {
-        TestMgr.check("someone 1 sayhi, context k: v", r);
-        latch.countDown();
-      });
+            return ((CodeFirstPojoClientIntf) codeFirst).sayHiAsync("someone 1");
+          })
+          .whenComplete((r, e) -> {
+            TestMgr.check("someone 1 sayhi, context k: v", r);
+            latch.countDown();
+          });
 
       ContextUtils.removeInvocationContext();
     });
diff --git a/common/common-rest/src/test/resources/microservice.yaml b/handlers/handler-loadbalance/src/test/resources/microservice.yaml
similarity index 75%
copy from common/common-rest/src/test/resources/microservice.yaml
copy to handlers/handler-loadbalance/src/test/resources/microservice.yaml
index b47bdef..4db1321 100644
--- a/common/common-rest/src/test/resources/microservice.yaml
+++ b/handlers/handler-loadbalance/src/test/resources/microservice.yaml
@@ -15,21 +15,9 @@
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
 
-APPLICATION_ID: test
-service_description:
-  name: test
-  version: 0.0.1
 servicecomb:
-  service:
-    registry:
-      address: http://127.0.0.1:30100
-  rest:
-    address: 0.0.0.0:8080
-  highway:
-    address: 0.0.0.0:7070
-  #executors:
-    #default: test 
-    #Provider: 
-      #server: test
-      #server.wrapParam: test
-        
+  filter-chains:
+    consumer:
+      default: empty
+    producer:
+      default: empty
\ No newline at end of file
diff --git a/common/common-rest/src/test/resources/microservice.yaml b/handlers/handler-publickey-auth/src/test/resources/microservice.yaml
similarity index 75%
copy from common/common-rest/src/test/resources/microservice.yaml
copy to handlers/handler-publickey-auth/src/test/resources/microservice.yaml
index b47bdef..4db1321 100644
--- a/common/common-rest/src/test/resources/microservice.yaml
+++ b/handlers/handler-publickey-auth/src/test/resources/microservice.yaml
@@ -15,21 +15,9 @@
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
 
-APPLICATION_ID: test
-service_description:
-  name: test
-  version: 0.0.1
 servicecomb:
-  service:
-    registry:
-      address: http://127.0.0.1:30100
-  rest:
-    address: 0.0.0.0:8080
-  highway:
-    address: 0.0.0.0:7070
-  #executors:
-    #default: test 
-    #Provider: 
-      #server: test
-      #server.wrapParam: test
-        
+  filter-chains:
+    consumer:
+      default: empty
+    producer:
+      default: empty
\ No newline at end of file
diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingFilter.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingFilter.java
index 9d76b26..f896004 100644
--- a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingFilter.java
+++ b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingFilter.java
@@ -21,28 +21,36 @@ import static org.apache.servicecomb.swagger.invocation.InvocationType.PRODUCER;
 
 import java.util.concurrent.CompletableFuture;
 
+import javax.annotation.Nonnull;
+
 import org.apache.servicecomb.core.Invocation;
-import org.apache.servicecomb.core.SCBEngine;
 import org.apache.servicecomb.core.exception.Exceptions;
 import org.apache.servicecomb.core.filter.Filter;
-import org.apache.servicecomb.core.filter.FilterMeta;
 import org.apache.servicecomb.core.filter.FilterNode;
-import org.apache.servicecomb.foundation.common.utils.BeanUtils;
 import org.apache.servicecomb.swagger.invocation.Response;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
 
 import brave.Span;
 import brave.Tracer.SpanInScope;
 import brave.http.HttpTracing;
 
-@FilterMeta(name = "zipkin")
+@Component
 public class ZipkinTracingFilter implements Filter {
+  public static final String NAME = "zipkin";
+
   private ZipkinConsumerDelegate consumer;
 
   private ZipkinProviderDelegate producer;
 
+  @Nonnull
   @Override
-  public void init(SCBEngine engine) {
-    HttpTracing httpTracing = BeanUtils.getContext().getBean(HttpTracing.class);
+  public String getName() {
+    return NAME;
+  }
+
+  @Autowired
+  public void setHttpTracing(HttpTracing httpTracing) {
     this.consumer = new ZipkinConsumerDelegate(httpTracing);
     this.producer = new ZipkinProviderDelegate(httpTracing);
   }
diff --git a/common/common-rest/src/test/resources/microservice.yaml b/inspector/src/test/resources/microservice.yaml
similarity index 75%
copy from common/common-rest/src/test/resources/microservice.yaml
copy to inspector/src/test/resources/microservice.yaml
index b47bdef..4db1321 100644
--- a/common/common-rest/src/test/resources/microservice.yaml
+++ b/inspector/src/test/resources/microservice.yaml
@@ -15,21 +15,9 @@
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
 
-APPLICATION_ID: test
-service_description:
-  name: test
-  version: 0.0.1
 servicecomb:
-  service:
-    registry:
-      address: http://127.0.0.1:30100
-  rest:
-    address: 0.0.0.0:8080
-  highway:
-    address: 0.0.0.0:7070
-  #executors:
-    #default: test 
-    #Provider: 
-      #server: test
-      #server.wrapParam: test
-        
+  filter-chains:
+    consumer:
+      default: empty
+    producer:
+      default: empty
\ No newline at end of file
diff --git a/integration-tests/tracing-tests/src/test/resources/microservice.yaml b/integration-tests/tracing-tests/src/test/resources/microservice.yaml
index 939decc..314ad9b 100644
--- a/integration-tests/tracing-tests/src/test/resources/microservice.yaml
+++ b/integration-tests/tracing-tests/src/test/resources/microservice.yaml
@@ -35,7 +35,7 @@ servicecomb:
         default: tracing-consumer,loadbalance,bizkeeper-consumer
   filter-chains:
     producer:
-      default: default-producer-transport, schedule, zipkin, validator, producer-operation
+      default: scb-producer-transport, schedule, zipkin, validator, producer-operation
   tracing:
     collector:
       address: http://localhost:9411
diff --git a/common/common-rest/src/test/resources/microservice.yaml b/providers/provider-pojo/src/test/resources/microservice.yaml
similarity index 75%
copy from common/common-rest/src/test/resources/microservice.yaml
copy to providers/provider-pojo/src/test/resources/microservice.yaml
index b47bdef..4db1321 100644
--- a/common/common-rest/src/test/resources/microservice.yaml
+++ b/providers/provider-pojo/src/test/resources/microservice.yaml
@@ -15,21 +15,9 @@
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
 
-APPLICATION_ID: test
-service_description:
-  name: test
-  version: 0.0.1
 servicecomb:
-  service:
-    registry:
-      address: http://127.0.0.1:30100
-  rest:
-    address: 0.0.0.0:8080
-  highway:
-    address: 0.0.0.0:7070
-  #executors:
-    #default: test 
-    #Provider: 
-      #server: test
-      #server.wrapParam: test
-        
+  filter-chains:
+    consumer:
+      default: empty
+    producer:
+      default: empty
\ No newline at end of file
diff --git a/common/common-rest/src/test/resources/microservice.yaml b/providers/provider-springmvc/src/test/resources/microservice.yaml
similarity index 75%
copy from common/common-rest/src/test/resources/microservice.yaml
copy to providers/provider-springmvc/src/test/resources/microservice.yaml
index b47bdef..4db1321 100644
--- a/common/common-rest/src/test/resources/microservice.yaml
+++ b/providers/provider-springmvc/src/test/resources/microservice.yaml
@@ -15,21 +15,9 @@
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
 
-APPLICATION_ID: test
-service_description:
-  name: test
-  version: 0.0.1
 servicecomb:
-  service:
-    registry:
-      address: http://127.0.0.1:30100
-  rest:
-    address: 0.0.0.0:8080
-  highway:
-    address: 0.0.0.0:7070
-  #executors:
-    #default: test 
-    #Provider: 
-      #server: test
-      #server.wrapParam: test
-        
+  filter-chains:
+    consumer:
+      default: empty
+    producer:
+      default: empty
\ No newline at end of file
diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClientFilter.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClientFilter.java
index 3110b40..fdd7a3e 100644
--- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClientFilter.java
+++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClientFilter.java
@@ -16,27 +16,36 @@
  */
 package org.apache.servicecomb.transport.highway;
 
-import static org.apache.servicecomb.swagger.invocation.InvocationType.CONSUMER;
-
 import java.util.concurrent.CompletableFuture;
 
+import javax.annotation.Nonnull;
+
 import org.apache.servicecomb.codec.protobuf.definition.OperationProtobuf;
 import org.apache.servicecomb.codec.protobuf.definition.ProtobufManager;
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.core.exception.Exceptions;
-import org.apache.servicecomb.core.filter.Filter;
-import org.apache.servicecomb.core.filter.FilterMeta;
+import org.apache.servicecomb.core.filter.ConsumerFilter;
 import org.apache.servicecomb.core.filter.FilterNode;
 import org.apache.servicecomb.foundation.common.utils.AsyncUtils;
 import org.apache.servicecomb.foundation.vertx.client.tcp.TcpData;
 import org.apache.servicecomb.swagger.invocation.Response;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
 
-@FilterMeta(name = "highway-client", invocationType = CONSUMER)
-public class HighwayClientFilter implements Filter {
+@Component
+public class HighwayClientFilter implements ConsumerFilter {
   private static final Logger LOGGER = LoggerFactory.getLogger(HighwayClientFilter.class);
 
+  public static final String NAME = "highway-client";
+
+  @Nonnull
+  @Override
+  public String getName() {
+    return NAME;
+  }
+
   @Override
   public CompletableFuture<Response> onFilter(Invocation invocation, FilterNode nextNode) {
     LOGGER.debug("Sending request by highway, operation={}, endpoint={}.",
@@ -81,7 +90,11 @@ public class HighwayClientFilter implements Filter {
 
   protected Response convertFailedResponseToException(Response response) {
     if (response.isFailed()) {
-      throw Exceptions.create(response.getStatus(), response.getResult());
+      Object errorData = response.getResult();
+      if (errorData instanceof InvocationException) {
+        errorData = ((InvocationException) errorData).getErrorData();
+      }
+      throw Exceptions.create(response.getStatus(), errorData);
     }
 
     return response;
diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerCodecFilter.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerCodecFilter.java
index c719ead..0464b6b 100644
--- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerCodecFilter.java
+++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerCodecFilter.java
@@ -18,24 +18,33 @@ package org.apache.servicecomb.transport.highway;
 
 import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
 import static org.apache.servicecomb.core.exception.Exceptions.exceptionToResponse;
-import static org.apache.servicecomb.swagger.invocation.InvocationType.PRODUCER;
 
 import java.util.concurrent.CompletableFuture;
 
+import javax.annotation.Nonnull;
+
 import org.apache.servicecomb.codec.protobuf.definition.OperationProtobuf;
 import org.apache.servicecomb.codec.protobuf.definition.ResponseRootSerializer;
 import org.apache.servicecomb.core.Invocation;
-import org.apache.servicecomb.core.filter.Filter;
-import org.apache.servicecomb.core.filter.FilterMeta;
 import org.apache.servicecomb.core.filter.FilterNode;
+import org.apache.servicecomb.core.filter.ProducerFilter;
 import org.apache.servicecomb.foundation.common.utils.AsyncUtils;
 import org.apache.servicecomb.swagger.invocation.Response;
 import org.apache.servicecomb.transport.highway.message.ResponseHeader;
+import org.springframework.stereotype.Component;
 
 import io.vertx.core.buffer.Buffer;
 
-@FilterMeta(name = "highway-server-codec", invocationType = PRODUCER)
-public class HighwayServerCodecFilter implements Filter {
+@Component
+public class HighwayServerCodecFilter implements ProducerFilter {
+  public static final String NAME = "highway-server-codec";
+
+  @Nonnull
+  @Override
+  public String getName() {
+    return NAME;
+  }
+
   @Override
   public CompletableFuture<Response> onFilter(Invocation invocation, FilterNode nextNode) {
     return CompletableFuture.completedFuture(invocation)
diff --git a/common/common-rest/src/test/resources/microservice.yaml b/transports/transport-highway/src/main/resources/microservice.yaml
similarity index 75%
copy from common/common-rest/src/test/resources/microservice.yaml
copy to transports/transport-highway/src/main/resources/microservice.yaml
index b47bdef..4b37228 100644
--- a/common/common-rest/src/test/resources/microservice.yaml
+++ b/transports/transport-highway/src/main/resources/microservice.yaml
@@ -15,21 +15,11 @@
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
 
-APPLICATION_ID: test
-service_description:
-  name: test
-  version: 0.0.1
+servicecomb-config-order: -500
 servicecomb:
-  service:
-    registry:
-      address: http://127.0.0.1:30100
-  rest:
-    address: 0.0.0.0:8080
-  highway:
-    address: 0.0.0.0:7070
-  #executors:
-    #default: test 
-    #Provider: 
-      #server: test
-      #server.wrapParam: test
-        
+  filter-chains:
+    transport:
+      scb-consumer-transport:
+        highway: highway-client
+      scb-producer-transport:
+        highway: highway-server-codec
diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientCodecFilter.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientCodecFilter.java
index 24f50ca..6db242a 100644
--- a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientCodecFilter.java
+++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientCodecFilter.java
@@ -16,25 +16,33 @@
  */
 package org.apache.servicecomb.transport.rest.client;
 
-import static org.apache.servicecomb.swagger.invocation.InvocationType.CONSUMER;
-
 import java.util.concurrent.CompletableFuture;
 
+import javax.annotation.Nonnull;
+
 import org.apache.servicecomb.core.Invocation;
-import org.apache.servicecomb.core.filter.Filter;
-import org.apache.servicecomb.core.filter.FilterMeta;
+import org.apache.servicecomb.core.filter.ConsumerFilter;
 import org.apache.servicecomb.core.filter.FilterNode;
 import org.apache.servicecomb.swagger.invocation.Response;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RestClientCodecFilter implements ConsumerFilter {
+  public static final String NAME = "rest-client-codec";
 
-@FilterMeta(name = "rest-client-codec", invocationType = CONSUMER)
-public class RestClientCodecFilter implements Filter {
   protected RestClientTransportContextFactory transportContextFactory;
 
   protected RestClientEncoder encoder;
 
   protected RestClientDecoder decoder;
 
+  @Nonnull
+  @Override
+  public String getName() {
+    return NAME;
+  }
+
   @Autowired
   public RestClientCodecFilter setTransportContextFactory(RestClientTransportContextFactory transportContextFactory) {
     this.transportContextFactory = transportContextFactory;
diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientFilterProvider.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientFilterProvider.java
deleted file mode 100644
index d1e9afb..0000000
--- a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientFilterProvider.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.servicecomb.transport.rest.client;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.servicecomb.core.filter.Filter;
-import org.apache.servicecomb.core.filter.FilterProvider;
-import org.springframework.stereotype.Component;
-
-@Component
-public class RestClientFilterProvider implements FilterProvider {
-  @Override
-  public List<Class<? extends Filter>> getFilters() {
-    return Arrays.asList(
-        RestClientCodecFilter.class,
-        RestClientSenderFilter.class
-    );
-  }
-}
diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientSenderFilter.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientSenderFilter.java
index dfec70a..d5c2bd4 100644
--- a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientSenderFilter.java
+++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientSenderFilter.java
@@ -16,18 +16,26 @@
  */
 package org.apache.servicecomb.transport.rest.client;
 
-import static org.apache.servicecomb.swagger.invocation.InvocationType.CONSUMER;
-
 import java.util.concurrent.CompletableFuture;
 
+import javax.annotation.Nonnull;
+
 import org.apache.servicecomb.core.Invocation;
-import org.apache.servicecomb.core.filter.Filter;
-import org.apache.servicecomb.core.filter.FilterMeta;
+import org.apache.servicecomb.core.filter.ConsumerFilter;
 import org.apache.servicecomb.core.filter.FilterNode;
 import org.apache.servicecomb.swagger.invocation.Response;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RestClientSenderFilter implements ConsumerFilter {
+  public static final String NAME = "rest-client-sender";
+
+  @Nonnull
+  @Override
+  public String getName() {
+    return NAME;
+  }
 
-@FilterMeta(name = "rest-client-sender", invocationType = CONSUMER)
-public class RestClientSenderFilter implements Filter {
   @Override
   public CompletableFuture<Response> onFilter(Invocation invocation, FilterNode nextNode) {
     CompletableFuture<Response> future = new RestClientSender(invocation)