解救应用启动危机:Spring Boot的FailureAnalyzer机制

news2024/12/23 16:40:07

目录

一、走进FailureAnalyzer

二、在Spring Boot中如何生效

三、为什么可能需要自定义FailureAnalyzer

四、实现自定义基本步骤

(一)完整步骤要求

(二)注册方式说明

通过Spring Boot的spring.factories文件(建议方式)

在启动类中手动注册(本人不建议)

五、实现自定义举例

六、一些建议


一、走进FailureAnalyzer

想象一下,你正在开发一个基于Spring Boot的网络应用程序,你已经编写了一大堆代码,做了各种配置,终于迫不及待地想要启动你的应用程序,看看它是不是如你所愿地运行。

你兴奋地运行了启动命令,但突然间,控制台上出现了一堆红色的错误信息。如下:

可以立刻看到这个报错来自于LoggingFailureAnalysisReporter,其内部其实就是Spring Boot中被誉为故障排查神器的工具FailureAnalyzer。你决定让它出马,看看能否解决你的问题。

你应该感到非常惊讶和兴奋,因为FailureAnalyzer不仅仅找出了问题,还给出了解决方案:按照建议修复了配置,再次启动应用程序,这一次一切都运行得非常顺利。

通过这个简单的场景,你立刻感受到了FailureAnalyzer的价值和魔力。它就像是你的应用程序启动的保险,让你在遇到问题时能够迅速找出解决方案,让你的开发过程更加流畅和高效。

二、在Spring Boot中如何生效

在Spring Boot的spring.factories文件(位于META-INF目录下)中已经包含了一些FailureAnalyzer的配置,FailureAnalyzer实现类通常在spring.factories文件中被声明,以便在应用程序启动时被Spring Boot自动发现并注册。

org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.jdbc.DataSourceFailedAnalyzer,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQConnectFailureAnalyzer,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisJmsConnectionFailureAnalyzer,\
org.springframework.boot.autoconfigure.jms.hornetq.HornetQConnectFailureAnalyzer,\
org.springframework.boot.autoconfigure.jms.hornetq.HornetQDependencyExceptionAnalyzer,\
org.springframework.boot.autoconfigure.solr.SolrExceptionAnalyzer,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBeanNotAvailableAnalyzer,\
org.springframework.boot.cloud.CloudPlatformConnectorsFailureAnalyzer,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessorFailureAnalyzer,\
org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessorChecker,\
org.springframework.boot.devtools.autoconfigure.DevToolsMissingFilterFailureAnalyzer,\
org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration$LocalDevToolsFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideAnalyzer,\
org.springframework.boot.diagnostics.analyzer.IllegalComponentScanFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidEmbeddedServletContainerConfigurationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidTemplateAvailabilityProviderAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NonCompatibleConfigurationClassFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.SingleConstructorInjectionAnalyzer

当应用程序启动失败时,Spring Boot会自动触发这个机制,尝试识别和处理启动失败的原因,并提供有用的诊断信息和解决方案。

三、为什么可能需要自定义FailureAnalyzer

当然,如果有需要的话,我们可以自定义FailureAnalyzer来更灵活地处理应用程序启动失败的情况,提供更精准的故障诊断和解决方案等,特别是针对做基础架构的同学。

理由说明
特定错误情况处理

默认的FailureAnalyzer无法准确识别或处理特定的错误情况。通过自定义可以针对这些特定的错误情况编写定制化的诊断逻辑,提供更精准的故障诊断和解决方案。

额外的诊断信息

默认的FailureAnalyzer只提供基本的诊断信息,但在某些情况下,可能需要更多的详细信息来准确诊断问题。通过自定义可添加额外的诊断逻辑,收集更多有用的信息来更好地理解问题。

集成外部系统应用程序与外部系统集成,而启动失败可能是由于与这些外部系统的交互出现问题所致。通过自定义可以集成额外的逻辑,例如调用外部API或检查外部系统的状态,以诊断和解决与外部系统相关的问题。
定制化的解决方案某些错误情况需要特定的解决方案,通过自定义可以根据应用程序的特定需求或约束,提供定制化的解决方案,以更好地满足应用程序的需求。

四、实现自定义基本步骤

(一)完整步骤要求

要实现自定义的FailureAnalyzer,我们需要完成以下步骤:

  1. 自定义异常,并创建检查要求规定。
  2. 创建一个类并实现AbstractFailureAnalyzer接口,重写analyze()方法,用于分析异常并返回FailureAnalysis对象。
  3. 将自定义的FailureAnalyzer类注册到Spring Boot应用程序中。

注意在 Spring Boot 应用程序中,自定义的多个失败分析器在实现上没有固定的先后次序。当应用程序启动时,Spring Boot 会自动扫描并注册所有的失败分析器,然后按照它们的类名顺序进行调用。这意味着,无论你如何组织和编写你的失败分析器类,它们都将在应用程序启动时同时注册,并且没有先后次序。

(二)注册方式说明

要让自定义的FailureAnalyzer生效注册到Spring Boot应用程序中,一般有两种方法:

通过Spring Boot的spring.factories文件(建议方式)

  1. src/main/resources目录下创建一个名为META-INF/spring.factories的文件(如果已存在则跳过此步骤)。
  2. spring.factories文件中添加用于实现的自定义FailureAnalyzer类,和上文中展示的spring.factories文件中的格式一样。

在启动类中手动注册(本人不建议)

在Spring Boot应用程序的启动类(@SpringBootApplication)中手动注册FailureAnalyzer

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(ZYFApplication.class);
        application.addListeners(new ConfigFileFailureAnalyzer());
        application.run(args);
    }

后续列举一些案例,但是情况请依据实际项目需求来定。我一般是以上面建议方式进行写的注册。

五、实现自定义举例

假设我们的应用程序在启动时需要加载某些特定的配置文件,但如果对应配置文件不存在将导致应用程序启动失败。默认的FailureAnalyzer可能无法准确地识别或处理这种特定情况,因此我们可以自定义一个FailureAnalyzer来处理这种特定的错误情况。

首先定义必要文件未找到异常如下:

package org.zyf.javabasic.spring.failureanalyzer.exception;

/**
 * @program: zyfboot-javabasic
 * @description: ConfigFileNotFoundException
 * @author: zhangyanfeng
 * @create: 2024-05-02 17:25
 **/
public class ConfigFileNotFoundException extends RuntimeException {

    private final String fileNames;

    public ConfigFileNotFoundException(String fileNames) {
        super("Configuration file '" + fileNames + "' not found");
        this.fileNames = fileNames;
    }

    public String getFileNames() {
        return fileNames;
    }
}

接着创建检查类对我们系统要求的必要文件作出基本的检查并返回要求文件异常基本信息:

package org.zyf.javabasic.spring.failureanalyzer.checker;

import com.google.common.collect.Lists;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;
import org.zyf.javabasic.spring.failureanalyzer.exception.ConfigFileNotFoundException;

import javax.annotation.PostConstruct;
import java.util.List;

/**
 * @program: zyfboot-javabasic
 * @description: 系统必要配置文件检查
 * @author: zhangyanfeng
 * @create: 2024-05-02 18:14
 **/
@Component
public class ConfigFileNotFoundChecker {

    private final ResourceLoader resourceLoader;

    public ConfigFileNotFoundChecker(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    public boolean exists(String fileName) {
        Resource resource = resourceLoader.getResource("classpath:" + fileName);
        return resource.exists();
    }

    @PostConstruct
    public void checkConfigFiles() throws ConfigFileNotFoundException {
        // 要检查的文件列表
        List<String> filesToCheck = Lists.newArrayList();
        filesToCheck.add("application.yml");
        filesToCheck.add("zyf_application_context.xml");
        filesToCheck.add("report-config.xml");
        filesToCheck.add("urlzyf.properties");

        // 存储不存在的文件名
        List<String> notFoundFiles = Lists.newArrayList();

        // 检查每个文件是否存在
        for (String fileName : filesToCheck) {
            if (!exists(fileName)) {
                notFoundFiles.add(fileName);
            }
        }

        // 如果存在未找到的文件,则抛出异常
        if (!notFoundFiles.isEmpty()) {
            throw new ConfigFileNotFoundException(notFoundFiles.toString());
        }
    }
}

接着创建并实现AbstractFailureAnalyzer,重写analyze()方法如下:

package org.zyf.javabasic.spring.failureanalyzer.analyzer;

import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
import org.springframework.boot.diagnostics.FailureAnalysis;
import org.zyf.javabasic.spring.failureanalyzer.exception.ConfigFileNotFoundException;
import org.zyf.javabasic.spring.failureanalyzer.exception.RequiredPropertyException;

/**
 * @program: zyfboot-javabasic
 * @description: 检查必要文件是否存在异常
 * @author: zhangyanfeng
 * @create: 2024-05-02 18:26
 **/
public class ZYFConfigFileFailureAnalyzer extends AbstractFailureAnalyzer<ConfigFileNotFoundException> {
    @Override
    protected FailureAnalysis analyze(Throwable rootFailure, ConfigFileNotFoundException cause) {
        String description = description(cause);
        String action = action(cause);
        return new FailureAnalysis(description, action, cause);
    }

    private String description(ConfigFileNotFoundException ex) {
        return String.format("Failed to load configuration file '%s'.", ex.getFileNames());
    }

    private String action(ConfigFileNotFoundException ex) {
        return String.format("Check if the configuration file:'%s' exists.", ex.getFileNames());
    }
}

spring.factories中增加本次新增验证:

org.springframework.boot.diagnostics.FailureAnalyzer=\
org.zyf.javabasic.spring.failureanalyzer.analyzer.ZYFConfigFileFailureAnalyzer

现在其中本地未创建ourlzyf.properties文件,故程序启动报错如下:

符合我们的预期。

接着如果要求针对报告配置文件 report-config.xml 中必须包含数据库连接信息和报告生成器的情况,并要求有更加详细和严格的配置文件格式验证,接着我们继续定义一个异常类且需要指明异常情况。

先定义一个这种类型返回的基本配置错误信息如下:

package org.zyf.javabasic.spring.failureanalyzer.model;

/**
 * @program: zyfboot-javabasic
 * @description: 表示不同的错误类型,例如缺少必要属性、属性值格式错误等
 * @author: zhangyanfeng
 * @create: 2024-05-02 19:57
 **/
public class ConfigFileFormatErrorInfo {
    private final boolean fileNotFound;
    private final ErrorType errorType;
    private final String fileName;

    public ConfigFileFormatErrorInfo(boolean fileNotFound, ErrorType errorType, String fileName) {
        this.fileNotFound = fileNotFound;
        this.errorType = errorType;
        this.fileName = fileName;
    }

    public boolean isFileNotFound() {
        return fileNotFound;
    }

    public ErrorType getErrorType() {
        return errorType;
    }

    public String getFileName() {
        return fileName;
    }

    public DescriptionAndAction getDescriptionAndAction() {
        String description;
        String action;

        if (fileNotFound) {
            description = "Configuration file '" + fileName + "' not found";
            action = "Check if the configuration file exists.";
        } else {
            switch (errorType) {
                case MISSING_PROPERTY:
                    description = "Missing required property in configuration file '" + fileName + "'";
                    action = "Ensure all required properties are provided in the configuration file.";
                    break;
                case INVALID_VALUE:
                    description = "Invalid value for property in configuration file '" + fileName + "'";
                    action = "Correct the value of the property in the configuration file.";
                    break;
                case OTHER:
                default:
                    description = "Other configuration file format error in file '" + fileName + "'";
                    action = "Review the configuration file for formatting issues.";
                    break;
            }
        }

        return new DescriptionAndAction(description, action);
    }

    public enum ErrorType {
        MISSING_PROPERTY,
        INVALID_VALUE,
        OTHER
    }
}


package org.zyf.javabasic.spring.failureanalyzer.model;

/**
 * @program: zyfboot-javabasic
 * @description: DescriptionAndAction
 * @author: zhangyanfeng
 * @create: 2024-05-02 20:19
 **/
public class DescriptionAndAction {
    private final String description;
    private final String action;

    public DescriptionAndAction(String description, String action) {
        this.description = description;
        this.action = action;
    }

    public String getDescription() {
        return description;
    }

    public String getAction() {
        return action;
    }
}

然后定义基本的异常信息如下:

package org.zyf.javabasic.spring.failureanalyzer.exception;

import com.alibaba.fastjson.JSON;
import org.zyf.javabasic.spring.failureanalyzer.model.ConfigFileFormatErrorInfo;

/**
 * @program: zyfboot-javabasic
 * @description: 配置文件格式问题异常
 * @author: zhangyanfeng
 * @create: 2024-05-02 19:23
 **/
public class ConfigFileFormatException extends RuntimeException {

    private final ConfigFileFormatErrorInfo errorInfo;

    public ConfigFileFormatException(ConfigFileFormatErrorInfo errorInfo) {
        super("Configuration file format error: " + JSON.toJSONString(errorInfo));
        this.errorInfo = errorInfo;
    }

    public ConfigFileFormatErrorInfo getErrorInfo() {
        return errorInfo;
    }

}

检查指定的配置文件(report-config.xml)是否符合预期的格式要求:

  1. 必须包含一个名为 "dataSource" 的 Bean 定义,用于配置数据库连接信息。
  2. "dataSource" Bean 中必须包含以下属性:driverClassName:数据库驱动类名;url:数据库连接 URL;username:数据库用户名;password:数据库密码。
  3. password 属性必须已加密,即以特定字符串开头。
  4. 必须包含一个名为 "reportGenerator" 的 Bean 定义,用于配置报告生成器。
  5. "reportGenerator" Bean 中必须包含一个名为 dataSource 的属性引用,指向之前定义的 "dataSource" Bean。

如果配置文件不符合上述要求之一,就会抛出相应的异常,指示配置文件格式错误。具体对应的检查实现如下:

package org.zyf.javabasic.spring.failureanalyzer.checker;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.zyf.javabasic.spring.failureanalyzer.exception.ConfigFileFormatException;
import org.zyf.javabasic.spring.failureanalyzer.model.ConfigFileFormatErrorInfo;

import javax.annotation.PostConstruct;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;

import static org.zyf.javabasic.spring.failureanalyzer.model.ConfigFileFormatErrorInfo.ErrorType.*;

/**
 * @program: zyfboot-javabasic
 * @description: 指定配置文件验证逻辑
 * @author: zhangyanfeng
 * @create: 2024-05-02 20:12
 **/
@Component
public class ConfigFileFormatChecker {

    @Autowired
    private ResourceLoader resourceLoader;

    @PostConstruct
    public void checkConfigFileFormat() {
        String fileName = "report-config.xml";
        Resource resource = resourceLoader.getResource("classpath:" + fileName);

        if (!resource.exists()) {
            throw new ConfigFileFormatException(new ConfigFileFormatErrorInfo(true, null, fileName));
        }

        Element root = null;
        try (InputStream inputStream = resource.getInputStream()) {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(new InputSource(inputStream));

            // 获取根元素
            root = document.getDocumentElement();

        } catch (Exception e) {
            throw new ConfigFileFormatException(new ConfigFileFormatErrorInfo(true, OTHER, fileName));
        }

        // 检查 dataSource Bean 定义
        checkDataSourceDefinition(root, fileName);

        // 检查报告生成器定义
        checkReportGeneratorDefinition(root, fileName);
    }

    private void checkDataSourceDefinition(Element root, String fileName) {
        // 获取 dataSource 元素
        NodeList dataSourceList = root.getElementsByTagName("bean");
        for (int i = 0; i < dataSourceList.getLength(); i++) {
            Element dataSourceElement = (Element) dataSourceList.item(i);
            String id = dataSourceElement.getAttribute("id");
            if ("dataSource".equals(id)) {
                // 获取 driverClassName 属性
                String driverClassName = dataSourceElement.getElementsByTagName("property")
                        .item(0)
                        .getAttributes()
                        .getNamedItem("value")
                        .getNodeValue();

                // 获取 url 属性
                String url = dataSourceElement.getElementsByTagName("property")
                        .item(1)
                        .getAttributes()
                        .getNamedItem("value")
                        .getNodeValue();

                // 获取 username 属性
                String username = dataSourceElement.getElementsByTagName("property")
                        .item(2)
                        .getAttributes()
                        .getNamedItem("value")
                        .getNodeValue();

                // 获取 password 属性
                String password = dataSourceElement.getElementsByTagName("property")
                        .item(3)
                        .getAttributes()
                        .getNamedItem("value")
                        .getNodeValue();

                if (StringUtils.isAnyBlank(driverClassName, url, username, password)) {
                    throw new ConfigFileFormatException(new ConfigFileFormatErrorInfo(false, MISSING_PROPERTY, fileName));
                }

                if (!isPasswordEncrypted(password)) {
                    throw new ConfigFileFormatException(new ConfigFileFormatErrorInfo(false, INVALID_VALUE, fileName));
                }
            }
        }

    }

    private void checkReportGeneratorDefinition(Element root, String fileName) {
        // 获取 reportGenerator 元素
        NodeList reportGeneratorList = root.getElementsByTagName("bean");
        for (int i = 0; i < reportGeneratorList.getLength(); i++) {
            Element reportGeneratorElement = (Element) reportGeneratorList.item(i);
            String id = reportGeneratorElement.getAttribute("id");
            if ("reportGenerator".equals(id)) {
                // 获取 dataSource 属性的引用
                String dataSourceRef = reportGeneratorElement.getElementsByTagName("property")
                        .item(0)
                        .getAttributes()
                        .getNamedItem("ref")
                        .getNodeValue();
                if (StringUtils.isAnyBlank(dataSourceRef)) {
                    throw new ConfigFileFormatException(new ConfigFileFormatErrorInfo(false, MISSING_PROPERTY, fileName));
                }
            }
        }
    }

    private boolean isPasswordEncrypted(String password) {
        // 检查密码是否已加密,这里可以根据具体加密方式进行验证
        return password.startsWith("Zyf");
    }
}

接着创建并实现AbstractFailureAnalyzer,重写analyze()方法如下:

package org.zyf.javabasic.spring.failureanalyzer.analyzer;

import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
import org.springframework.boot.diagnostics.FailureAnalysis;
import org.zyf.javabasic.spring.failureanalyzer.exception.ConfigFileFormatException;
import org.zyf.javabasic.spring.failureanalyzer.model.ConfigFileFormatErrorInfo;
import org.zyf.javabasic.spring.failureanalyzer.model.DescriptionAndAction;

/**
 * @program: zyfboot-javabasic
 * @description: 指定配置文件具体格式要求
 * @author: zhangyanfeng
 * @create: 2024-05-02 20:31
 **/
public class ZYFConfigFileFormatFailureanalyzer extends AbstractFailureAnalyzer<ConfigFileFormatException> {
    @Override
    protected FailureAnalysis analyze(Throwable rootFailure, ConfigFileFormatException cause) {
        ConfigFileFormatErrorInfo errorInfo = cause.getErrorInfo();

        String description;
        String action;

        if (errorInfo.isFileNotFound()) {
            description = "Configuration file '" + errorInfo.getFileName() + "' not found";
            action = "Check if the configuration file exists.";
        } else {
            DescriptionAndAction descriptionAndAction = errorInfo.getDescriptionAndAction();

            description = descriptionAndAction.getDescription();
            action = descriptionAndAction.getAction();
        }

        return new FailureAnalysis(description, action, cause);
    }
}

spring.factories中增加本次新增验证:

org.springframework.boot.diagnostics.FailureAnalyzer=\
org.zyf.javabasic.spring.failureanalyzer.analyzer.ZYFConfigFileFailureAnalyzer,\
org.zyf.javabasic.spring.failureanalyzer.analyzer.ZYFConfigFileFormatFailureanalyzer

但是我实际report-config.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 数据库连接信息 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/zyf"/>
        <property name="username" value="root"/>
        <property name="password" value="Zsyf2014"/>
    </bean>

    <!-- 报告生成器 -->
    <bean id="reportGenerator" class="org.zyf.javabasic.spring.beanFactory.ReportGenerator">
        <property name="dataSource" ref="dataSource"/>
        <!-- 其他配置属性 -->
    </bean>
</beans>

由于数据库加密不正确,故程序启动报错如下:

六、一些建议

如果确定了需要创建自定义的 FailureAnalyzer 时,必须有几个注意事项:

  • 确保 FailureAnalyzer 能够准确地识别失败的原因,避免误导性的诊断,帮助更快地找到并解决问题。
  • 在诊断中提供尽可能详细的信息,包括失败的具体原因、发生失败的位置等。
  • 提供清晰的建议或解决方案,可以包括修复代码、调整配置或执行其他操作的建议。

相关源码依旧在常用的github地址中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1639165.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java中的字符流

字符流字节流编码表 Java为什么可以区分字母和汉字 package day3; ​ import java.io.UnsupportedEncodingException; import java.lang.reflect.Array; import java.util.Arrays; ​ public class Test {public static void main(String[] args) throws UnsupportedEncoding…

文件批量高效管理,批量将PDF类型文件移动到指定文件夹里,实现文件高效管理

文件的管理与整理成为了我们生活中不可或缺的一部分。面对堆积如山的PDF文件&#xff0c;你是否也曾感到手足无措、焦头烂额&#xff1f;现在&#xff0c;有了我们的批量文件管理工具&#xff0c;PDF文件的管理将变得前所未有的高效与简单&#xff01; 首先&#xff0c;我们要…

用龙梦迷你电脑福珑2.0做web服务器

用龙梦迷你电脑福珑2.0上做web服务器是可行的。已将一个网站源码放到该电脑&#xff0c;在局域网里可以访问网站网页。另外通过在同一局域网内的一台windows10电脑上安装花生壳软件&#xff0c;也可以在外网访问该内网服务器网站网页。该电脑的操作系统属于LAMP。在该电脑上安装…

Android 开发部分基础工具使用

c调试 在NDK调试的时候&#xff0c;如果找不到 符号的话&#xff0c;我们可以在调试配置中添加符号地址的全路径一直到根目录&#xff1a;&#xff0c;xxx/armeabi-v7a&#xff1a; You must point the symbol search paths at the obj/local/ directory. This is also not a …

C++奇迹之旅:C++内存管理的机制初篇

文章目录 &#x1f4dd;C/C内存分布&#x1f320; C语言中动态内存管理方式&#x1f309;C内存管理方式 &#x1f320;new/delete操作内置类型&#x1f309;C与C链表构建对比 &#x1f6a9;总结 &#x1f4dd;C/C内存分布 这是C/C中程序内存区域划分图&#xff1a; 数据段&am…

基于springboot+vue+Mysql的网上商城购物系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

蓝桥杯练习系统(算法训练)ALGO-951 预备爷的悲剧

资源限制 内存限制&#xff1a;512.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 英语预备爷gzp是个逗(tu)比(hao)&#xff0c;为了在即将到来的英语的quiz中不挂科&#xff0c;gzp废寝忘食复习英语附录单词…

V23 中的新增功能:LEADTOOLS React Medical Web 查看器

LEADTOOLS (Lead Technology)由Moe Daher and Rich Little创建于1990年&#xff0c;其总部设在北卡罗来纳州夏洛特。LEAD的建立是为了使Daher先生在数码图象与压缩技术领域的发明面向市场。在过去超过30年的发展历程中&#xff0c;LEAD以其在全世界主要国家中占有的市场领导地位…

JUC常见类

背景 JUC是java.util.concurrent的简称&#xff0c;这个包里面存放的都是和多线程相关的类&#xff0c;在面试中非常的重要 目录 1.Callable接口 2.ReentrantLock 3.信号量Semaphore 4.CountDownLatch 5.集合的线程安全问题 1.Callable接口 1.1.认识Callable接口 &#x…

phpstudy 搭建 upload-labs 文件上传靶场

phpstudy 搭建靶场&#xff1a;下载安装好phpstudy后&#xff0c;下载靶场源码&#xff1a; upload-labs下载地址&#xff1a; https://github.com/c0ny1/upload-labs 下载完压缩文件&#xff0c;解压文件&#xff0c;解压后的文件夹命名为upload--labs 将解压后到文件夹放…

爱普生晶振在物联网LoRa通讯中的应用

LoRa 是LPWAN通信技术中的一种&#xff0c;是美国Semtech公司采用和推广的一种基于扩频技术的超远距离无线传输方案。这一方案改变了以往关于传输距离与功耗的折衷考虑方式&#xff0c;为用户提供一种简单的能实现远距离、长电池寿命、大容量的系统&#xff0c;进而扩展传感网络…

频分复用系统设计及其MATLAB实现

引言 随着通信技术的飞速发展&#xff0c;通信系统的容量需求不断增长。频分复用&#xff08;Frequency Division Multiplexing, FDM&#xff09;作为一种重要的多路复用技术&#xff0c;被广泛应用于现代通信系统中。本文将介绍频分复用系统的设计原理&#xff0c;并展示如何…

springboot 自动配置源码解读

什么是自动装配 当我们程序依赖第三方功能组件时&#xff0c;不需要手动将这些组件类加载到IOC容器中。例如 当程序需要用到redis时&#xff0c;在pom.xml文件中引入依赖&#xff0c;然后使用依赖注入的方式直接从IOC容器中拿到相应RedisTemplate实例。 SpringBootApplication …

cuda非root用户安装及mamba库安装报错问题

1、先检查是不是cuda版本的问题&#xff08;cuda≥11.6&#xff09; 非root用户安装指南&#xff1a; &#xff08;1&#xff09;先去NVIDIA官网CUDA Toolkit Archive | NVIDIA Developer 选一个版本 查看architecture的命令 uname -m 查看version的命令 lsb_release -a 下…

探索AIGC技术:创新、挑战与责任

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f4d5;格言&#xff1a;那些在暗处执拗生长的花&#xff0c;终有一日会馥郁传香欢迎大家&#x1f44d;点赞✍评论⭐收藏 #如何看待AIGC技术&#xff1f; 目录 AIGC简单介绍 创新 责任 未来展望和挑战 AIGC简单介绍 A…

34.基础乐理-简谱需要移调吗?

首先需要具备 首调 与 固定调的知识&#xff0c;才能理解&#xff0c;以两只老虎为例子&#xff0c;如下图&#xff1a; 首调&#xff1a;可以看到C大调、D大调、E大调三种方式的乐谱&#xff0c;记录的数字&#xff0c;记录的唱名&#xff0c;都是1231&#xff0c;唯一不同的…

深度学习中的归一化:BN,LN,IN,GN的优缺点

目录 深度学习中归一化的作用常见归一化的优缺点 深度学习中归一化的作用 加速训练过程 归一化可以加速深度学习模型的训练过程。通过调整输入数据的尺度&#xff0c;归一化有助于改善优化算法的收敛速度。这是因为归一化后的数据具有相似的尺度&#xff0c;使得梯度下降等优化…

开源框架 NanUI 项目宣布将暂停开发,作者转行卖钢材

NanUI 界面组件是一个开源的 .NET 窗体应用程序界面框架&#xff0c;适用于希望使用 HTML5 / CSS3 等前端技术来构建 Windows 窗体应用程序用户界面的 .NET 开发人员。 该项目的作者林选臣日前在 GitHub 上发布了停更公告&#xff0c;称因去年被裁员失业&#xff0c;他目前已经…

VBA技术资料MF147:从Excel运行PowerPoint演示文稿

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

毫米波雷达多人呼吸心跳检测MATLAB仿真

本文基于TI的IWR1642毫米波雷达 2T4R MIMO阵列&#xff0c;通过实际采集数据算法仿真&#xff0c;实现多人呼吸心跳检测。 文章末尾给出了本文的仿真代码。 主要内容包含&#xff1a; &#xff08;1&#xff09;雷达参数设定 &#xff08;2&#xff09;ADC数据导入 &#xff08…