release 0.5.0 (#930)

* set branch protection

* rat exclude ".asf.yaml"

* add master-0.2.0 to branch protection

* Exclude the".flattened-pom.xml" file into the source package (#799)

* Update copyright year (#801)

* fix NPE in ServiceTestUtil.java (#804)

* polish dockerfile for 0.3.0 (#805)

* update dockerfile and enable autotest

* fix test script

* fix zookeeper version

* fix rat

* develop-for-dubbo-3.x branch merge to develop branch (#808)

* [3.0]Add mesh rule route (#789)

* add mesh rule route

* add mesh rule check

* For #756 (#791)

* [ISSUE #760]Application discover support (#807)

* application discover support

* fix checkstyle

* fix ci

* remove useless pom import,modify Chinese comment

* fix UT bug

Co-authored-by: haoyann <1064645534@qq.com>
Co-authored-by: Aaron-boom <55744718+Aaron-boom@users.noreply.github.com>

* Fix generic invoke fail (#810)

* fix generic invoke fail

* fix ci

* Nacos support application discover (#812)

* Fix generic can't invoke repeatedly (#814)

* Reduce nacos mapping service storage (#817)

* optimize some code for RegistryServerSync (#822)

* Fix circular reference (#823)

* Fix service version spell (#824)

* For #756 (#815)

* For #756

* for 830 (#832)

* for 830

* For 830

* For 830

* For 830

* For 830

* For 830

* [Feature] Dubbo Admin provides service mock ability. (#838)

* commit the API

* develop the front page.

* add edit logic

* develop the front page and test.

* ui change

* change the config key and group

* change rule enable to config center.

* update GlobalMockRule update logic.

* remove the GlobalMockRule

* [feature admin mock] move the diver dependency out of the project.

* [feature admin mock] remove the contributor name and date in javadoc.

* [feature admin mock] optimize the delete mock rule step.

* [feature admin mock] fix the dialog cannot be closed when delete successfully.

* [feature admin mock] add the support for h2 database.

* [feature admin mock] rollback to zookeeper registry.

* [feature admin mock] fix properties.

* [feature admin mock] change mock-admin-api maven version.

* [feature admin mock] fix the feedback and add the parameters in docker-compose.

* [feature admin mock] fix the ci problem.

* [feature admin mock] fix the ci problem.

* [feature admin mock] removed unused import.

* [feature admin mock] add license.

* GovernanceConfiguration use dubbo instead DynamicConfiguration (#840)

* GovernanceConfiguration use dubbo instead DynamicConfiguration

* remove useless change

* for release 0.4.0 (#850)

* [ISSUE #856] update README.md (#857)

* 修复更新,删除service类型的条件路由异常的问题 (#861)

* Fix flaky (#883)

* fix flaky test

* Delete dubbo-admin-server/.nondex directory

Co-authored-by: Ubuntu <rootadmin@vm001.qmx3d0w2ozeuflvliyjbpujvhf.bx.internal.cloudapp.net>

* support jdk11 #862 (#886)

* support jdk11 #862

* support jdk11 #862

Co-authored-by: 卫龙 <weilong@yeteam.com>

* fix #895 (#896)

Co-authored-by: 卫龙 <weilong@yeteam.com>

* fix #893 (#894)

fix #893

Co-authored-by: 卫龙 <weilong@yeteam.com>

* Update index.html (#899)

原cdn.bootcss.com域名失效,需要切换到新域名cdn.bootcdn.net

官网申明:https://www.bootcdn.cn

* support swagger.enable (#902)

* support swagger.enable

* enable swagger by default

Co-authored-by: 璟源 <jingyuan.mj@alibaba-inc.com>

* support dubbo 3.0.8 (#903)

* [Fix bug](#908) (#910)

* ZookeeperMetaDataCollector init method add zk digest acl support (#911)

* Fix notice and opt registry source (#913)

* update year

* fix search

* add relation support

* disable swagger

* Bump fastjson from 1.2.67 to 1.2.83 (#907)

Bumps [fastjson](https://github.com/alibaba/fastjson) from 1.2.67 to 1.2.83.
- [Release notes](https://github.com/alibaba/fastjson/releases)
- [Commits](https://github.com/alibaba/fastjson/compare/1.2.67...1.2.83)

---
updated-dependencies:
- dependency-name: com.alibaba:fastjson
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Add seriialization & timeout (#914)

* update year

* fix search

* add relation support

* disable swagger

* fix interface

* fix interface

* 解决重复点功能,浏览器控制台报错问题,如点击:服务查询-搜索按钮 (#916)

* Fix error when host is null (#920)

* 解决重复点功能,浏览器控制台报错问题,如点击:服务查询-搜索按钮

* 解决可能产生的空指针问题,导致 '消费者'标签无法显示数据

* 解决在服务测试,方法执行成功后。动态生成的consumer元数据,host取值为空的问题情况(dubbo version 3.0.8)

* Update ServiceDetail.vue (#921)

* Up develop (#926)

* release 0.5.0

Co-authored-by: wuwen <wuwen.55@aliyun.com>
Co-authored-by: Huang YunKun <htynkn@gmail.com>
Co-authored-by: haoyann <1064645534@qq.com>
Co-authored-by: Aaron-boom <55744718+Aaron-boom@users.noreply.github.com>
Co-authored-by: Wang Chengming <634749869@qq.com>
Co-authored-by: brotherlu-xcq <1285823170@qq.com>
Co-authored-by: Robert LU <robberphex@gmail.com>
Co-authored-by: ymybxx <775289630@qq.com>
Co-authored-by: plzdoo <55066376+plzdoo@users.noreply.github.com>
Co-authored-by: Ubuntu <rootadmin@vm001.qmx3d0w2ozeuflvliyjbpujvhf.bx.internal.cloudapp.net>
Co-authored-by: chenjjl <50745778+chenjjl@users.noreply.github.com>
Co-authored-by: 卫龙 <weilong@yeteam.com>
Co-authored-by: VirensCn <595170292@qq.com>
Co-authored-by: itmajing <itmajing@163.com>
Co-authored-by: 璟源 <jingyuan.mj@alibaba-inc.com>
Co-authored-by: sherl0ckLiu <108274057+sherl0ckLiu@users.noreply.github.com>
Co-authored-by: sage.xue <job.xueqi@outlook.com>
Co-authored-by: Albumen Kevin <jhq0812@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: cnjxzhao <85160585+cnjxzhao@users.noreply.github.com>
diff --git a/NOTICE b/NOTICE
index 6367c40..9776704 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,5 +1,5 @@
 Apache Dubbo Admin
-Copyright 2018-2021 The Apache Software Foundation
+Copyright 2018-2022 The Apache Software Foundation
 
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
diff --git a/README.md b/README.md
index e018245..20b1122 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,11 @@
 
 - [Vue.js](https://vuejs.org) and [Vue Cli](https://cli.vuejs.org/)
 - [dubbo-admin-ui/README.md](dubbo-admin-ui/README.md) for more detail
-- Set npm **proxy mirror**: if you have network issue, you can set npm proxy mirror to speedup npm install: add `registry =https://registry.npm.taobao.org` to ~/.npmrc
+- Set npm **proxy mirror**:
+
+  if you have network issue, you can set npm proxy mirror to speedup npm install:
+
+  add `registry=https://registry.npmmirror.com` to ~/.npmrc
 
 ### admin Server
 
@@ -35,10 +39,9 @@
 1. Clone source code on develop branch `git clone https://github.com/apache/dubbo-admin.git`
 2. Specify registry address in `dubbo-admin-server/src/main/resources/application.properties`
 3. Build
-
-    > - `mvn clean package -Dmaven.test.skip=true`  
+    - `mvn clean package -Dmaven.test.skip=true`
 4. Start 
-    * `mvn --projects dubbo-admin-server spring-boot:run`  
+    * `mvn --projects dubbo-admin-server spring-boot:run`
     OR
     * `cd dubbo-admin-distribution/target`;   `java -jar dubbo-admin-0.1.jar`
 5. Visit `http://localhost:8080`
@@ -47,10 +50,15 @@
 
 ### Development Setup
 * Run admin server project
-   backend is a standard spring boot project, you can run it in any java IDE
+
+  backend is a standard spring boot project, you can run it in any java IDE
+
 * Run admin ui project
+
   run with `npm run dev`.
+
 * visit web page
+
   visit `http://localhost:8081`, frontend supports hot reload.
   
 ### Swagger support
diff --git a/README_ZH.md b/README_ZH.md
index c1a21d1..4d35128 100644
--- a/README_ZH.md
+++ b/README_ZH.md
@@ -20,7 +20,11 @@
 
 - 使用[Vue.js](https://vuejs.org)作为javascript框架
 - [dubbo-admin-ui/README.md](dubbo-admin-ui/README.md)中有更详细的介绍
-- 设置 npm **代理镜像** : 如果遇到了网络问题,可以设置npm代理镜像来加速npm install的过程:在~/.npmrc中增加 `registry =https://registry.npm.taobao.org`
+- 设置 npm **代理镜像** :
+
+    如果遇到了网络问题,可以设置npm代理镜像来加速npm install的过程:
+
+    在~/.npmrc中增加 `registry=https://registry.npmmirror.com`
 
 ### 后端部分
 
@@ -33,21 +37,25 @@
 1. 下载代码: `git clone https://github.com/apache/dubbo-admin.git`
 2. 在 `dubbo-admin-server/src/main/resources/application.properties`中指定注册中心地址
 3. 构建
-
-    > - `mvn clean package -Dmaven.test.skip=true`  
+    - `mvn clean package -Dmaven.test.skip=true`
 4. 启动 
-   * `mvn --projects dubbo-admin-server spring-boot:run`   
-   或者   
-   * `cd dubbo-admin-distribution/target; java -jar dubbo-admin-0.1.jar`
+    * `mvn --projects dubbo-admin-server spring-boot:run`
+    或者
+    * `cd dubbo-admin-distribution/target; java -jar dubbo-admin-0.1.jar`
 5. 访问 `http://localhost:8080`
 ---
 
 ### 开发环境配置
 * 运行`dubbo admin server`
-   `dubbo admin server`是一个标准的spring boot项目, 可以在任何java IDE中运行它
+
+  `dubbo admin server`是一个标准的spring boot项目, 可以在任何java IDE中运行它
+
 * 运行`dubbo admin ui`
+
   `dubbo admin ui`由npm管理和构建,在开发环境中,可以单独运行: `npm run dev`
+
 * 页面访问
+
   访问 `http://localhost:8081`, 由于前后端分开部署,前端支持热加载,任何页面的修改都可以实时反馈,不需要重启应用。
 
 ### Swagger 支持
diff --git a/docker/0.4.0/Dockerfile b/docker/0.4.0/Dockerfile
new file mode 100644
index 0000000..621959c
--- /dev/null
+++ b/docker/0.4.0/Dockerfile
@@ -0,0 +1,30 @@
+# 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.
+
+FROM maven:3-openjdk-8
+RUN mkdir /source && wget https://github.com/apache/dubbo-admin/archive/0.4.0.zip && unzip -q 0.4.0.zip -d /source
+WORKDIR /source/dubbo-admin-0.4.0
+RUN mvn --batch-mode clean package -Dmaven.test.skip=true
+
+FROM openjdk:8-jre
+LABEL maintainer="dev@dubbo.apache.org"
+RUN apt-get update && apt-get install -y tini
+COPY --from=0 /source/dubbo-admin-0.4.0/dubbo-admin-distribution/target/dubbo-admin-0.4.0.jar /app.jar
+COPY --from=0 /source/dubbo-admin-0.4.0/docker/entrypoint.sh /usr/local/bin/entrypoint.sh
+
+ENV JAVA_OPTS ""
+
+ENTRYPOINT ["tini", "--", "/usr/local/bin/entrypoint.sh"]
+EXPOSE 8080
diff --git a/docker/0.4.0/Dockerfile.test b/docker/0.4.0/Dockerfile.test
new file mode 100644
index 0000000..dee4d1d
--- /dev/null
+++ b/docker/0.4.0/Dockerfile.test
@@ -0,0 +1,23 @@
+# 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.
+
+FROM ubuntu:trusty
+RUN apt-get update && apt-get install -yq curl && apt-get clean
+
+WORKDIR /app
+
+ADD test.sh /app/test.sh
+
+CMD ["bash", "test.sh"]
\ No newline at end of file
diff --git a/docker/0.4.0/docker-compose.test.yml b/docker/0.4.0/docker-compose.test.yml
new file mode 100644
index 0000000..9ac7fec
--- /dev/null
+++ b/docker/0.4.0/docker-compose.test.yml
@@ -0,0 +1,33 @@
+# 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.
+
+zookeeper:
+  image: zookeeper:3.5
+admin:
+  build: .
+  dockerfile: Dockerfile
+  links:
+    - zookeeper
+  environment:
+    - admin.registry.address=zookeeper://zookeeper:2181
+    - admin.config-center=zookeeper://zookeeper:2181
+    - admin.metadata-report.address=zookeeper://zookeeper:2181
+  ports: 
+    - 8080
+sut:
+  build: .
+  dockerfile: Dockerfile.test
+  links:
+    - admin
\ No newline at end of file
diff --git a/docker/0.4.0/test.sh b/docker/0.4.0/test.sh
new file mode 100644
index 0000000..d342e35
--- /dev/null
+++ b/docker/0.4.0/test.sh
@@ -0,0 +1,34 @@
+# 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.
+
+LOOP_SIZE=60
+i=0
+
+while [[ $i -lt LOOP_SIZE ]]; do
+	status_code=$(curl --write-out %{http_code} --silent --output /dev/null http://admin:8080)
+
+  if [[ "$status_code" -eq 200 ]] ; then
+    echo "Tests passed!"
+    exit 0
+  else
+    curl -v http://admin:8080
+    echo "status is incorrect, waiting for next turn"
+  fi
+	sleep 5
+	i=$i+1
+done
+
+echo "Tests failed!"
+exit 1
\ No newline at end of file
diff --git a/docker/0.5.0/Dockerfile b/docker/0.5.0/Dockerfile
new file mode 100644
index 0000000..0cf7bcd
--- /dev/null
+++ b/docker/0.5.0/Dockerfile
@@ -0,0 +1,30 @@
+# 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.
+
+FROM maven:3-openjdk-8
+RUN mkdir /source && wget https://github.com/apache/dubbo-admin/archive/0.5.0.zip && unzip -q 0.5.0.zip -d /source
+WORKDIR /source/dubbo-admin-0.5.0
+RUN mvn --batch-mode clean package -Dmaven.test.skip=true
+
+FROM openjdk:8-jre
+LABEL maintainer="dev@dubbo.apache.org"
+RUN apt-get update && apt-get install -y tini
+COPY --from=0 /source/dubbo-admin-0.5.0/dubbo-admin-distribution/target/dubbo-admin-0.5.0.jar /app.jar
+COPY --from=0 /source/dubbo-admin-0.5.0/docker/entrypoint.sh /usr/local/bin/entrypoint.sh
+
+ENV JAVA_OPTS ""
+
+ENTRYPOINT ["tini", "--", "/usr/local/bin/entrypoint.sh"]
+EXPOSE 8080
diff --git a/docker/0.5.0/Dockerfile.test b/docker/0.5.0/Dockerfile.test
new file mode 100644
index 0000000..dee4d1d
--- /dev/null
+++ b/docker/0.5.0/Dockerfile.test
@@ -0,0 +1,23 @@
+# 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.
+
+FROM ubuntu:trusty
+RUN apt-get update && apt-get install -yq curl && apt-get clean
+
+WORKDIR /app
+
+ADD test.sh /app/test.sh
+
+CMD ["bash", "test.sh"]
\ No newline at end of file
diff --git a/docker/0.5.0/docker-compose.test.yml b/docker/0.5.0/docker-compose.test.yml
new file mode 100644
index 0000000..9ac7fec
--- /dev/null
+++ b/docker/0.5.0/docker-compose.test.yml
@@ -0,0 +1,33 @@
+# 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.
+
+zookeeper:
+  image: zookeeper:3.5
+admin:
+  build: .
+  dockerfile: Dockerfile
+  links:
+    - zookeeper
+  environment:
+    - admin.registry.address=zookeeper://zookeeper:2181
+    - admin.config-center=zookeeper://zookeeper:2181
+    - admin.metadata-report.address=zookeeper://zookeeper:2181
+  ports: 
+    - 8080
+sut:
+  build: .
+  dockerfile: Dockerfile.test
+  links:
+    - admin
\ No newline at end of file
diff --git a/docker/0.5.0/test.sh b/docker/0.5.0/test.sh
new file mode 100644
index 0000000..d342e35
--- /dev/null
+++ b/docker/0.5.0/test.sh
@@ -0,0 +1,34 @@
+# 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.
+
+LOOP_SIZE=60
+i=0
+
+while [[ $i -lt LOOP_SIZE ]]; do
+	status_code=$(curl --write-out %{http_code} --silent --output /dev/null http://admin:8080)
+
+  if [[ "$status_code" -eq 200 ]] ; then
+    echo "Tests passed!"
+    exit 0
+  else
+    curl -v http://admin:8080
+    echo "status is incorrect, waiting for next turn"
+  fi
+	sleep 5
+	i=$i+1
+done
+
+echo "Tests failed!"
+exit 1
\ No newline at end of file
diff --git a/dubbo-admin-distribution/pom.xml b/dubbo-admin-distribution/pom.xml
index e8e42fa..3cd4dda 100644
--- a/dubbo-admin-distribution/pom.xml
+++ b/dubbo-admin-distribution/pom.xml
@@ -53,6 +53,8 @@
                             <tasks>
                                 <copy file="../dubbo-admin-server/target/dubbo-admin-server-${project.version}.jar"
                                       tofile="target/dubbo-admin-${project.version}.jar"/>
+                                <copy file="../dubbo-admin-server/target/classes/application.properties"
+                                      tofile="src/bin/config/application.properties"/>
                             </tasks>
                         </configuration>
                         <goals>
diff --git a/dubbo-admin-distribution/src/NOTICE b/dubbo-admin-distribution/src/NOTICE
index df92423..05c73d6 100644
--- a/dubbo-admin-distribution/src/NOTICE
+++ b/dubbo-admin-distribution/src/NOTICE
@@ -1,5 +1,5 @@
 Apache Dubbo Admin
-Copyright 2018-2021 The Apache Software Foundation
+Copyright 2018-2022 The Apache Software Foundation
 
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
@@ -100,7 +100,7 @@
 
 ========================================================================
 Apache Dubbo
-Copyright 2018-2021 The Apache Software Foundation
+Copyright 2018-2022 The Apache Software Foundation
 
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
diff --git a/dubbo-admin-distribution/src/bin/config/application.properties b/dubbo-admin-distribution/src/bin/config/application.properties
index dbbc16c..232b05e 100644
--- a/dubbo-admin-distribution/src/bin/config/application.properties
+++ b/dubbo-admin-distribution/src/bin/config/application.properties
@@ -57,6 +57,11 @@
 server.compression.mime-types=text/css,text/javascript,application/javascript
 server.compression.min-response-size=10240
 
+#token timeout, default is one hour
+admin.check.tokenTimeoutMilli=3600000
+#Jwt signingKey
+admin.check.signSecret=86295dd0c4ef69a1036b0b0c15158d77
+
 #dubbo config
 dubbo.application.name=dubbo-admin
 dubbo.registry.address=${admin.registry.address}
@@ -68,7 +73,7 @@
 #spring.datasource.password=mysql
 
 # h2
-spring.datasource.url=jdbc:h2:mem:~/dubbo-admin;
+spring.datasource.url=jdbc:h2:mem:~/dubbo-admin;MODE=MYSQL;
 spring.datasource.username=sa
 spring.datasource.password=
 
diff --git a/dubbo-admin-server/pom.xml b/dubbo-admin-server/pom.xml
index 73be90f..f03e523 100644
--- a/dubbo-admin-server/pom.xml
+++ b/dubbo-admin-server/pom.xml
@@ -228,6 +228,11 @@
             <artifactId>h2</artifactId>
             <scope>runtime</scope>
         </dependency>
+
+        <dependency>
+            <groupId>javax.xml.bind</groupId>
+            <artifactId>jaxb-api</artifactId>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/SyncUtils.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/SyncUtils.java
index 7a36c0b..34b4e65 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/SyncUtils.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/SyncUtils.java
@@ -21,6 +21,8 @@
 import org.apache.dubbo.admin.model.domain.RegistrySource;
 import org.apache.dubbo.common.BaseServiceMetadata;
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.url.component.DubboServiceAddressURL;
 import org.apache.dubbo.common.utils.StringUtils;
 
 import java.util.ArrayList;
@@ -57,11 +59,13 @@
         p.setService(service);
         p.setAddress(url.getAddress());
         p.setApplication(url.getParameter(Constants.APPLICATION_KEY));
-        p.setUrl(url.toIdentityString());
+        p.setUrl(url.toFullString());
         p.setParameters(url.toParameterString());
 
         p.setDynamic(url.getParameter("dynamic", true));
         p.setEnabled(url.getParameter(Constants.ENABLED_KEY, true));
+        p.setSerialization(url.getParameter(org.apache.dubbo.remoting.Constants.SERIALIZATION_KEY, "hessian2"));
+        p.setTimeout(url.getParameter(CommonConstants.TIMEOUT_KEY, CommonConstants.DEFAULT_TIMEOUT));
         p.setWeight(url.getParameter(Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT));
         p.setUsername(url.getParameter("owner"));
         p.setRegistrySource(RegistrySource.INTERFACE);
@@ -94,7 +98,13 @@
         String version = url.getUrlParam().getParameter(Constants.VERSION_KEY);
         String service = BaseServiceMetadata.buildServiceKey(getServiceInterface(url), group, version);
         c.setService(service);
-        c.setAddress(url.getHost());
+        if (url.getHost() == null) {
+            if (url instanceof DubboServiceAddressURL) {
+                c.setAddress(((DubboServiceAddressURL) url).getConsumerURL().getRawParameter("host"));
+            }
+        } else {
+            c.setAddress(url.getHost());
+        }
         c.setApplication(url.getParameter(Constants.APPLICATION_KEY));
         c.setParameters(url.toParameterString());
 
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java
index 8c39771..f354d6d 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java
@@ -38,6 +38,7 @@
 import org.apache.dubbo.registry.RegistryService;
 import org.apache.dubbo.registry.client.ServiceDiscovery;
 import org.apache.dubbo.registry.client.ServiceDiscoveryFactory;
+import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -46,6 +47,7 @@
 import java.util.Arrays;
 
 import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_PROTECTION_KEY;
 import static org.apache.dubbo.registry.client.ServiceDiscoveryFactory.getExtension;
 
 @Configuration
@@ -147,8 +149,8 @@
             }
             registryUrl = formUrl(registryAddress, registryGroup, registryNameSpace, username, password);
         }
-        RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
-        registry = registryFactory.getRegistry(registryUrl);
+        RegistryFactory registryFactory = ApplicationModel.defaultModel().getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
+        registry = registryFactory.getRegistry(registryUrl.addParameter(ENABLE_EMPTY_PROTECTION_KEY, String.valueOf(false)));
         return registry;
     }
 
@@ -166,7 +168,7 @@
             }
         }
         if (metadataUrl != null) {
-            metaDataCollector = ExtensionLoader.getExtensionLoader(MetaDataCollector.class).getExtension(metadataUrl.getProtocol());
+            metaDataCollector = ApplicationModel.defaultModel().getExtensionLoader(MetaDataCollector.class).getExtension(metadataUrl.getProtocol());
             metaDataCollector.setUrl(metadataUrl);
             metaDataCollector.init();
         } else {
@@ -179,11 +181,10 @@
     @Bean(destroyMethod = "destroy")
     @DependsOn("dubboRegistry")
     ServiceDiscovery getServiceDiscoveryRegistry() throws Exception {
-        URL registryURL = registryUrl.setPath(RegistryService.class.getName());
+        URL registryURL = registryUrl.setPath(RegistryService.class.getName())
+                .addParameter(ENABLE_EMPTY_PROTECTION_KEY, String.valueOf(false));
         ServiceDiscoveryFactory factory = getExtension(registryURL);
-        ServiceDiscovery serviceDiscovery = factory.getServiceDiscovery(registryURL);
-        serviceDiscovery.initialize(registryURL);
-        return serviceDiscovery;
+        return factory.getServiceDiscovery(registryURL);
     }
 
     @Bean
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/SwaggerConfiguration.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/SwaggerConfiguration.java
index a4a4e8a..ef44250 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/SwaggerConfiguration.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/SwaggerConfiguration.java
@@ -17,6 +17,7 @@
 
 package org.apache.dubbo.admin.config;
 
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import springfox.documentation.builders.ApiInfoBuilder;
@@ -29,6 +30,7 @@
 
 @Configuration
 @EnableSwagger2
+@ConditionalOnProperty(name = "swagger.enable", havingValue = "true")
 public class SwaggerConfiguration {
     @Bean
     public Docket createRestApi() {
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/Entity.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/Entity.java
index 3982d62..9778d1b 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/Entity.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/Entity.java
@@ -19,10 +19,10 @@
 import java.io.Serializable;
 import java.util.Date;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Entity
- *
  */
 public abstract class Entity implements Serializable {
 
@@ -128,4 +128,20 @@
         this.miss = miss;
     }
 
+    @java.lang.Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        Entity entity = (Entity) o;
+        return miss == entity.miss && Objects.equals(ids, entity.ids) && Objects.equals(id, entity.id) && Objects.equals(hash, entity.hash) && Objects.equals(created, entity.created) && Objects.equals(modified, entity.modified) && Objects.equals(now, entity.now) && Objects.equals(operator, entity.operator) && Objects.equals(operatorAddress, entity.operatorAddress);
+    }
+
+    @java.lang.Override
+    public int hashCode() {
+        return Objects.hash(ids, id, hash, created, modified, now, operator, operatorAddress, miss);
+    }
 }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/Provider.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/Provider.java
index 2de0ad0..3d4b151 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/Provider.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/Provider.java
@@ -23,10 +23,10 @@
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Provider
- *
  */
 public class Provider extends Entity {
 
@@ -46,6 +46,10 @@
 
     private boolean enabled;          /* provider enabled or not */
 
+    private int timeout;              /* provider timeout */
+
+    private String serialization;      /* provider serialization */
+
     private int weight;          /* provider weight */
 
     private String application; /* application name */
@@ -191,6 +195,22 @@
         this.registrySource = registrySource;
     }
 
+    public int getTimeout() {
+        return timeout;
+    }
+
+    public void setTimeout(int timeout) {
+        this.timeout = timeout;
+    }
+
+    public String getSerialization() {
+        return serialization;
+    }
+
+    public void setSerialization(String serialization) {
+        this.serialization = serialization;
+    }
+
     public URL toUrl() {
         Map<String, String> serviceName2Map = ConvertUtil.serviceName2Map(getService());
         /*if(!serviceName2Map.containsKey(Constants.INTERFACE_KEY)) {
@@ -221,4 +241,23 @@
         return url;
     }
 
+    @java.lang.Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        if (!super.equals(o)) {
+            return false;
+        }
+        Provider provider = (Provider) o;
+        return dynamic == provider.dynamic && enabled == provider.enabled && timeout == provider.timeout && weight == provider.weight && alived == provider.alived && Objects.equals(service, provider.service) && Objects.equals(url, provider.url) && Objects.equals(parameters, provider.parameters) && Objects.equals(address, provider.address) && Objects.equals(registry, provider.registry) && Objects.equals(serialization, provider.serialization) && Objects.equals(application, provider.application) && Objects.equals(username, provider.username) && Objects.equals(expired, provider.expired) && Objects.equals(override, provider.override) && Objects.equals(overrides, provider.overrides) && registrySource == provider.registrySource;
+    }
+
+    @java.lang.Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), service, url, parameters, address, registry, dynamic, enabled, timeout, serialization, weight, application, username, expired, alived, override, overrides, registrySource);
+    }
 }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/RegistrySource.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/RegistrySource.java
index e54644c..a6a9939 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/RegistrySource.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/RegistrySource.java
@@ -19,6 +19,8 @@
 
 public enum RegistrySource {
 
+    ALL,
+
     INTERFACE,
 
     INSTANCE
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminMappingListener.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminMappingListener.java
index 750c734..e335755 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminMappingListener.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminMappingListener.java
@@ -115,6 +115,7 @@
                 List<InstanceAddressURL> instanceAddressUrls = urls.stream().map(url -> (InstanceAddressURL) url).collect(Collectors.toList());
                 serviceMap.put(serviceKey, instanceAddressUrls);
             }
+            instanceRegistryCache.refreshConsumer(false);
         }
 
         private String removeProtocol(String protocolServiceKey) {
@@ -126,4 +127,9 @@
         }
     }
 
+    @Override
+    public void stop() {
+        // ignore
+    }
+
 }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/ZookeeperServiceMapping.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/ZookeeperServiceMapping.java
index 799c040..4c5dc5d 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/ZookeeperServiceMapping.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/ZookeeperServiceMapping.java
@@ -26,6 +26,7 @@
 import org.apache.dubbo.metadata.MappingListener;
 import org.apache.dubbo.remoting.zookeeper.ZookeeperClient;
 import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter;
+import org.apache.dubbo.rpc.model.ApplicationModel;
 
 import java.util.List;
 import java.util.Set;
@@ -45,7 +46,7 @@
 
     @Override
     public void init(URL url) {
-        ZookeeperTransporter zookeeperTransporter = ZookeeperTransporter.getExtension();
+        ZookeeperTransporter zookeeperTransporter = ZookeeperTransporter.getExtension(ApplicationModel.defaultModel());
         zkClient = zookeeperTransporter.connect(url);
         listenerAll();
     }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/metadata/impl/NacosMetaDataCollector.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/metadata/impl/NacosMetaDataCollector.java
index 4379eca..f03ca39 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/metadata/impl/NacosMetaDataCollector.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/metadata/impl/NacosMetaDataCollector.java
@@ -110,8 +110,11 @@
 
     private String getMetaData(MetadataIdentifier identifier) {
         try {
-            return configService.getConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY),
-                    group, 1000 * 10);
+            String fromDubboGroup = configService.getConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY),
+                    "dubbo", 1000 * 10);
+            return org.apache.dubbo.common.utils.StringUtils.isNotEmpty(fromDubboGroup) ? fromDubboGroup :
+                    configService.getConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY),
+                            group, 1000 * 10);
         } catch (NacosException e) {
             logger.warn("Failed to get " + identifier + " from nacos, cause: " + e.getMessage(), e);
         }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/metadata/impl/ZookeeperMetaDataCollector.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/metadata/impl/ZookeeperMetaDataCollector.java
index 3048f64..9bba742 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/metadata/impl/ZookeeperMetaDataCollector.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/metadata/impl/ZookeeperMetaDataCollector.java
@@ -53,7 +53,15 @@
             group = Constants.PATH_SEPARATOR + group;
         }
         root = group;
-        client = CuratorFrameworkFactory.newClient(url.getAddress(), new ExponentialBackoffRetry(1000, 3));
+        CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.
+                builder()
+                .connectString(url.getAddress())
+                .retryPolicy(new ExponentialBackoffRetry(1000, 3));
+        String userInformation = url.getUserInformation();
+        if (userInformation != null && userInformation.length() > 0) {
+            builder = builder.authorization("digest", userInformation.getBytes());
+        }
+        client = builder.build();
         client.start();
     }
 
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java
index 3e66694..886c5b6 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java
@@ -98,7 +98,12 @@
         for (URL url : urls) {
             String category = url.getUrlParam().getParameter(Constants.CATEGORY_KEY);
             if (category == null) {
-                category = Constants.PROVIDERS_CATEGORY;
+                // Assign an initial value to category according to the information in url
+                if (Constants.CONSUMER_SIDE.equals(url.getSide()) || Constants.CONSUMER_PROTOCOL.equals(url.getProtocol())) {
+                    category = Constants.CONSUMERS_CATEGORY;
+                } else {
+                    category = Constants.PROVIDERS_CATEGORY;
+                }
             }
             // NOTE: group and version in empty protocol is *
             if (Constants.EMPTY_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ConsumerServiceImpl.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ConsumerServiceImpl.java
index 0d0f2e5..8395026 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ConsumerServiceImpl.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ConsumerServiceImpl.java
@@ -24,6 +24,8 @@
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;
+
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import java.util.HashMap;
@@ -33,15 +35,22 @@
 @Component
 public class ConsumerServiceImpl extends AbstractService implements ConsumerService {
 
+    @Autowired
+    private InstanceRegistryQueryHelper instanceRegistryQueryHelper;
+
     @Override
     public List<Consumer> findByService(String service) {
-        return SyncUtils.url2ConsumerList(findConsumerUrlByService(service));
+        List<Consumer> consumers = SyncUtils.url2ConsumerList(findConsumerUrlByService(service));
+        consumers.addAll(instanceRegistryQueryHelper.findConsumerByService(service));
+        return consumers;
     }
 
 
     @Override
     public List<Consumer> findAll() {
-        return SyncUtils.url2ConsumerList(findAllConsumerUrl());
+        List<Consumer> consumers = SyncUtils.url2ConsumerList(findAllConsumerUrl());
+        consumers.addAll(instanceRegistryQueryHelper.findAllConsumer());
+        return consumers;
     }
 
     @Override
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryCache.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryCache.java
index 9f1b5ac..520f0db 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryCache.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryCache.java
@@ -17,16 +17,29 @@
 
 package org.apache.dubbo.admin.service.impl;
 
+import org.apache.dubbo.admin.common.util.Constants;
 import org.apache.dubbo.admin.service.RegistryCache;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.NamedThreadFactory;
+import org.apache.dubbo.metadata.MetadataService;
 import org.apache.dubbo.registry.client.InstanceAddressURL;
+import org.apache.dubbo.registry.client.metadata.MetadataUtils;
+import org.apache.dubbo.rpc.service.Destroyable;
 
 import org.springframework.stereotype.Component;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * instance registry url {@link InstanceAddressURL} cache
@@ -37,6 +50,10 @@
 
     private final ConcurrentMap<String, ConcurrentMap<String, Map<String, List<InstanceAddressURL>>>> registryCache = new ConcurrentHashMap<>();
 
+    private final Map<String, Map<String, List<URL>>> subscribedCache = new ConcurrentHashMap<>();
+
+    private final AtomicBoolean startRefresh = new AtomicBoolean(false);
+
     @Override
     public void put(String key, ConcurrentMap<String, Map<String, List<InstanceAddressURL>>> value) {
         registryCache.put(key, value);
@@ -52,4 +69,44 @@
                                                                                         Function<? super String, ? extends ConcurrentMap<String, Map<String, List<InstanceAddressURL>>>> mappingFunction) {
         return registryCache.computeIfAbsent(key, mappingFunction);
     }
+
+    public Map<String, Map<String, List<URL>>> getSubscribedCache() {
+        return subscribedCache;
+    }
+
+    public synchronized void refreshConsumer(boolean refreshAll) {
+        if (startRefresh.compareAndSet(false, true)) {
+            ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("Consumer-Refresh"));
+            executorService.scheduleAtFixedRate(() -> refreshConsumer(true), 60, 60, TimeUnit.MINUTES);
+        }
+
+        Map<String, Map<String, List<URL>>> origin;
+
+        if (refreshAll) {
+            origin = new ConcurrentHashMap<>();
+        } else {
+            origin = subscribedCache;
+        }
+
+        Map<String, List<InstanceAddressURL>> providers = get(Constants.PROVIDERS_CATEGORY).values().stream()
+                .flatMap((e) -> e.values().stream())
+                .flatMap(Collection::stream)
+                .collect(Collectors.groupingBy(InstanceAddressURL::getAddress));
+
+        // remove cached
+        origin.keySet().forEach(providers::remove);
+
+        for (List<InstanceAddressURL> instanceAddressURLs : providers.values()) {
+            MetadataService metadataService = MetadataUtils.referProxy(instanceAddressURLs.get(0).getInstance());
+            try {
+                Set<String> subscribedURLs = metadataService.getSubscribedURLs();
+
+                Map<String, List<URL>> subscribed = subscribedURLs.stream().map(URL::valueOf).collect(Collectors.groupingBy(URL::getServiceKey));
+                origin.put(instanceAddressURLs.get(0).getAddress(), subscribed);
+            } catch (Throwable ignored) {
+
+            }
+            ((Destroyable) metadataService).$destroy();
+        }
+    }
 }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryQueryHelper.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryQueryHelper.java
index aae6e65..c6d075d 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryQueryHelper.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryQueryHelper.java
@@ -18,17 +18,25 @@
 package org.apache.dubbo.admin.service.impl;
 
 import org.apache.dubbo.admin.common.util.Constants;
+import org.apache.dubbo.admin.common.util.Pair;
+import org.apache.dubbo.admin.common.util.SyncUtils;
+import org.apache.dubbo.admin.model.domain.Consumer;
 import org.apache.dubbo.admin.model.domain.Provider;
 import org.apache.dubbo.admin.model.domain.RegistrySource;
+import org.apache.dubbo.common.URLBuilder;
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.url.component.ServiceConfigURL;
 import org.apache.dubbo.common.utils.CollectionUtils;
 import org.apache.dubbo.metadata.MetadataInfo;
 import org.apache.dubbo.registry.client.InstanceAddressURL;
 import org.apache.dubbo.registry.client.ServiceInstance;
+import org.apache.dubbo.rpc.RpcContext;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import org.springframework.stereotype.Component;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -85,6 +93,23 @@
                 .collect(Collectors.toList());
     }
 
+    public List<Consumer> findAllConsumer() {
+        return instanceRegistryCache.getSubscribedCache().values().stream()
+                .flatMap(m -> m.values().stream())
+                .flatMap(Collection::stream)
+                .map(m -> new Pair<>(m.toFullString(), m))
+                .map(SyncUtils::url2Consumer)
+                .collect(Collectors.toList());
+    }
+
+    public List<Consumer> findConsumerByService(String serviceName) {
+        return instanceRegistryCache.getSubscribedCache().values().stream().filter(m -> m.containsKey(serviceName))
+                .flatMap(m -> m.get(serviceName).stream())
+                .map(m -> new Pair<>(m.toFullString(), m))
+                .map(SyncUtils::url2Consumer)
+                .collect(Collectors.toList());
+    }
+
     public List<Provider> findByAddress(String providerAddress) {
         ConcurrentMap<String, Map<String, List<InstanceAddressURL>>> appInterfaceMap = instanceRegistryCache.get(Constants.PROVIDERS_CATEGORY);
         if (appInterfaceMap == null) {
@@ -136,18 +161,31 @@
             MetadataInfo metadataInfo = url.getMetadataInfo();
 
             metadataInfo.getServices().forEach((serviceKey, serviceInfo) -> {
+                // build consumer url
+
+                ServiceConfigURL consumerUrl = new URLBuilder()
+                        .setProtocol(serviceInfo.getProtocol())
+                        .setPath(serviceInfo.getPath())
+                        .addParameter("group", serviceInfo.getGroup())
+                        .addParameter("version", serviceInfo.getVersion())
+                        .build();
+                RpcContext.getServiceContext().setConsumerUrl(consumerUrl);
                 Provider p = new Provider();
                 String service = serviceInfo.getServiceKey();
                 p.setService(service);
                 p.setAddress(url.getAddress());
                 p.setApplication(instance.getServiceName());
-                p.setUrl(url.toParameterString());
+                p.setUrl(url.toFullString());
                 p.setDynamic(url.getParameter("dynamic", true));
                 p.setEnabled(url.getParameter(Constants.ENABLED_KEY, true));
+                p.setSerialization(url.getParameter(org.apache.dubbo.remoting.Constants.SERIALIZATION_KEY, "hessian2"));
+                p.setTimeout(url.getParameter(CommonConstants.TIMEOUT_KEY, CommonConstants.DEFAULT_TIMEOUT));
                 p.setWeight(url.getParameter(Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT));
                 p.setUsername(url.getParameter("owner"));
                 p.setRegistrySource(RegistrySource.INSTANCE);
                 providers.add(p);
+
+                RpcContext.getServiceContext().setConsumerUrl(null);
             });
         });
         return providers;
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java
index 1defce7..5e09ed7 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java
@@ -21,10 +21,12 @@
 import org.apache.dubbo.admin.common.util.SyncUtils;
 import org.apache.dubbo.admin.common.util.Tool;
 import org.apache.dubbo.admin.model.domain.Provider;
+import org.apache.dubbo.admin.model.domain.RegistrySource;
 import org.apache.dubbo.admin.model.dto.ServiceDTO;
 import org.apache.dubbo.admin.service.ProviderService;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;
+
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -292,19 +294,40 @@
      */
     public Set<ServiceDTO> convertProviders2DTO(List<Provider> providers) {
         Set<ServiceDTO> result = new TreeSet<>();
-        for (Provider provider : providers) {
-            String app = provider.getApplication();
-            String service = provider.getService();
+        Map<String, List<Provider>> providerMap = providers.stream().collect(Collectors.groupingBy(Provider::getService));
+        for (Map.Entry<String, List<Provider>> entry : providerMap.entrySet()) {
+            String service = entry.getKey();
             String group = Tool.getGroup(service);
             String version = Tool.getVersion(service);
             String interfaze = Tool.getInterface(service);
-            ServiceDTO s = new ServiceDTO();
-            s.setAppName(app);
-            s.setService(interfaze);
-            s.setGroup(group);
-            s.setVersion(version);
-            s.setRegistrySource(provider.getRegistrySource());
-            result.add(s);
+
+            List<Provider> value = entry.getValue();
+            if (value.size() == 1) {
+                Provider provider = value.get(0);
+                ServiceDTO s = new ServiceDTO();
+                s.setAppName(provider.getApplication());
+                s.setService(interfaze);
+                s.setGroup(group);
+                s.setVersion(version);
+                s.setRegistrySource(provider.getRegistrySource());
+                result.add(s);
+            } else {
+                String app = value.stream().map(Provider::getApplication).distinct().collect(Collectors.joining(", "));
+                RegistrySource registrySource = value.get(0).getRegistrySource();
+
+                boolean matchInterface = value.stream().map(Provider::getRegistrySource).anyMatch(e -> e.equals(RegistrySource.INTERFACE));
+                boolean matchInstance = value.stream().map(Provider::getRegistrySource).anyMatch(e -> e.equals(RegistrySource.INSTANCE));
+                if (matchInterface && matchInstance) {
+                    registrySource = RegistrySource.ALL;
+                }
+                ServiceDTO s = new ServiceDTO();
+                s.setAppName(app);
+                s.setService(interfaze);
+                s.setGroup(group);
+                s.setVersion(version);
+                s.setRegistrySource(registrySource);
+                result.add(s);
+            }
         }
         return result;
     }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/RouteServiceImpl.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/RouteServiceImpl.java
index 4856a5f..e15375e 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/RouteServiceImpl.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/RouteServiceImpl.java
@@ -77,6 +77,7 @@
         //for 2.6
         if (StringUtils.isNotEmpty(newConditionRoute.getService())) {
             for (Route old : convertRouteToOldRoute(oldConditionRoute)) {
+                old.setService(id);
             	registry.unregister(old.toUrl().addParameter(Constants.COMPATIBLE_CONFIG, true));
             }
             for (Route updated : convertRouteToOldRoute(newConditionRoute)) {
@@ -101,6 +102,7 @@
             RoutingRule originRule = YamlParser.loadObject(config, RoutingRule.class);
             ConditionRouteDTO conditionRouteDTO = RouteUtils.createConditionRouteFromRule(originRule);
             for (Route old : convertRouteToOldRoute(conditionRouteDTO)) {
+                old.setService(id);
                 URL oldUrl = old.toUrl();
                 if(oldUrl.getParameter("rule").contains("host") && oldUrl.getParameter("rule").contains("false")) {
                     registry.unregister(oldUrl);
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/utils/ApiDocsDubboGenericUtil.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/utils/ApiDocsDubboGenericUtil.java
index 12b54af..896749f 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/utils/ApiDocsDubboGenericUtil.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/utils/ApiDocsDubboGenericUtil.java
@@ -121,6 +121,8 @@
             referenceConfig.setTimeout(timeout);
             referenceConfig.setVersion(version);
             referenceConfig.setGroup(group);
+            //Keep it consistent with the ConfigManager cache
+            referenceConfig.setSticky(false);
 
             referenceConfig.setApplication(application);
             if (address.startsWith("dubbo")) {
diff --git a/dubbo-admin-server/src/main/resources/application.properties b/dubbo-admin-server/src/main/resources/application.properties
index 4aa924b..232b05e 100644
--- a/dubbo-admin-server/src/main/resources/application.properties
+++ b/dubbo-admin-server/src/main/resources/application.properties
@@ -73,7 +73,7 @@
 #spring.datasource.password=mysql
 
 # h2
-spring.datasource.url=jdbc:h2:mem:~/dubbo-admin;
+spring.datasource.url=jdbc:h2:mem:~/dubbo-admin;MODE=MYSQL;
 spring.datasource.username=sa
 spring.datasource.password=
 
diff --git a/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/common/util/UrlUtilsTest.java b/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/common/util/UrlUtilsTest.java
index 6d74e9a..bdba1e8 100644
--- a/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/common/util/UrlUtilsTest.java
+++ b/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/common/util/UrlUtilsTest.java
@@ -19,14 +19,14 @@
 import org.junit.Assert;
 import org.junit.Test;
 
-import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Map;
 
 public class UrlUtilsTest {
 
     @Test
     public void testParamsMapToString() {
-        Map<String, String[]> params = new HashMap<>();
+        Map<String, String[]> params = new LinkedHashMap<>();
         params.put("a", new String[]{"1", "2", "3"});
         params.put("b", new String[]{"8", "7", "6"});
         String result = UrlUtils.paramsMapToString(params);
diff --git a/dubbo-admin-ui/public/dubbo-admin-info.json b/dubbo-admin-ui/public/dubbo-admin-info.json
index dfcc3af..156772d 100644
--- a/dubbo-admin-ui/public/dubbo-admin-info.json
+++ b/dubbo-admin-ui/public/dubbo-admin-info.json
@@ -1,3 +1,3 @@
 {
-  "version": "0.3.0"
+  "version": "0.5.0"
 }
diff --git a/dubbo-admin-ui/public/index.html b/dubbo-admin-ui/public/index.html
index 63dadb1..01be2e7 100644
--- a/dubbo-admin-ui/public/index.html
+++ b/dubbo-admin-ui/public/index.html
@@ -23,7 +23,7 @@
     <title>Dubbo Admin</title>
     <link href='OpenSans.css' rel="stylesheet" type="text/css">
     <link rel="shortcut icon" href="dubbo.ico" type="image/x-icon">
-    <script src="https://cdn.bootcss.com/echarts/4.0.4/echarts-en.min.js"></script>
+    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/4.0.4/echarts-en.min.js"></script>
   </head>
   <body>
     <div id="app"></div>
diff --git a/dubbo-admin-ui/src/components/ServiceDetail.vue b/dubbo-admin-ui/src/components/ServiceDetail.vue
index 79fa779..554e5ba 100644
--- a/dubbo-admin-ui/src/components/ServiceDetail.vue
+++ b/dubbo-admin-ui/src/components/ServiceDetail.vue
@@ -55,8 +55,8 @@
                 <td>{{getIp(props.item.address)}}</td>
                 <td>{{getPort(props.item.address)}}</td>
                 <td>{{props.item.registrySource}}</td>
-                <td></td>
-                <td></td>
+                <td>{{props.item.timeout}}</td>
+                <td>{{props.item.serialization}}</td>
                 <td>{{props.item.weight}}</td>
                 <td>
                   <v-tooltip top>
@@ -84,7 +84,6 @@
             >
               <template slot="items" slot-scope="props">
                 <td>{{getIp(props.item.address)}}</td>
-                <td>{{getPort(props.item.address)}}</td>
                 <td>{{props.item.application}}</td>
               </template>
             </v-data-table>
@@ -177,7 +176,7 @@
             },
             {
               text: this.$t('serialization'),
-              value: 'serial'
+              value: 'serialization'
             },
             {
               text: this.$t('weight'),
@@ -195,10 +194,6 @@
               value: 'ip'
             },
             {
-              text: this.$t('port'),
-              value: 'port'
-            },
-            {
               text: this.$t('appName'),
               value: 'appName'
             }
@@ -211,6 +206,7 @@
               this.providerDetails = response.data.providers
               const instanceRegistry = this.$t('instanceRegistry')
               const interfaceRegistry = this.$t('interfaceRegistry')
+              const allRegistry = this.$t('allRegistry')
               for (let i = 0; i < this.providerDetails.length; i++) {
                 if (this.providerDetails[i].registrySource === 'INSTANCE') {
                   this.providerDetails[i].registrySource = instanceRegistry
@@ -218,6 +214,9 @@
                 if (this.providerDetails[i].registrySource === 'INTERFACE') {
                   this.providerDetails[i].registrySource = interfaceRegistry
                 }
+                if (this.providerDetails[i].registrySource === 'ALL') {
+                  this.providerDetails[i].registrySource = allRegistry
+                }
                 console.log(this.providerDetails[i])
                 this.$set(this.providerDetails[i], 'hint', 'url')
               }
@@ -228,10 +227,10 @@
             })
       },
       getIp: function (address) {
-        return address.split(':')[0]
+        return address != null ? address.split(':')[0] : null
       },
       getPort: function (address) {
-        return address.split(':')[1]
+        return address != null && address.split(':').length >= 2 ? address.split(':')[1] : null
       },
       toCopyText (text) {
         this.$copyText(text).then(() => {
diff --git a/dubbo-admin-ui/src/components/ServiceSearch.vue b/dubbo-admin-ui/src/components/ServiceSearch.vue
index c5ce4fb..4627fbd 100644
--- a/dubbo-admin-ui/src/components/ServiceSearch.vue
+++ b/dubbo-admin-ui/src/components/ServiceSearch.vue
@@ -201,6 +201,7 @@
       }
       const instanceRegistry = this.$t('instanceRegistry')
       const interfaceRegistry = this.$t('interfaceRegistry')
+      const allRegistry = this.$t('allRegistry')
       return this.resultPage.content.filter(function (item) {
         if (item.registrySource === 'INSTANCE') {
           item.registrySource = instanceRegistry
@@ -208,6 +209,9 @@
         if (item.registrySource === 'INTERFACE') {
           item.registrySource = interfaceRegistry
         }
+        if (item.registrySource === 'ALL') {
+          item.registrySource = allRegistry
+        }
         return item
       })
     }
diff --git a/dubbo-admin-ui/src/components/public/Footers.vue b/dubbo-admin-ui/src/components/public/Footers.vue
index 6ad8ae6..08e4016 100644
--- a/dubbo-admin-ui/src/components/public/Footers.vue
+++ b/dubbo-admin-ui/src/components/public/Footers.vue
@@ -18,7 +18,7 @@
 <template>
   <v-footer inset height="auto" class="pa-3 footer-border-top">
     <v-spacer></v-spacer>
-    <span class="caption mr-1"><strong>Copyright</strong> &copy;2018-2021 <strong>The Apache Software Foundation.</strong></span>
+    <span class="caption mr-1"><strong>Copyright</strong> &copy;2018-2022 <strong>The Apache Software Foundation.</strong></span>
   </v-footer>
 </template>
 <script>
diff --git a/dubbo-admin-ui/src/lang/en.js b/dubbo-admin-ui/src/lang/en.js
index c84fd7a..f534e81 100644
--- a/dubbo-admin-ui/src/lang/en.js
+++ b/dubbo-admin-ui/src/lang/en.js
@@ -49,6 +49,7 @@
   registrySource: 'Registry Source',
   instanceRegistry: 'Instance Registry',
   interfaceRegistry: 'Interface Registry',
+  allRegistry: 'Instance / Interface Registry',
   operation: 'Operation',
   searchResult: 'Search Result',
   search: 'Search',
diff --git a/dubbo-admin-ui/src/lang/zh.js b/dubbo-admin-ui/src/lang/zh.js
index fa979c4..2b97382 100644
--- a/dubbo-admin-ui/src/lang/zh.js
+++ b/dubbo-admin-ui/src/lang/zh.js
@@ -49,6 +49,7 @@
   registrySource: '注册来源',
   instanceRegistry: '应用级',
   interfaceRegistry: '接口级',
+  allRegistry: '应用级/接口级',
   operation: '操作',
   searchResult: '查询结果',
   search: '搜索',
diff --git a/dubbo-admin-ui/src/router/index.js b/dubbo-admin-ui/src/router/index.js
index 8cb9574..96a3af3 100644
--- a/dubbo-admin-ui/src/router/index.js
+++ b/dubbo-admin-ui/src/router/index.js
@@ -36,6 +36,11 @@
 import Index from '@/Index'
 import Login from '@/Login'
 
+const originalPush = Router.prototype.push
+Router.prototype.push = function push(location) {
+  return originalPush.call(this, location).catch(err => err)
+}
+
 Vue.use(Router)
 
 export default new Router({
diff --git a/pom.xml b/pom.xml
index c9ec158..fec0211 100644
--- a/pom.xml
+++ b/pom.xml
@@ -53,17 +53,18 @@
 	</repositories>
 
 	<properties>
-		<revision>0.3.0</revision>
+		<revision>0.5.0</revision>
 		<main.basedir>${project.basedir}</main.basedir>
 		<commons-lang3-version>3.7</commons-lang3-version>
-		<dubbo-version>3.0.2.1</dubbo-version>
-		<fastjson-version>1.2.67</fastjson-version>
+		<dubbo-version>3.0.8</dubbo-version>
+		<fastjson-version>1.2.83</fastjson-version>
 		<springfox-swagger-version>2.9.2</springfox-swagger-version>
 		<jacoco-version>0.8.2</jacoco-version>
 		<apollo-version>1.2.0</apollo-version>
 		<guava-version>20.0</guava-version>
 		<dubbo-mock-version>3.0.0</dubbo-mock-version>
 		<mybatis-plus-boot-version>3.4.2</mybatis-plus-boot-version>
+		<curator-test-veriosn>2.12.0</curator-test-veriosn>
 
 		<maven-checkstyle-plugin-version>3.0.0</maven-checkstyle-plugin-version>
 		<spring-boot-version>2.3.12.RELEASE</spring-boot-version>
@@ -143,6 +144,11 @@
 				<version>${mybatis-plus-boot-version}</version>
 			</dependency>
 
+			<dependency>
+				<groupId>org.apache.curator</groupId>
+				<artifactId>curator-test</artifactId>
+				<version>${curator-test-veriosn}</version>
+			</dependency>
 		</dependencies>
 	</dependencyManagement>