当前位置: 代码网 > it编程>编程语言>Java > Spring Boot 自动配置原理实现机制深度解析(实战示例)

Spring Boot 自动配置原理实现机制深度解析(实战示例)

2025年10月19日 Java 我要评论
本文深入剖析 spring boot 自动配置的实现原理,从核心注解到完整流程,包含详细源码分析和实战示例。1. 自动配置概述1.1 什么是自动配置?spring boot 自动配置是其最重要的特性之

本文深入剖析 spring boot 自动配置的实现原理,从核心注解到完整流程,包含详细源码分析和实战示例。

1. 自动配置概述

1.1 什么是自动配置?

spring boot 自动配置是其最重要的特性之一,它尝试根据添加的 jar 依赖自动配置 spring 应用程序。简单来说,就是约定优于配置理念的具体实现。

传统 spring 配置:

@configuration
public class manualdatasourceconfig {
    @bean
    public datasource datasource() {
        drivermanagerdatasource datasource = new drivermanagerdatasource();
        datasource.setdriverclassname("com.mysql.cj.jdbc.driver");
        datasource.seturl("jdbc:mysql://localhost:3306/test");
        datasource.setusername("root");
        datasource.setpassword("password");
        return datasource;
    }
    @bean
    public jdbctemplate jdbctemplate(datasource datasource) {
        return new jdbctemplate(datasource);
    }
}

spring boot 自动配置:

// 只需在 application.properties 中配置
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=password
// spring boot 自动创建 datasource 和 jdbctemplate

1.2 自动配置的优势

  • 快速启动:减少样板代码配置
  • 智能默认值:提供合理的默认配置
  • 灵活覆盖:可轻松自定义配置
  • 条件化装配:根据条件智能启用配置

2. 自动配置核心原理

2.1 核心注解 @springbootapplication

让我们从启动类开始分析:

@springbootapplication
public class application {
    public static void main(string[] args) {
        springapplication.run(application.class, args);
    }
}

@springbootapplication 源码分析:

@target(elementtype.type)
@retention(retentionpolicy.runtime)
@documented
@inherited
@springbootconfiguration
@enableautoconfiguration  // 关键注解
@componentscan(excludefilters = { 
    @filter(type = filtertype.custom, classes = typeexcludefilter.class),
    @filter(type = filtertype.custom, classes = autoconfigurationexcludefilter.class) 
})
public @interface springbootapplication {
    // ...
}

2.2 @enableautoconfiguration 注解

这是自动配置的入口点:

@target(elementtype.type)
@retention(retentionpolicy.runtime)
@documented
@inherited
@autoconfigurationpackage
@import(autoconfigurationimportselector.class)  // 核心导入
public @interface enableautoconfiguration {
    // ...
}

2.3 autoconfigurationimportselector 类

这是自动配置的核心处理器:

public class autoconfigurationimportselector implements deferredimportselector, beanclassloaderaware, resourceloaderaware, beanfactoryaware, environmentaware, ordered {
    @override
    public string[] selectimports(annotationmetadata annotationmetadata) {
        if (!isenabled(annotationmetadata)) {
            return no_imports;
        }
        // 获取自动配置入口
        autoconfigurationentry autoconfigurationentry = getautoconfigurationentry(annotationmetadata);
        return stringutils.tostringarray(autoconfigurationentry.getconfigurations());
    }
    protected autoconfigurationentry getautoconfigurationentry(annotationmetadata annotationmetadata) {
        // 获取所有配置类
        list<string> configurations = getcandidateconfigurations(annotationmetadata, attributes);
        configurations = removeduplicates(configurations);
        set<string> exclusions = getexclusions(annotationmetadata, attributes);
        checkexcludedclasses(configurations, exclusions);
        configurations.removeall(exclusions);
        configurations = getconfigurationclassfilter().filter(configurations);
        fireautoconfigurationimportevents(configurations, exclusions);
        return new autoconfigurationentry(configurations, exclusions);
    }
    protected list<string> getcandidateconfigurations(annotationmetadata metadata, annotationattributes attributes) {
        // 从 meta-inf/spring.factories 加载配置
        list<string> configurations = springfactoriesloader.loadfactorynames(getspringfactoriesloaderfactoryclass(), getbeanclassloader());
        return configurations;
    }
    protected class<?> getspringfactoriesloaderfactoryclass() {
        return enableautoconfiguration.class;
    }
}

3. 自动配置加载机制

3.1 spring.factories 文件

spring boot 在 spring-boot-autoconfigure jar 包的 meta-inf/spring.factories 文件中定义了大量的自动配置类:

# auto configure
org.springframework.boot.autoconfigure.enableautoconfiguration=\
org.springframework.boot.autoconfigure.admin.springapplicationadminjmxautoconfiguration,\
org.springframework.boot.autoconfigure.aop.aopautoconfiguration,\
org.springframework.boot.autoconfigure.amqp.rabbitautoconfiguration,\
org.springframework.boot.autoconfigure.batch.batchautoconfiguration,\
org.springframework.boot.autoconfigure.cache.cacheautoconfiguration,\
org.springframework.boot.autoconfigure.cassandra.cassandraautoconfiguration,\
org.springframework.boot.autoconfigure.context.configurationpropertiesautoconfiguration,\
org.springframework.boot.autoconfigure.context.messagesourceautoconfiguration,\
org.springframework.boot.autoconfigure.context.propertyplaceholderautoconfiguration,\
org.springframework.boot.autoconfigure.couchbase.couchbaseautoconfiguration,\
org.springframework.boot.autoconfigure.dao.persistenceexceptiontranslationautoconfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.cassandradataautoconfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.cassandrareactivedataautoconfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.couchbasedataautoconfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.elasticsearchdataautoconfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.elasticsearchrepositoriesautoconfiguration,\
org.springframework.boot.autoconfigure.data.jdbc.jdbcrepositoriesautoconfiguration,\
org.springframework.boot.autoconfigure.data.jpa.jparepositoriesautoconfiguration,\
org.springframework.boot.autoconfigure.data.ldap.ldaprepositoriesautoconfiguration,\
org.springframework.boot.autoconfigure.data.mongo.mongodataautoconfiguration,\
org.springframework.boot.autoconfigure.data.mongo.mongoreactivedataautoconfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.neo4jdataautoconfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.neo4jrepositoriesautoconfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.r2dbcdataautoconfiguration,\
org.springframework.boot.autoconfigure.data.redis.redisautoconfiguration,\
org.springframework.boot.autoconfigure.data.redis.redisreactiveautoconfiguration,\
org.springframework.boot.autoconfigure.data.redis.redisrepositoriesautoconfiguration,\
org.springframework.boot.autoconfigure.data.rest.repositoryrestmvcautoconfiguration,\
org.springframework.boot.autoconfigure.data.web.springdatawebautoconfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.elasticsearchrestclientautoconfiguration,\
org.springframework.boot.autoconfigure.flyway.flywayautoconfiguration,\
org.springframework.boot.autoconfigure.freemarker.freemarkerautoconfiguration,\
org.springframework.boot.autoconfigure.groovy.template.groovytemplateautoconfiguration,\
org.springframework.boot.autoconfigure.gson.gsonautoconfiguration,\
org.springframework.boot.autoconfigure.h2.h2consoleautoconfiguration,\
org.springframework.boot.autoconfigure.hateoas.hypermediaautoconfiguration,\
org.springframework.boot.autoconfigure.hazelcast.hazelcastautoconfiguration,\
org.springframework.boot.autoconfigure.hazelcast.hazelcastjpadependencyautoconfiguration,\
org.springframework.boot.autoconfigure.http.httpmessageconvertersautoconfiguration,\
org.springframework.boot.autoconfigure.http.codec.codecsautoconfiguration,\
org.springframework.boot.autoconfigure.influx.influxdbautoconfiguration,\
org.springframework.boot.autoconfigure.info.projectinfoautoconfiguration,\
org.springframework.boot.autoconfigure.integration.integrationautoconfiguration,\
org.springframework.boot.autoconfigure.jackson.jacksonautoconfiguration,\
org.springframework.boot.autoconfigure.jdbc.datasourceautoconfiguration,\
org.springframework.boot.autoconfigure.jdbc.jdbctemplateautoconfiguration,\
org.springframework.boot.autoconfigure.jdbc.jndidatasourceautoconfiguration,\
org.springframework.boot.autoconfigure.jdbc.xadatasourceautoconfiguration,\
org.springframework.boot.autoconfigure.jdbc.datasourcetransactionmanagerautoconfiguration,\
org.springframework.boot.autoconfigure.jms.jmsautoconfiguration,\
org.springframework.boot.autoconfigure.jmx.jmxautoconfiguration,\
org.springframework.boot.autoconfigure.jms.jndiconnectionfactoryautoconfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.activemqautoconfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.artemisautoconfiguration,\
org.springframework.boot.autoconfigure.kafka.kafkaautoconfiguration,\
org.springframework.boot.autoconfigure.availability.applicationavailabilityautoconfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.embeddedldapautoconfiguration,\
org.springframework.boot.autoconfigure.ldap.ldapautoconfiguration,\
org.springframework.boot.autoconfigure.liquibase.liquibaseautoconfiguration,\
org.springframework.boot.autoconfigure.mail.mailsenderautoconfiguration,\
org.springframework.boot.autoconfigure.mail.mailsendervalidatorautoconfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.embeddedmongoautoconfiguration,\
org.springframework.boot.autoconfigure.mongo.mongoautoconfiguration,\
org.springframework.boot.autoconfigure.mongo.mongoreactiveautoconfiguration,\
org.springframework.boot.autoconfigure.mustache.mustacheautoconfiguration,\
org.springframework.boot.autoconfigure.neo4j.neo4jautoconfiguration,\
org.springframework.boot.autoconfigure.netty.nettyautoconfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.hibernatejpaautoconfiguration,\
org.springframework.boot.autoconfigure.quartz.quartzautoconfiguration,\
org.springframework.boot.autoconfigure.r2dbc.r2dbcautoconfiguration,\
org.springframework.boot.autoconfigure.rsocket.rsocketmessagingautoconfiguration,\
org.springframework.boot.autoconfigure.rsocket.rsocketrequesterautoconfiguration,\
org.springframework.boot.autoconfigure.rsocket.rsocketserverautoconfiguration,\
org.springframework.boot.autoconfigure.rsocket.rsocketstrategiesautoconfiguration,\
org.springframework.boot.autoconfigure.security.servlet.securityautoconfiguration,\
org.springframework.boot.autoconfigure.security.servlet.userdetailsserviceautoconfiguration,\
org.springframework.boot.autoconfigure.security.servlet.securityfilterautoconfiguration,\
org.springframework.boot.autoconfigure.security.reactive.reactivesecurityautoconfiguration,\
org.springframework.boot.autoconfigure.security.reactive.reactiveuserdetailsserviceautoconfiguration,\
org.springframework.boot.autoconfigure.security.rsocket.rsocketsecurityautoconfiguration,\
org.springframework.boot.autoconfigure.security.saml2.saml2relyingpartyautoconfiguration,\
org.springframework.boot.autoconfigure.sendgrid.sendgridautoconfiguration,\
org.springframework.boot.autoconfigure.session.sessionautoconfiguration,\
org.springframework.boot.autoconfigure.sql.init.sqlinitializationautoconfiguration,\
org.springframework.boot.autoconfigure.ssl.sslautoconfiguration,\
org.springframework.boot.autoconfigure.task.taskexecutionautoconfiguration,\
org.springframework.boot.autoconfigure.task.taskschedulingautoconfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.thymeleafautoconfiguration,\
org.springframework.boot.autoconfigure.transaction.transactionautoconfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.jtaautoconfiguration,\
org.springframework.boot.autoconfigure.validation.validationautoconfiguration,\
org.springframework.boot.autoconfigure.web.client.resttemplateautoconfiguration,\
org.springframework.boot.autoconfigure.web.embedded.embeddedwebserverfactorycustomizerautoconfiguration,\
org.springframework.boot.autoconfigure.web.reactive.httphandlerautoconfiguration,\
org.springframework.boot.autoconfigure.web.reactive.reactivewebserverfactoryautoconfiguration,\
org.springframework.boot.autoconfigure.web.reactive.webfluxautoconfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.errorwebfluxautoconfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.clienthttpconnectorautoconfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.webclientautoconfiguration,\
org.springframework.boot.autoconfigure.web.servlet.dispatcherservletautoconfiguration,\
org.springframework.boot.autoconfigure.web.servlet.servletwebserverfactoryautoconfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.errormvcautoconfiguration,\
org.springframework.boot.autoconfigure.web.servlet.httpencodingautoconfiguration,\
org.springframework.boot.autoconfigure.web.servlet.multipartautoconfiguration,\
org.springframework.boot.autoconfigure.web.servlet.webmvcautoconfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.websocketreactiveautoconfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.websocketservletautoconfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.websocketmessagingautoconfiguration,\
org.springframework.boot.autoconfigure.webservices.webservicesautoconfiguration,\
org.springframework.boot.autoconfigure.webservices.client.webservicetemplateautoconfiguration

3.2 自动配置加载流程

graph td
    a[spring boot 启动] --> b[@springbootapplication]
    b --> c[@enableautoconfiguration]
    c --> d[autoconfigurationimportselector]
    d --> e[加载 spring.factories]
    e --> f[获取自动配置类列表]
    f --> g[条件注解过滤]
    g --> h[排除用户配置的类]
    h --> i[注册有效的配置类]
    i --> j[创建 bean 定义]
    j --> k[完成自动配置]
    subgraph 条件过滤
        g1[@conditionalonclass]
        g2[@conditionalonbean]
        g3[@conditionalonproperty]
        g4[@conditionalonmissingbean]
    end

4. 条件化配置详解

4.1 常用条件注解

spring boot 提供了一系列条件注解来控制配置类的加载:

注解说明
@conditionalonclass类路径下存在指定类时生效
@conditionalonmissingclass类路径下不存在指定类时生效
@conditionalonbean容器中存在指定 bean 时生效
@conditionalonmissingbean容器中不存在指定 bean 时生效
@conditionalonproperty配置属性满足条件时生效
@conditionalonresource资源文件存在时生效
@conditionalonwebapplication是 web 应用时生效
@conditionalonnotwebapplication不是 web 应用时生效
@conditionalonexpressionspel 表达式为 true 时生效

4.2 datasource 自动配置示例

让我们分析 datasourceautoconfiguration 的实现:

@configuration(proxybeanmethods = false)
@conditionalonclass({ datasource.class, embeddeddatabasetype.class })
@conditionalonmissingbean(type = "io.r2dbc.spi.connectionfactory")
@enableconfigurationproperties(datasourceproperties.class)
@import({ datasourcepoolmetadataprovidersconfiguration.class, 
          datasourceinitializationconfiguration.class })
public class datasourceautoconfiguration {
    @configuration(proxybeanmethods = false)
    @conditional(embeddeddatabasecondition.class)
    @conditionalonmissingbean({ datasource.class, xadatasource.class })
    @import(embeddeddatasourceconfiguration.class)
    static class embeddeddatabaseconfiguration {
    }
    @configuration(proxybeanmethods = false)
    @conditional(pooleddatasourcecondition.class)
    @conditionalonmissingbean({ datasource.class, xadatasource.class })
    @import({ datasourceconfiguration.hikari.class, 
              datasourceconfiguration.tomcat.class,
              datasourceconfiguration.dbcp2.class, 
              datasourceconfiguration.generic.class,
              datasourcejmxconfiguration.class })
    protected static class pooleddatasourceconfiguration {
    }
    // 内部条件类
    static class pooleddatasourcecondition extends springbootcondition {
        // 条件判断逻辑
    }
}

4.3 自定义条件注解

我们也可以创建自定义条件注解:

// 自定义条件注解
@target({ elementtype.type, elementtype.method })
@retention(retentionpolicy.runtime)
@documented
@conditional(onproductioncondition.class)
public @interface conditionalonproduction {
}
// 条件判断逻辑
public class onproductioncondition implements condition {
    @override
    public boolean matches(conditioncontext context, annotatedtypemetadata metadata) {
        environment env = context.getenvironment();
        string profile = env.getproperty("spring.profiles.active");
        return "prod".equals(profile);
    }
}
// 使用自定义条件注解
@configuration
@conditionalonproduction
public class productionconfiguration {
    // 生产环境特有的配置
}

5. 自动配置实现实战

5.1 创建自定义 starter

让我们创建一个简单的邮件服务自动配置:

项目结构:

email-spring-boot-starter/
├── src/
│   └── main/
│       ├── java/
│       │   └── com/example/email/
│       │       ├── emailservice.java
│       │       ├── emailproperties.java
│       │       └── autoconfigure/
│       │           └── emailautoconfiguration.java
│       └── resources/
│           └── meta-inf/
│               └── spring.factories

emailservice.java:

public class emailservice {
    private final string host;
    private final int port;
    private final string username;
    private final string password;
    public emailservice(string host, int port, string username, string password) {
        this.host = host;
        this.port = port;
        this.username = username;
        this.password = password;
    }
    public void sendemail(string to, string subject, string content) {
        // 模拟发送邮件
        system.out.printf("发送邮件到: %s, 主题: %s, 内容: %s%n", to, subject, content);
        system.out.printf("使用服务器: %s:%d, 用户: %s%n", host, port, username);
    }
}

emailproperties.java:

@configurationproperties(prefix = "email")
public class emailproperties {
    private string host = "smtp.example.com";
    private int port = 25;
    private string username;
    private string password;
    private boolean enabled = true;
    // getters and setters
    public string gethost() { return host; }
    public void sethost(string host) { this.host = host; }
    public int getport() { return port; }
    public void setport(int port) { this.port = port; }
    public string getusername() { return username; }
    public void setusername(string username) { this.username = username; }
    public string getpassword() { return password; }
    public void setpassword(string password) { this.password = password; }
    public boolean isenabled() { return enabled; }
    public void setenabled(boolean enabled) { this.enabled = enabled; }
}

emailautoconfiguration.java:

@configuration
@conditionalonclass(emailservice.class)
@enableconfigurationproperties(emailproperties.class)
public class emailautoconfiguration {
    private final emailproperties properties;
    public emailautoconfiguration(emailproperties properties) {
        this.properties = properties;
    }
    @bean
    @conditionalonmissingbean
    @conditionalonproperty(prefix = "email", name = "enabled", havingvalue = "true", matchifmissing = true)
    public emailservice emailservice() {
        return new emailservice(
            properties.gethost(),
            properties.getport(),
            properties.getusername(),
            properties.getpassword()
        );
    }
    @bean
    @conditionalonmissingbean
    public emailcontroller emailcontroller(emailservice emailservice) {
        return new emailcontroller(emailservice);
    }
}

emailcontroller.java:

public class emailcontroller {
    private final emailservice emailservice;
    public emailcontroller(emailservice emailservice) {
        this.emailservice = emailservice;
    }
    public void sendwelcomeemail(string email) {
        emailservice.sendemail(email, "欢迎", "欢迎使用我们的服务!");
    }
}

spring.factories:

# auto configure
org.springframework.boot.autoconfigure.enableautoconfiguration=\
com.example.email.autoconfigure.emailautoconfiguration

5.2 使用自定义 starter

在应用项目中引入 starter 依赖:

application.yml:

email:
  host: smtp.163.com
  port: 465
  username: your-email@163.com
  password: your-password
  enabled: true

使用示例:

@restcontroller
public class usercontroller {
    private final emailcontroller emailcontroller;
    public usercontroller(emailcontroller emailcontroller) {
        this.emailcontroller = emailcontroller;
    }
    @postmapping("/register")
    public string register(@requestparam string email) {
        // 用户注册逻辑
        emailcontroller.sendwelcomeemail(email);
        return "注册成功";
    }
}

6. 自动配置高级特性

6.1 配置顺序控制

使用 @autoconfigureafter@autoconfigurebefore 控制配置顺序:

@configuration
@autoconfigureafter(datasourceautoconfiguration.class)
@autoconfigurebefore(transactionautoconfiguration.class)
public class mycustomautoconfiguration {
    // 这个配置会在 datasource 配置之后,事务配置之前执行
}

6.2 条件配置的复杂逻辑

@configuration
@conditionalonclass({ datasource.class, jdbctemplate.class })
@conditionalonsinglecandidate(datasource.class)
@conditionalonproperty(prefix = "app.feature", name = "enabled", havingvalue = "true")
public class complexconditionconfiguration {
    @bean
    @conditionalonmissingbean
    public myrepository myrepository(jdbctemplate jdbctemplate) {
        return new myrepository(jdbctemplate);
    }
    static class myrepository {
        private final jdbctemplate jdbctemplate;
        public myrepository(jdbctemplate jdbctemplate) {
            this.jdbctemplate = jdbctemplate;
        }
        // 数据访问方法
    }
}

6.3 使用 @conditionalonexpression

@configuration
@conditionalonexpression(
    "${app.feature.enabled:false} && " +
    "t(org.springframework.util.stringutils).hastext('${app.feature.api-key:}')"
)
public class expressionconditionconfiguration {
    // 复杂的条件判断
}

7. 自动配置调试与优化

7.1 调试自动配置

启用调试日志:

# application.properties
debug=true

查看自动配置报告:
启动应用后,控制台会输出自动配置报告:

=========================
auto-configuration report
=========================
positive matches:
-----------------
   aopautoconfiguration matched:
      - @conditionalonclass found required classes 'org.springframework.context.annotation.enableaspectjautoproxy', ... (onclasscondition)
      - @conditionalonproperty (spring.aop.auto=true) matched (onpropertycondition)
   datasourceautoconfiguration matched:
      - @conditionalonclass found required classes 'javax.sql.datasource', ... (onclasscondition)
negative matches:
-----------------
   activemqautoconfiguration:
      did not match:
         - @conditionalonclass did not find required class 'javax.jms.connectionfactory' (onclasscondition)
exclusions:
-----------
    none

7.2 排除自动配置

方式1:使用注解排除

@springbootapplication(exclude = {
    datasourceautoconfiguration.class,
    mailsenderautoconfiguration.class
})
public class application {
    // ...
}

方式2:使用配置属性排除

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.datasourceautoconfiguration

7.3 性能优化建议

  1. 合理使用条件注解:避免不必要的条件检查
  2. 延迟初始化:使用 @lazy 注解
  3. 配置扫描路径:精确指定 @componentscan 路径
  4. 排除不必要的自动配置

8. 自动配置完整流程图

9. 总结

spring boot 自动配置是一个强大而灵活的特性,其核心原理包括:

  1. @enableautoconfiguration:自动配置的入口点
  2. spring.factories:自动配置类的注册机制
  3. 条件注解:智能的条件化配置决策
  4. 配置属性:外部化配置支持

通过理解自动配置的工作原理,我们可以:

  • 更好地使用 spring boot 提供的自动配置
  • 创建自己的 starter 和自动配置
  • 解决自动配置过程中的问题
  • 优化应用的启动性能

自动配置体现了 spring boot 的核心理念:约定优于配置,让开发者能够更专注于业务逻辑而不是框架配置。

参考资源

到此这篇关于spring boot 自动配置原理实现机制深度解析(实战示例)的文章就介绍到这了,更多相关spring boot 自动配置原理内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com