parent
90d6823693
commit
6e2a0e6c13
@ -1,90 +0,0 @@ |
||||
# nacos注册中心 |
||||
|
||||
使用nacos作为注册中心,源码在`registry-nacos`分支 |
||||
|
||||
这里演示如何将默认的eureka注册中心替换成nacos,步骤如下: |
||||
|
||||
- 准备工作 |
||||
|
||||
1.安装nacos,前往[最新稳定版本](https://github.com/alibaba/nacos/releases),下载最新版nacos |
||||
|
||||
2.启动nacos服务器,cd nacos/bin |
||||
|
||||
Linux/Unix/Mac,启动命令(standalone代表着单机模式运行,非集群模式): |
||||
|
||||
`sh startup.sh -m standalone` |
||||
|
||||
Windows,启动命令: |
||||
|
||||
`cmd startup.cmd` |
||||
|
||||
或者双击startup.cmd运行文件。 |
||||
|
||||
更多访问:https://nacos.io/zh-cn/docs/quick-start.html |
||||
|
||||
- 微服务端修改 |
||||
|
||||
1.修改微服务应用pom,打开`sop-example/sop-story/sop-story-web/pom.xml`,注释eureka服务发现依赖,添加nacos服务发现依赖 |
||||
|
||||
```xml |
||||
<!-- 注册中心【只能用一个,不用的注释掉】 --> |
||||
<!-- 使用eureka注册中心 |
||||
<dependency> |
||||
<groupId>org.springframework.cloud</groupId> |
||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> |
||||
</dependency> |
||||
--> |
||||
|
||||
<!-- 使用nacos注册中心 |
||||
版本 0.2.x.RELEASE 对应的是 Spring Boot 2.x 版本,版本 0.1.x.RELEASE 对应的是 Spring Boot 1.x 版本。 |
||||
https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-alibaba-nacos-discovery |
||||
--> |
||||
<dependency> |
||||
<groupId>org.springframework.cloud</groupId> |
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> |
||||
<version>0.2.2.RELEASE</version> |
||||
</dependency> |
||||
<!-- 注册中心end --> |
||||
``` |
||||
|
||||
2.yml文件新增nacos配置,并注释掉eureka相关配置 |
||||
|
||||
```yaml |
||||
spring: |
||||
cloud: |
||||
# nacos注册中心,和eureka只能用一个 |
||||
nacos: |
||||
discovery: |
||||
server-addr: 127.0.0.1:8848 |
||||
``` |
||||
|
||||
- 网关修改 |
||||
|
||||
找到`sop-gateway`工程,步骤同上 |
||||
|
||||
- SOP-admin修改 |
||||
|
||||
|
||||
修改yml文件,设置nacos服务器地址,`registry.name`填nacos |
||||
|
||||
```yaml |
||||
# 注册中心地址,根据实际情况改,这里只是参数,并不会去注册 |
||||
registry: |
||||
eureka-server-addr: http://localhost:1111/eureka/ |
||||
# nacos服务器地址 |
||||
nacos-server-addr: 127.0.0.1:8848 |
||||
# 使用eureka,填:eureka,使用nacos填:nacos |
||||
name: nacos |
||||
``` |
||||
|
||||
- website-server修改 |
||||
|
||||
步骤同`SOP-admin修改` |
||||
|
||||
如果要改成consul注册中心,可参照以上步骤。 |
||||
|
||||
- 参考资料 |
||||
|
||||
1.[nacos介绍及安装](https://nacos.io/zh-cn/docs/quick-start.html) |
||||
|
||||
2.[nacos spring cloud注册发现](https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html) |
@ -1,112 +0,0 @@ |
||||
# 扩展其它注册中心 |
||||
|
||||
**注: nacos注册中心已经实现,本篇以nacos为例介绍如何扩展,如果要改成consul,可按照此方式进行修改** |
||||
|
||||
SOP默认使用eureka注册中心,如果要换成nacos注册中心,步骤如下: |
||||
|
||||
- 实现`com.gitee.sop.registryapi.service.RegistryService`接口 |
||||
|
||||
1.找到`SOP/sop-common/sop-registry-api`工程,在service.impl包下新建一个类,实现RegistryService接口 |
||||
|
||||
```java |
||||
public class RegistryServiceNacos implements RegistryService { |
||||
|
||||
@Override |
||||
public List<ServiceInfo> listAllService(int pageNo, int pageSize) throws Exception { |
||||
// TODO: 返回服务实例 |
||||
} |
||||
|
||||
@Override |
||||
public void onlineInstance(ServiceInstance serviceInstance) throws Exception { |
||||
// TODO: 实例上线 |
||||
} |
||||
|
||||
@Override |
||||
public void offlineInstance(ServiceInstance serviceInstance) throws Exception { |
||||
// TODO: 实例下线 |
||||
} |
||||
} |
||||
``` |
||||
|
||||
2.在`com.gitee.sop.registryapi.config.BaseRegistryConfig`中新增 |
||||
|
||||
```java |
||||
/** |
||||
* 当配置了registry.name=nacos生效 |
||||
* |
||||
* @return |
||||
*/ |
||||
@Bean |
||||
@ConditionalOnProperty(prefix = "registry", name = "name", havingValue = "nacos") |
||||
RegistryService registryServiceNacos() { |
||||
return new RegistryServiceNacos(); |
||||
} |
||||
``` |
||||
|
||||
其中`@ConditionalOnProperty(prefix = "registry", name = "name", havingValue = "nacos")` |
||||
表示`application.properties`配置了`registry.name=nacos`参数才能生效,registry.name=nacos下文会讲到。 |
||||
|
||||
|
||||
- 微服务端修改 |
||||
|
||||
1.修改微服务应用pom.xml,注释eureka服务发现依赖,添加nacos服务发现依赖 |
||||
|
||||
```xml |
||||
<!-- 注册中心【只能用一个,不用的注释掉】 --> |
||||
<!-- 使用eureka注册中心 |
||||
<dependency> |
||||
<groupId>org.springframework.cloud</groupId> |
||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> |
||||
</dependency> |
||||
--> |
||||
|
||||
<!-- 使用nacos注册中心 |
||||
版本 0.2.x.RELEASE 对应的是 Spring Boot 2.x 版本,版本 0.1.x.RELEASE 对应的是 Spring Boot 1.x 版本。 |
||||
https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-alibaba-nacos-discovery |
||||
--> |
||||
<dependency> |
||||
<groupId>org.springframework.cloud</groupId> |
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> |
||||
<version>0.2.2.RELEASE</version> |
||||
</dependency> |
||||
<!-- 注册中心end --> |
||||
``` |
||||
|
||||
2.yml文件新增nacos配置,并注释掉eureka相关配置 |
||||
|
||||
```yaml |
||||
spring: |
||||
cloud: |
||||
# nacos注册中心,和eureka只能用一个 |
||||
nacos: |
||||
discovery: |
||||
server-addr: 127.0.0.1:8848 |
||||
``` |
||||
|
||||
- 网关修改 |
||||
|
||||
找到`sop-gateway`工程,步骤同上 |
||||
|
||||
- SOP-admin修改 |
||||
|
||||
|
||||
修改yml文件,新增nacos服务器地址,`registry.name`填nacos |
||||
|
||||
```yaml |
||||
# 注册中心地址,根据实际情况改,这里只是参数,并不会去注册 |
||||
registry: |
||||
# 使用eureka,填:eureka,使用nacos填:nacos |
||||
name: nacos |
||||
eureka-server-addr: http://localhost:1111/eureka/ |
||||
nacos-server-addr: 127.0.0.1:8848 |
||||
``` |
||||
|
||||
- website-server修改 |
||||
|
||||
步骤同`SOP-admin修改` |
||||
|
||||
- 参考资料 |
||||
|
||||
1.[nacos介绍及安装](https://nacos.io/zh-cn/docs/quick-start.html) |
||||
|
||||
2.[nacos spring cloud注册发现](https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html) |
@ -1,25 +0,0 @@ |
||||
# 原理分析之路由存储 |
||||
|
||||
SOP将路由信息存到了zookeeper当中,服务在启动时,将自己的路由信息上传到zookeeper中。 |
||||
网关监听存放路由的节点,动态更新到本地。 |
||||
|
||||
zookeeper存储路由的结构如下: |
||||
|
||||
```xml |
||||
/com.gitee.sop.route 根节点 |
||||
/serviceId 服务节点,名字为服务名 |
||||
/route1 路由节点,名字为:name+version,存放路由信息 |
||||
/route2 |
||||
/... |
||||
``` |
||||
|
||||
服务启动时,创建`/serviceId`节点,然后遍历创建`/routeN`节点 |
||||
|
||||
同时,网关监听`服务节点`和`路由节点`,当有新服务加入时,网关会获取到新加入的路由节点信息, |
||||
同时路由节点下面的子节点也会被监听到。后续子节点的增删改都会被网关监听到,然后更新到本地。 |
||||
|
||||
服务上传路由相关代码在`com.gitee.sop.servercommon.manager.ServiceZookeeperApiMetaManager`类中 |
||||
|
||||
网关监听相关代码在`com.gitee.sop.gatewaycommon.manager.BaseRouteManager`中 |
||||
|
||||
|
@ -1,19 +0,0 @@ |
||||
package com.gitee.sop.adminserver.bean; |
||||
|
||||
/** |
||||
* @author tanghc |
||||
*/ |
||||
public class SopAdminConstants { |
||||
/** |
||||
* zookeeper存放接口路由信息的根目录 |
||||
*/ |
||||
public static final String SOP_SERVICE_ROUTE_PATH = "/com.gitee.sop.route"; |
||||
|
||||
/** |
||||
* 消息监听路径 |
||||
*/ |
||||
public static final String SOP_MSG_CHANNEL_PATH = "/com.gitee.sop.channel"; |
||||
|
||||
public static final String RELOAD_ROUTE_PERMISSION_PATH = "/com.gitee.sop.route.permission.reload"; |
||||
|
||||
} |
@ -1,16 +0,0 @@ |
||||
package com.gitee.sop.servercommon.bean; |
||||
|
||||
/** |
||||
* @author tanghc |
||||
*/ |
||||
public class ServiceConstants { |
||||
/** |
||||
* zookeeper存放接口路由信息的根目录 |
||||
*/ |
||||
public static final String SOP_SERVICE_ROUTE_PATH = "/com.gitee.sop.route"; |
||||
|
||||
/** |
||||
* 服务临时节点 |
||||
*/ |
||||
public static final String SOP_SERVICE_TEMP_PATH = "/com.gitee.sop.service.tmp"; |
||||
} |
@ -1,92 +0,0 @@ |
||||
package com.gitee.sop.servercommon.configuration; |
||||
|
||||
import com.gitee.sop.servercommon.bean.ServiceConfig; |
||||
import com.gitee.sop.servercommon.exception.ServiceException; |
||||
import com.gitee.sop.servercommon.result.ServiceResultBuilder; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.springframework.web.bind.annotation.ControllerAdvice; |
||||
import org.springframework.web.bind.annotation.ExceptionHandler; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
import org.springframework.web.bind.annotation.ResponseBody; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
|
||||
/** |
||||
* 全局异常处理 |
||||
* @author tanghc |
||||
*/ |
||||
@ControllerAdvice |
||||
@Slf4j |
||||
public class DefaultGlobalExceptionHandler implements GlobalExceptionHandler { |
||||
|
||||
/** |
||||
* 与网关约定好的状态码,表示业务出错 |
||||
*/ |
||||
public static final int BIZ_ERROR_CODE = 4000; |
||||
/** |
||||
* 系统错误 |
||||
*/ |
||||
public static final int SYSTEM_ERROR_CODE = 5050; |
||||
|
||||
public static final String X_SERVICE_ERROR_CODE = "x-service-error-code"; |
||||
|
||||
@RequestMapping("/error") |
||||
@ResponseBody |
||||
public Object error(HttpServletRequest request, HttpServletResponse response) { |
||||
ServiceResultBuilder serviceResultBuilder = ServiceConfig.getInstance().getServiceResultBuilder(); |
||||
return serviceResultBuilder.buildError(request, response, new ServiceException("系统繁忙")); |
||||
} |
||||
|
||||
/** |
||||
* 捕获手动抛出的异常 |
||||
* @param request |
||||
* @param response |
||||
* @param exception |
||||
* @return |
||||
*/ |
||||
@ExceptionHandler(ServiceException.class) |
||||
@ResponseBody |
||||
public Object serviceExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception exception) { |
||||
response.addHeader(X_SERVICE_ERROR_CODE, String.valueOf(BIZ_ERROR_CODE)); |
||||
return this.processError(request, response, exception); |
||||
} |
||||
|
||||
/** |
||||
* 捕获未知异常 |
||||
* @param request |
||||
* @param response |
||||
* @param exception |
||||
* @return |
||||
*/ |
||||
@ExceptionHandler(Exception.class) |
||||
@ResponseBody |
||||
public Object exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception exception) { |
||||
response.addHeader(X_SERVICE_ERROR_CODE, String.valueOf(SYSTEM_ERROR_CODE)); |
||||
log.error("系统错误", exception); |
||||
StringBuilder msg = new StringBuilder(); |
||||
msg.append(exception.getMessage()); |
||||
StackTraceElement[] stackTrace = exception.getStackTrace(); |
||||
// 取5行错误内容
|
||||
int lineCount = 5; |
||||
for (int i = 0; i < stackTrace.length && i < lineCount ; i++) { |
||||
StackTraceElement stackTraceElement = stackTrace[i]; |
||||
msg.append("<br> at ").append(stackTraceElement.toString()); |
||||
} |
||||
response.setHeader("x-service-error-message", msg.toString()); |
||||
return this.processError(request, response, new ServiceException("系统繁忙")); |
||||
} |
||||
|
||||
/** |
||||
* 处理异常 |
||||
* |
||||
* @param request |
||||
* @param response |
||||
* @param exception |
||||
* @return 返回最终结果 |
||||
*/ |
||||
protected Object processError(HttpServletRequest request, HttpServletResponse response, Exception exception) { |
||||
ServiceResultBuilder serviceResultBuilder = ServiceConfig.getInstance().getServiceResultBuilder(); |
||||
return serviceResultBuilder.buildError(request, response, exception); |
||||
} |
||||
} |
@ -0,0 +1,27 @@ |
||||
package com.gitee.sop.servercommon.configuration; |
||||
|
||||
import com.gitee.sop.servercommon.bean.ServiceConfig; |
||||
import com.gitee.sop.servercommon.exception.ServiceException; |
||||
import com.gitee.sop.servercommon.result.ServiceResultBuilder; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
import org.springframework.web.bind.annotation.RestController; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
|
||||
/** |
||||
* @author tanghc |
||||
*/ |
||||
@RestController |
||||
public class ErrorController { |
||||
|
||||
@RequestMapping("/error") |
||||
public Object error(HttpServletRequest request, HttpServletResponse response) { |
||||
return getResult(request, response); |
||||
} |
||||
|
||||
protected Object getResult(HttpServletRequest request, HttpServletResponse response) { |
||||
ServiceResultBuilder serviceResultBuilder = ServiceConfig.getInstance().getServiceResultBuilder(); |
||||
return serviceResultBuilder.buildError(request, response, new ServiceException("系统繁忙")); |
||||
} |
||||
} |
@ -1,7 +1,92 @@ |
||||
package com.gitee.sop.servercommon.configuration; |
||||
|
||||
import com.gitee.sop.servercommon.bean.ServiceConfig; |
||||
import com.gitee.sop.servercommon.exception.ServiceException; |
||||
import com.gitee.sop.servercommon.result.ServiceResultBuilder; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.springframework.web.bind.annotation.ControllerAdvice; |
||||
import org.springframework.web.bind.annotation.ExceptionHandler; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
import org.springframework.web.bind.annotation.ResponseBody; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
|
||||
/** |
||||
* 全局异常处理 |
||||
* @author tanghc |
||||
*/ |
||||
public interface GlobalExceptionHandler { |
||||
@ControllerAdvice |
||||
@Slf4j |
||||
public class GlobalExceptionHandler { |
||||
|
||||
/** |
||||
* 与网关约定好的状态码,表示业务出错 |
||||
*/ |
||||
public static final int BIZ_ERROR_CODE = 4000; |
||||
/** |
||||
* 系统错误 |
||||
*/ |
||||
public static final int SYSTEM_ERROR_CODE = 5050; |
||||
|
||||
public static final String X_SERVICE_ERROR_CODE = "x-service-error-code"; |
||||
|
||||
@RequestMapping("/error") |
||||
@ResponseBody |
||||
public Object error(HttpServletRequest request, HttpServletResponse response) { |
||||
ServiceResultBuilder serviceResultBuilder = ServiceConfig.getInstance().getServiceResultBuilder(); |
||||
return serviceResultBuilder.buildError(request, response, new ServiceException("系统繁忙")); |
||||
} |
||||
|
||||
/** |
||||
* 捕获手动抛出的异常 |
||||
* @param request |
||||
* @param response |
||||
* @param exception |
||||
* @return |
||||
*/ |
||||
@ExceptionHandler(ServiceException.class) |
||||
@ResponseBody |
||||
public Object serviceExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception exception) { |
||||
response.addHeader(X_SERVICE_ERROR_CODE, String.valueOf(BIZ_ERROR_CODE)); |
||||
return this.processError(request, response, exception); |
||||
} |
||||
|
||||
/** |
||||
* 捕获未知异常 |
||||
* @param request |
||||
* @param response |
||||
* @param exception |
||||
* @return |
||||
*/ |
||||
@ExceptionHandler(Exception.class) |
||||
@ResponseBody |
||||
public Object exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception exception) { |
||||
response.addHeader(X_SERVICE_ERROR_CODE, String.valueOf(SYSTEM_ERROR_CODE)); |
||||
log.error("系统错误", exception); |
||||
StringBuilder msg = new StringBuilder(); |
||||
msg.append(exception.getMessage()); |
||||
StackTraceElement[] stackTrace = exception.getStackTrace(); |
||||
// 取5行错误内容
|
||||
int lineCount = 5; |
||||
for (int i = 0; i < stackTrace.length && i < lineCount ; i++) { |
||||
StackTraceElement stackTraceElement = stackTrace[i]; |
||||
msg.append("<br> at ").append(stackTraceElement.toString()); |
||||
} |
||||
response.setHeader("x-service-error-message", msg.toString()); |
||||
return this.processError(request, response, new ServiceException("系统繁忙")); |
||||
} |
||||
|
||||
/** |
||||
* 处理异常 |
||||
* |
||||
* @param request |
||||
* @param response |
||||
* @param exception |
||||
* @return 返回最终结果 |
||||
*/ |
||||
protected Object processError(HttpServletRequest request, HttpServletResponse response, Exception exception) { |
||||
ServiceResultBuilder serviceResultBuilder = ServiceConfig.getInstance().getServiceResultBuilder(); |
||||
return serviceResultBuilder.buildError(request, response, exception); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,9 @@ |
||||
package com.gitee.sop.servercommon.manager; |
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
||||
/** |
||||
* @author tanghc |
||||
*/ |
||||
public interface ServiceRouteInfoHandler { |
||||
} |
@ -1,17 +1,13 @@ |
||||
server.port=3333 |
||||
spring.application.name=book-service |
||||
spring.application.description=book服务 |
||||
|
||||
# nacos注册中心 |
||||
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 |
||||
|
||||
# zookeeper配置 |
||||
spring.cloud.zookeeper.connect-string=localhost:2181 |
||||
|
||||
# zipkin服务跟踪 |
||||
spring.zipkin.base-url=http://127.0.0.1:9411/ |
||||
# 设置sleuth收集信息的比率,默认0.1,最大是1,数字越大越耗性能 |
||||
spring.sleuth.sampler.probability=1 |
||||
# dubbo使用zipkin过滤器 |
||||
dubbo.provider.filter=tracing |
||||
dubbo.consumer.filter=tracing |
||||
#spring.zipkin.base-url=http://127.0.0.1:9411/ |
||||
## 设置sleuth收集信息的比率,默认0.1,最大是1,数字越大越耗性能 |
||||
#spring.sleuth.sampler.probability=1 |
||||
## dubbo使用zipkin过滤器 |
||||
#dubbo.provider.filter=tracing |
||||
#dubbo.consumer.filter=tracing |
||||
|
@ -1,16 +0,0 @@ |
||||
package com.gitee.sop.websiteserver.bean; |
||||
|
||||
/** |
||||
* @author tanghc |
||||
*/ |
||||
public class WebsiteConstants { |
||||
/** |
||||
* zookeeper存放接口路由信息的根目录 |
||||
*/ |
||||
public static final String SOP_SERVICE_ROUTE_PATH = "/com.gitee.sop.route"; |
||||
|
||||
/** |
||||
* 服务临时节点 |
||||
*/ |
||||
public static final String SOP_SERVICE_TEMP_PATH = "/com.gitee.sop.service.tmp"; |
||||
} |
Loading…
Reference in new issue