《SpringCloud超级入门》Spring Boot项目搭建步骤(超详细)《六(2)

“status”: “UP”,

“total”: 491270434816,

“free”: 383870214144,

“threshold”: 10485760

}

}

大部分端点默认都不暴露出来,我们可以手动配置需要暴露的端点。如果需要暴露多个端点,可以用逗号分隔,如下所示:

management.endpoints.web.exposure.include=configprops,beans

如果想全部端点都暴露的话直接配置成下面的方式:

management.endpoints.web.exposure.include=*

后面我们会介绍如何使用 Spring Boot Admin在页面上更加直观地展示这些信息,目前都是 Json 格式的数据,不方便查看。

自定义 actuator 端点


我们需要自定义一些规则来判断应用的状态是否健康,可以采用自定义端点的方式来满足多样性的需求。如果我们只是需要对应用的健康状态增加一些其他维度的数据,可以通过继承 AbstractHealthIndicator 来实现自己的业务逻辑。代码如下。

@Component

public class UserHealthIndicator extends AbstractHealthIndicator {

@Override

protected void doHealthCheck(Builder builder) throws Exception {

builder.up().withDetail(“status”, true);

// builder.down().withDetail(“status”, false);

}

}

通过 up 方法指定应用的状态为健康,down 方法指定应用的状态为不健康。withDetail 方法用于添加一些详细信息。访问 /actuator/health,可以得到我们自定义的健康状态的详细信息:

{

“status”: “UP”,

“details”: {

“user”: {

“status”: “UP”,

“details”: {

“status”: true

}

},

“diskSpace”: {

“status”: “UP”,

“details”: {

“total”:

249795969024,

“free”: 7575375872,

“threshold”: 10485760

}

}

}

}

上面我们是在框架自带的 health 端点中进行扩展,还有一种需求是完全开发一个全新的端点,比如查看当前登录的用户信息的端点。自定义全新的端点很简单,通过 @Endpoint 注解就可以实现。代码如下所示。

@Component

@Endpoint(id = “user”)

public class UserEndpoint {

@ReadOperation

public List<Map<String, Object>> health() {

List<Map<String, Object>> list = new ArrayList<>();

Map<String, Object> map = new HashMap<>();

map.put(“userId”, 1001);

map.put(“userName”, “zhangsan”);

list.add(map);

return list;

}

}

访问 /actuator/user 可以看到返回的用户信息如下:

[

{

“userName”: “zhangsan”,

“userId”: 1001

}

]

统一异常处理


对于接口的定义,我们通常会有一个固定的格式

{

“status”: true,

“code”: 200,

“message”: null,

“data”: [

{

“id”: “101”,

“name”: “jack”

},

{

“id”: “102”,

“name”: “jason”

}

]

}

如果调用方在请求我们的 API 时把接口地址写错了,就会得到一个 404 错误:

{

“timestamp”: 1492063521109,

“status”: 404,

“error”: “Not Found”,

“message”: “No message available”,

“path”: “/rest11/auth”

}

后端服务会告诉我们哪个地址没找到,其实也挺友好。但是因为我们上面自定义的数据格式跟下面的不一致,所以当用户拿到这个返回的时候是无法识别的,其中最明显的是 status 字段。

我们自定义的是 boolean 类型,用来表示请求是否成功,这里返回的就是 Http 的状态码,所以我们需要在发生这种系统错误时也能返回我们自定义的那种格式,那就要定义一个异常处理类(代码如下所示),通过这个类既可以返回统一的格式,也可以统一记录异常日志。

@ControllerAdvice

public class GlobalExceptionHandler {

private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

@ExceptionHandler(value = Exception.class)

@ResponseBody

public ResponseData defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {

logger.error(“”, e);

ResponseData r = new ResponseData();

r.setMessage(e.getMessage());

if (e instanceof org.springframework.web.servlet.NoHandlerFoundException) {

r.setCode(404);

} else {

r.setCode(500);

}

r.setData(null);

r.setStatus(false);

return r;

}

}

ResponseData 是我们返回格式的实体类,其发生错误时也会被捕获到,然后封装好返回格式并返回给调用方。在 Spring Boot 的配置文件中加上如下代码所示配置。

出现错误时, 直接抛出异常

spring.mvc.throw-exception-if-no-handler-found=true

不要为我们工程中的资源文件建立映射

spring.resources.add-mappings=false

当我们调用一个不存在的接口时,返回的错误信息就是我们自定义的那种格式:

{

“status”: false, “code”: 404,

“message”: “No handler found for GET /rest11/auth”, “data”: null

}

最后贴上 ResponseData 的定义,代码如下。

public class ResponseData {

private Boolean status = true;

private int code = 200;

private String message;

private Object data;

// get set …

}

异步执行


异步调用就是不用等待结果的返回就执行后面的逻辑;同步调用则需要等待结果再执行后面的逻辑。

通常我们使用异步操作时都会创建一个线程执行一段逻辑,然后把这个线程丢到线程池中去执行,代码如下所示。

ExecutorService executorService = Executors.newFixedThreadPool(10);

executorService.execute(() -> {

try {

// 业务逻辑

} catch (Exception e) {

e.printStackTrace();

} finally {

}

});

这种方式尽管使用了 Java 的 Lambda,但看起来没那么优雅。在 Spring 中有一种更简单的方式来执行异步操作,只需要一个 @Async 注解即可,代码如下所示。

@Async

public void saveLog() {

System.err.println(Thread.currentThread().getName());

}

我们可以直接在 Controller 中调用这个业务方法,它就是异步执行的,会在默认的线程池中去执行。需要注意的是,一定要在外部的类中去调用这个方法,如果在本类调用则不起作用,比如 this.saveLog()。最后在启动类上开启异步任务的执行,添加 @EnableAsync 即可。

@Configuration

@ConfigurationProperties(prefix = “spring.task.pool”)

public class TaskThreadPoolConfig {

// 核心线程数

private int corePoolSize = 5;

// 最大线程数

private int maxPoolSize = 50;

// 线程池维护线程所允许的空闲时间

private int keepAliveSeconds = 60;

// 队列长度

private int queueCapacity = 10000;

// 线程名称前缀

private String threadNamePrefix = “FSH-AsyncTask-”;

// get set …

}

然后我们重新定义线程池的配置,代码如下所示。

@Configuration

public class AsyncTaskExecutePool implements AsyncConfigurer {

private Logger logger = LoggerFactory.getLogger(AsyncTaskExecutePool.class);

@Autowired

private TaskThreadPoolConfig config;

@Override

public Executor getAsyncExecutor() {

ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

executor.setCorePoolSize(config.getCorePoolSize());

executor.setMaxPoolSize(config.getMaxPoolSize());

executor.setQueueCapacity(config.getQueueCapacity());

executor.setKeepAliveSeconds(config.getKeepAliveSeconds());

executor.setThreadNamePrefix(config.getThreadNamePrefix());

executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

executor.initia lize();

return executor;

}

@Override

public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {

// 异步任务中异常处理

return new AsyncUncaughtExceptionHandler() {

@Override

public void handleUncaughtException(Throwable arg0, Method arg1, Object… arg2) {

logger.error(“====" + arg0.getMessage() + "=”, arg0);

logger.error(“exception method:” + arg1.getName());

}

};

}

}

配置完之后我们的异步任务执行的线程池就是我们自定义的了,我们可以在属性文件里面配置线程池的大小等信息,也可以使用默认的配置:

spring.task.pool.maxPoolSize=100

最后讲一下线程池配置的拒绝策略。当我们的线程数量高于线程池的处理速度时,任务会被缓存到本地的队列中。队列也是有大小的,如果超过了这个大小,就需要有拒绝的策略,不然就会出现内存溢出。目前支持两种拒绝策略:

  • AbortPolicy:直接抛出 java.util.concurrent.RejectedExecutionException 异常。

  • CallerRunsPolicy:主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,这样可以有效降低向线程池内添加任务的速度。

建议大家用 CallerRunsPolicy 策略,因为当队列中的任务满了之后,如果直接抛异常,那么这个任务就会被丢弃。

随机端口


在实际的开发过程中,每个项目的端口都是定好的,通过 server.port 可以指定端口。

当一个服务想要启动多个实例时,就需要改变端口,特别是在我们后面进行 Spring Cloud习的时候,服务都会注册到注册中心里去,为了能够让服务随时都可以扩容,在服务启动的时候能随机生成一个可以使用的端口是最好不过的。

在 Spring Boot 中,可以通过 ${random} 来生成随机数字,我们可以这样使用:

server.port=${random.int[2000,8000]}

通过 random.int 方法,指定随机数的访问,生成一个在 2000 到 8000 之间的数字,

编写一个启动参数设置类,代码如下所示。

public class StartCommand {

private Logger logger = LoggerFactory.getLogger(StartCommand.class);

public StartCommand(String[] args) {

Boolean isServerPort = false;

String serverPort = “”;

if (args != null) {

for (String arg : args) {

if (StringUtils.hasText(arg) && arg.startsWith(“–server.port”)) {

isServerPort = true;

serverPort = arg;

break;

}

}

}

// 没有指定端口, 则随机生成一个可用的端口

if (!isServerPort) {

int port = ServerPortUtils.getAvailablePort();

logger.info(“current server.port=” + port);

System.setProperty(“server.port”, String.valueOf(port));

} else {

logger.info(“current server.port=” + serverPort.split(“=”)[1]);

System.setProperty(“server.port”, serverPort.split(“=”)[1]);

}

}

}

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

} else {

logger.info(“current server.port=” + serverPort.split(“=”)[1]);

System.setProperty(“server.port”, serverPort.split(“=”)[1]);

}

}

}

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-epxuZmby-1710847526856)]
[外链图片转存中…(img-bILVmh3s-1710847526857)]
[外链图片转存中…(img-8ZVs4x0I-1710847526857)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-7MVy6BRj-1710847526858)]

  • 21
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud Alibaba 是阿里巴巴提供的基于 Spring Cloud 的开源框架,用于构建微服务架构的应用程序。它提供了一套完整的分布式系统解决方案,包括服务注册与发现、配置管理、负载均衡、熔断器、限流器等核心组件,为开发者提供了高可用、高可靠、高性能的微服务开发环境。 要学习 Spring Cloud Alibaba 并应用于项目实战,可以按照以下步骤进行: 1. 学习基础知识:先了解 Spring Cloud 和 Alibaba 的相关概念和技术栈,包括 Spring Cloud Netflix、Spring Cloud Gateway、Nacos、Sentinel 等。 2. 搭建环境:根据项目需求,选择合适的开发工具和环境,如 IntelliJ IDEA、Eclipse、Maven、JDK 等,并配置好相关依赖。 3. 创建微服务应用:通过 Spring Initializr 创建一个基础的 Spring Boot 项目,并添加 Spring Cloud Alibaba 的相关依赖。 4. 配置服务注册与发现:使用 Nacos 注册中心,将微服务的信息注册到 Nacos 中,并实现服务之间的调用和发现。 5. 配置负载均衡:通过使用 Spring Cloud LoadBalancer 和 Nacos 客户端实现负载均衡,在多个实例之间分配请求负载。 6. 实现断路器和限流:使用 Sentinel 来实现服务的熔断和限流,保护系统免受高并发的冲击。 7. 使用分布式配置:通过 Nacos 实现配置中心,将应用程序的配置文件统一管理,并自动刷新配置。 8. 实现服务网关:使用 Spring Cloud Gateway 构建统一的入口,对外提供简化的 API,并进行请求过滤、路由转发等功能。 9. 监控和追踪:使用 SkyWalking 对微服务的性能和健康状态进行监控,并进行错误追踪和分析。 10. 测试和部署:编写测试用例,对微服务进行单元测试和集成测试,并使用 Docker、Kubernetes 等容器技术进行部署和管理。 通过以上步骤的学习和实践,逐步掌握 Spring Cloud Alibaba 的核心组件和功能,就可以从入门项目实战了。但需要注意的是,只有持续学习和实践,并结合实际项目需求,才能不断提升自己在 Spring Cloud Alibaba 上的能力和经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值