SpringBoot-03 | SpringBoot自动配置

SpringBoot-03 | SpringBoot自动配置

  • 原理分析
  • 代码示例
  • 源码剖析
    • @SpringBootConfiguration:组合注解,标记当前类为配置类
    • @ComponentScan
    • @EnableAutoConfiguration
      • @Import加载spring.factories
      • run初始化加载spring.factories
      • spring.factories中的钩子类

在这里插入图片描述
网上盗一个图,请call 666

原理分析

SpringBoot自动配置也使用到了SPI的思想。和JDK中的原理相同。

工具类不同:

  • JDK使用的工具类是ServiceLoader
  • SpringBoot中使用的类是SpringFactoriesLoader
    文件路径不同:
  • JDK配置在 META-INF/services文件夹,然后创建以接口全限定名为名字的文件,文件内容为实现类的全路径名
  • SpringBoot配置放在 META-INF/spring.factories中

代码示例

spring.factories

org.springframework.context.ApplicationListener=\
  com.tope365.config.profile.StandaloneProfileApplicationListener
org.springframework.boot.SpringApplicationRunListener=\
  com.tope365.config.profile.SpringApplicationRunListener
org.springframework.context.ApplicationContextInitializer=\
  com.tope365.config.profile.ApplicationUtils

**.ApplicationContextInitializer

package com.tope365.config.profile;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
/**
 * @author yewenhai
 */
@SuppressWarnings("all")
public class ApplicationUtils implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    private static ApplicationContext applicationContext;
    @Override
    public void initialize(ConfigurableApplicationContext context) {
        System.out.println("org.springframework.context.ApplicationContextInitializer  initialize...");
        applicationContext = context;
    }
}

**.SpringApplicationRunListener

package com.tope365.config.profile;

import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.event.EventPublishingRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import java.util.Collection;
/**
 * {@link org.springframework.boot.SpringApplicationRunListener} before {@link EventPublishingRunListener} execution.
 *
 * @author yewenhai
 * @since 0.2.2
 */
public class SpringApplicationRunListener implements org.springframework.boot.SpringApplicationRunListener, Ordered {
    
    private final SpringApplication application;
    
    private final String[] args;

    public SpringApplicationRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
    }
    
    @Override
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        System.out.println("org.springframework.boot.SpringApplicationRunListener  starting...");
    }
    
    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        System.out.println("org.springframework.boot.SpringApplicationRunListener  environmentPrepared...");
    }
    
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("org.springframework.boot.SpringApplicationRunListener  contextPrepared...");
    }
    
    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("org.springframework.boot.SpringApplicationRunListener  contextLoaded...");
    }
    
    @Override
    public void started(ConfigurableApplicationContext context) {
        System.out.println("org.springframework.boot.SpringApplicationRunListener  started...");
    }
    
    @Override
    public void running(ConfigurableApplicationContext context) {
        System.out.println("org.springframework.boot.SpringApplicationRunListener  running...");
    }
    
    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("org.springframework.boot.SpringApplicationRunListener  failed...");
    }
    
    /**
     * Before {@link EventPublishingRunListener}.
     *
     * @return HIGHEST_PRECEDENCE
     */
    @Override
    public int getOrder() {
        return HIGHEST_PRECEDENCE;
    }
}

**.ApplicationListener

package com.tope365.config.profile;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Profile;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.env.ConfigurableEnvironment;
import java.util.Arrays;

public class StandaloneProfileApplicationListener
        implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, PriorityOrdered {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(StandaloneProfileApplicationListener.class);
    String STANDALONE_MODE_PROPERTY_NAME = "standalone";
    String STANDALONE_SPRING_PROFILE = "standalone";
    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
        System.out.println("org.springframework.context.ApplicationListener  onApplicationEvent...");
        ConfigurableEnvironment environment = event.getEnvironment();
        if (environment.getProperty(STANDALONE_MODE_PROPERTY_NAME, boolean.class, false)) {
            environment.addActiveProfile(STANDALONE_SPRING_PROFILE);
        }
    }
    
    @Override
    public int getOrder() {
        return HIGHEST_PRECEDENCE;
    }
}

启动后输出:

F:\develop\jdk-17.0.9\bin\java.exe -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:64926,suspend=y,server=n -XX:TieredStopAtLevel=1 -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-Dmanagement.endpoints.jmx.exposure.include=*" -javaagent:C:\Users\Administrator\AppData\Local\JetBrains\IntelliJIdea2023.1\captureAgent\debugger-agent.jar=file:/C:/Users/Administrator/AppData/Local/Temp/capture1.props -Dfile.encoding=UTF-8 -classpath "F:\iframework\ai-coder\ai-java\web\target\classes;F:\iframework\ai-coder\ai-java\service\target\classes;F:\iframework\ai-coder\ai-java\api\target\classes;F:\iframework\ai-coder\ai-java\qdrant\http\target\classes;C:\.m2\repository\com\squareup\okhttp3\okhttp\4.11.0\okhttp-4.11.0.jar;C:\.m2\repository\com\squareup\okio\okio\3.2.0\okio-3.2.0.jar;C:\.m2\repository\com\squareup\okio\okio-jvm\3.2.0\okio-jvm-3.2.0.jar;C:\.m2\repository\org\jetbrains\kotlin\kotlin-stdlib\1.6.20\kotlin-stdlib-1.6.20.jar;C:\.m2\repository\org\jetbrains\kotlin\kotlin-stdlib-common\1.6.20\kotlin-stdlib-common-1.6.20.jar;C:\.m2\repository\org\jetbrains\annotations\13.0\annotations-13.0.jar;C:\.m2\repository\org\jetbrains\kotlin\kotlin-stdlib-jdk8\1.6.20\kotlin-stdlib-jdk8-1.6.20.jar;C:\.m2\repository\org\jetbrains\kotlin\kotlin-stdlib-jdk7\1.6.20\kotlin-stdlib-jdk7-1.6.20.jar;C:\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.15.0\jackson-databind-2.15.0.jar;F:\iframework\ai-coder\ai-java\qdrant\common\target\classes;C:\.m2\repository\org\springframework\retry\spring-retry\2.0.5\spring-retry-2.0.5.jar;C:\.m2\repository\org\aspectj\aspectjrt\1.9.7\aspectjrt-1.9.7.jar;C:\.m2\repository\org\aspectj\aspectjweaver\1.9.7\aspectjweaver-1.9.7.jar;C:\.m2\repository\org\apache\commons\commons-text\1.9\commons-text-1.9.jar;C:\.m2\repository\org\apache\commons\commons-lang3\3.11\commons-lang3-3.11.jar;C:\.m2\repository\com\huaban\jieba-analysis\1.0.2\jieba-analysis-1.0.2.jar;C:\.m2\repository\org\springframework\boot\spring-boot-starter-web\2.7.11\spring-boot-starter-web-2.7.11.jar;C:\.m2\repository\org\springframework\boot\spring-boot-starter\2.7.11\spring-boot-starter-2.7.11.jar;C:\.m2\repository\org\springframework\boot\spring-boot-starter-logging\2.7.11\spring-boot-starter-logging-2.7.11.jar;C:\.m2\repository\ch\qos\logback\logback-classic\1.2.12\logback-classic-1.2.12.jar;C:\.m2\repository\ch\qos\logback\logback-core\1.2.12\logback-core-1.2.12.jar;C:\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.17.2\log4j-to-slf4j-2.17.2.jar;C:\.m2\repository\org\apache\logging\log4j\log4j-api\2.17.2\log4j-api-2.17.2.jar;C:\.m2\repository\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;C:\.m2\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;C:\.m2\repository\org\springframework\spring-core\5.3.27\spring-core-5.3.27.jar;C:\.m2\repository\org\springframework\spring-jcl\5.3.27\spring-jcl-5.3.27.jar;C:\.m2\repository\org\yaml\snakeyaml\1.30\snakeyaml-1.30.jar;C:\.m2\repository\org\springframework\boot\spring-boot-starter-json\2.7.11\spring-boot-starter-json-2.7.11.jar;C:\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.5\jackson-datatype-jdk8-2.13.5.jar;C:\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.5\jackson-datatype-jsr310-2.13.5.jar;C:\.m2\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.5\jackson-module-parameter-names-2.13.5.jar;C:\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\2.7.11\spring-boot-starter-tomcat-2.7.11.jar;C:\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.74\tomcat-embed-core-9.0.74.jar;C:\.m2\repository\org\apache\tomcat\embed\tomcat-embed-el\9.0.74\tomcat-embed-el-9.0.74.jar;C:\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.74\tomcat-embed-websocket-9.0.74.jar;C:\.m2\repository\org\springframework\spring-web\5.3.27\spring-web-5.3.27.jar;C:\.m2\repository\org\springframework\spring-beans\5.3.27\spring-beans-5.3.27.jar;C:\.m2\repository\org\springframework\spring-webmvc\5.3.27\spring-webmvc-5.3.27.jar;C:\.m2\repository\org\springframework\spring-aop\5.3.27\spring-aop-5.3.27.jar;C:\.m2\repository\org\springframework\spring-context\5.3.27\spring-context-5.3.27.jar;C:\.m2\repository\org\springframework\spring-expression\5.3.27\spring-expression-5.3.27.jar;C:\.m2\repository\org\springframework\boot\spring-boot-starter-webflux\2.7.11\spring-boot-starter-webflux-2.7.11.jar;C:\.m2\repository\org\springframework\boot\spring-boot-starter-reactor-netty\2.7.11\spring-boot-starter-reactor-netty-2.7.11.jar;C:\.m2\repository\io\projectreactor\netty\reactor-netty-http\1.0.31\reactor-netty-http-1.0.31.jar;C:\.m2\repository\io\netty\netty-resolver-dns-native-macos\4.1.91.Final\netty-resolver-dns-native-macos-4.1.91.Final-osx-x86_64.jar;C:\.m2\repository\io\projectreactor\netty\reactor-netty-core\1.0.31\reactor-netty-core-1.0.31.jar;C:\.m2\repository\org\springframework\spring-webflux\5.3.27\spring-webflux-5.3.27.jar;C:\.m2\repository\org\springframework\boot\spring-boot-configuration-processor\2.7.11\spring-boot-configuration-processor-2.7.11.jar;C:\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.7.11\spring-boot-autoconfigure-2.7.11.jar;C:\.m2\repository\org\springframework\boot\spring-boot\2.7.11\spring-boot-2.7.11.jar;C:\.m2\repository\org\springframework\boot\spring-boot-starter-jdbc\2.7.11\spring-boot-starter-jdbc-2.7.11.jar;C:\.m2\repository\com\zaxxer\HikariCP\4.0.3\HikariCP-4.0.3.jar;C:\.m2\repository\org\springframework\spring-jdbc\5.3.27\spring-jdbc-5.3.27.jar;C:\.m2\repository\org\springframework\spring-tx\5.3.27\spring-tx-5.3.27.jar;C:\.m2\repository\mysql\mysql-connector-java\8.0.19\mysql-connector-java-8.0.19.jar;C:\.m2\repository\com\google\protobuf\protobuf-java\3.6.1\protobuf-java-3.6.1.jar;C:\.m2\repository\com\alibaba\druid-spring-boot-starter\1.1.10\druid-spring-boot-starter-1.1.10.jar;C:\.m2\repository\com\alibaba\druid\1.1.10\druid-1.1.10.jar;C:\.m2\repository\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;C:\.m2\repository\com\baomidou\mybatis-plus-boot-starter\3.4.1\mybatis-plus-boot-starter-3.4.1.jar;C:\.m2\repository\com\github\pagehelper\pagehelper-spring-boot-starter\1.3.0\pagehelper-spring-boot-starter-1.3.0.jar;C:\.m2\repository\org\mybatis\spring\boot\mybatis-spring-boot-starter\2.1.3\mybatis-spring-boot-starter-2.1.3.jar;C:\.m2\repository\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\2.1.3\mybatis-spring-boot-autoconfigure-2.1.3.jar;C:\.m2\repository\org\mybatis\mybatis\3.5.5\mybatis-3.5.5.jar;C:\.m2\repository\org\mybatis\mybatis-spring\2.0.5\mybatis-spring-2.0.5.jar;C:\.m2\repository\com\github\pagehelper\pagehelper-spring-boot-autoconfigure\1.3.0\pagehelper-spring-boot-autoconfigure-1.3.0.jar;C:\.m2\repository\com\github\pagehelper\pagehelper\5.2.0\pagehelper-5.2.0.jar;C:\.m2\repository\com\github\jsqlparser\jsqlparser\3.2\jsqlparser-3.2.jar;C:\.m2\repository\com\baomidou\mybatis-plus\3.4.1\mybatis-plus-3.4.1.jar;C:\.m2\repository\com\baomidou\mybatis-plus-extension\3.4.1\mybatis-plus-extension-3.4.1.jar;C:\.m2\repository\com\baomidou\mybatis-plus-core\3.4.1\mybatis-plus-core-3.4.1.jar;C:\.m2\repository\com\baomidou\mybatis-plus-annotation\3.4.1\mybatis-plus-annotation-3.4.1.jar;C:\.m2\repository\com\baomidou\mybatis-plus-generator\3.4.1\mybatis-plus-generator-3.4.1.jar;C:\.m2\repository\org\freemarker\freemarker\2.3.29\freemarker-2.3.29.jar;C:\.m2\repository\org\springframework\boot\spring-boot-starter-data-redis\2.7.11\spring-boot-starter-data-redis-2.7.11.jar;C:\.m2\repository\org\springframework\data\spring-data-redis\2.7.11\spring-data-redis-2.7.11.jar;C:\.m2\repository\org\springframework\data\spring-data-keyvalue\2.7.11\spring-data-keyvalue-2.7.11.jar;C:\.m2\repository\org\springframework\data\spring-data-commons\2.7.11\spring-data-commons-2.7.11.jar;C:\.m2\repository\org\springframework\spring-oxm\5.3.27\spring-oxm-5.3.27.jar;C:\.m2\repository\org\springframework\spring-context-support\5.3.27\spring-context-support-5.3.27.jar;C:\.m2\repository\io\lettuce\lettuce-core\6.1.10.RELEASE\lettuce-core-6.1.10.RELEASE.jar;C:\.m2\repository\org\redisson\redisson\3.27.0\redisson-3.27.0.jar;C:\.m2\repository\io\netty\netty-common\4.1.107.Final\netty-common-4.1.107.Final.jar;C:\.m2\repository\io\netty\netty-codec\4.1.107.Final\netty-codec-4.1.107.Final.jar;C:\.m2\repository\io\netty\netty-buffer\4.1.107.Final\netty-buffer-4.1.107.Final.jar;C:\.m2\repository\io\netty\netty-transport\4.1.107.Final\netty-transport-4.1.107.Final.jar;C:\.m2\repository\io\netty\netty-resolver\4.1.107.Final\netty-resolver-4.1.107.Final.jar;C:\.m2\repository\io\netty\netty-resolver-dns\4.1.107.Final\netty-resolver-dns-4.1.107.Final.jar;C:\.m2\repository\io\netty\netty-codec-dns\4.1.107.Final\netty-codec-dns-4.1.107.Final.jar;C:\.m2\repository\io\netty\netty-handler\4.1.107.Final\netty-handler-4.1.107.Final.jar;C:\.m2\repository\io\netty\netty-transport-native-unix-common\4.1.107.Final\netty-transport-native-unix-common-4.1.107.Final.jar;C:\.m2\repository\javax\cache\cache-api\1.1.1\cache-api-1.1.1.jar;C:\.m2\repository\io\projectreactor\reactor-core\3.6.2\reactor-core-3.6.2.jar;C:\.m2\repository\org\reactivestreams\reactive-streams\1.0.4\reactive-streams-1.0.4.jar;C:\.m2\repository\io\reactivex\rxjava3\rxjava\3.1.6\rxjava-3.1.6.jar;C:\.m2\repository\org\jboss\marshalling\jboss-marshalling\2.0.11.Final\jboss-marshalling-2.0.11.Final.jar;C:\.m2\repository\org\jboss\marshalling\jboss-marshalling-river\2.0.11.Final\jboss-marshalling-river-2.0.11.Final.jar;C:\.m2\repository\com\esotericsoftware\kryo\5.6.0\kryo-5.6.0.jar;C:\.m2\repository\com\esotericsoftware\reflectasm\1.11.9\reflectasm-1.11.9.jar;C:\.m2\repository\org\objenesis\objenesis\3.3\objenesis-3.3.jar;C:\.m2\repository\com\esotericsoftware\minlog\1.3.1\minlog-1.3.1.jar;C:\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.16.1\jackson-annotations-2.16.1.jar;C:\.m2\repository\com\fasterxml\jackson\dataformat\jackson-dataformat-yaml\2.16.1\jackson-dataformat-yaml-2.16.1.jar;C:\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.16.1\jackson-core-2.16.1.jar;C:\.m2\repository\net\bytebuddy\byte-buddy\1.14.5\byte-buddy-1.14.5.jar;C:\.m2\repository\org\jodd\jodd-bean\5.1.6\jodd-bean-5.1.6.jar;C:\.m2\repository\org\jodd\jodd-core\5.1.6\jodd-core-5.1.6.jar;C:\.m2\repository\org\eclipse\jgit\org.eclipse.jgit\5.13.2.202306221912-r\org.eclipse.jgit-5.13.2.202306221912-r.jar;C:\.m2\repository\com\googlecode\javaewah\JavaEWAH\1.1.13\JavaEWAH-1.1.13.jar;C:\.m2\repository\commons-io\commons-io\2.15.1\commons-io-2.15.1.jar;C:\.m2\repository\com\github\javaparser\javaparser-core\3.25.8\javaparser-core-3.25.8.jar;C:\.m2\repository\com\tope365\tope-netty-sdk-server\1.0.4-SNAPSHOT\tope-netty-sdk-server-1.0.4-SNAPSHOT.jar;C:\.m2\repository\com\tope365\tope-netty-sdk-common\1.0.4-SNAPSHOT\tope-netty-sdk-common-1.0.4-SNAPSHOT.jar;C:\.m2\repository\io\netty\netty-all\4.1.74.Final\netty-all-4.1.74.Final.jar;C:\.m2\repository\io\netty\netty-codec-haproxy\4.1.74.Final\netty-codec-haproxy-4.1.74.Final.jar;C:\.m2\repository\io\netty\netty-codec-memcache\4.1.74.Final\netty-codec-memcache-4.1.74.Final.jar;C:\.m2\repository\io\netty\netty-codec-mqtt\4.1.74.Final\netty-codec-mqtt-4.1.74.Final.jar;C:\.m2\repository\io\netty\netty-codec-redis\4.1.74.Final\netty-codec-redis-4.1.74.Final.jar;C:\.m2\repository\io\netty\netty-codec-smtp\4.1.74.Final\netty-codec-smtp-4.1.74.Final.jar;C:\.m2\repository\io\netty\netty-codec-socks\4.1.74.Final\netty-codec-socks-4.1.74.Final.jar;C:\.m2\repository\io\netty\netty-codec-stomp\4.1.74.Final\netty-codec-stomp-4.1.74.Final.jar;C:\.m2\repository\io\netty\netty-codec-xml\4.1.74.Final\netty-codec-xml-4.1.74.Final.jar;C:\.m2\repository\org\jctools\jctools-core\3.1.0\jctools-core-3.1.0.jar;C:\.m2\repository\io\netty\netty-tcnative-classes\2.0.48.Final\netty-tcnative-classes-2.0.48.Final.jar;C:\.m2\repository\io\netty\netty-transport-rxtx\4.1.74.Final\netty-transport-rxtx-4.1.74.Final.jar;C:\.m2\repository\io\netty\netty-transport-sctp\4.1.74.Final\netty-transport-sctp-4.1.74.Final.jar;C:\.m2\repository\io\netty\netty-transport-udt\4.1.74.Final\netty-transport-udt-4.1.74.Final.jar;C:\.m2\repository\io\netty\netty-transport-classes-epoll\4.1.74.Final\netty-transport-classes-epoll-4.1.74.Final.jar;C:\.m2\repository\io\netty\netty-transport-classes-kqueue\4.1.74.Final\netty-transport-classes-kqueue-4.1.74.Final.jar;C:\.m2\repository\io\netty\netty-resolver-dns-classes-macos\4.1.74.Final\netty-resolver-dns-classes-macos-4.1.74.Final.jar;C:\.m2\repository\com\google\code\gson\gson\2.8.6\gson-2.8.6.jar;C:\.m2\repository\cn\hutool\hutool-all\5.7.13\hutool-all-5.7.13.jar;C:\.m2\repository\commons-lang\commons-lang\2.6\commons-lang-2.6.jar;C:\.m2\repository\com\googlecode\protobuf-java-format\protobuf-java-format\1.2\protobuf-java-format-1.2.jar;C:\.m2\repository\org\reflections\reflections\0.9.12\reflections-0.9.12.jar;C:\.m2\repository\org\javassist\javassist\3.26.0-GA\javassist-3.26.0-GA.jar;C:\.m2\repository\com\auth0\java-jwt\3.3.0\java-jwt-3.3.0.jar;C:\.m2\repository\commons-codec\commons-codec\1.11\commons-codec-1.11.jar;C:\.m2\repository\com\squareup\retrofit2\retrofit\2.9.0\retrofit-2.9.0.jar;C:\.m2\repository\com\squareup\retrofit2\adapter-rxjava2\2.9.0\adapter-rxjava2-2.9.0.jar;C:\.m2\repository\io\reactivex\rxjava2\rxjava\2.0.0\rxjava-2.0.0.jar;C:\.m2\repository\com\squareup\retrofit2\converter-jackson\2.9.0\converter-jackson-2.9.0.jar;C:\.m2\repository\io\swagger\swagger-annotations\1.5.21\swagger-annotations-1.5.21.jar;C:\.m2\repository\io\swagger\swagger-models\1.5.21\swagger-models-1.5.21.jar;C:\.m2\repository\io\springfox\springfox-swagger2\2.9.2\springfox-swagger2-2.9.2.jar;C:\.m2\repository\io\springfox\springfox-spi\2.9.2\springfox-spi-2.9.2.jar;C:\.m2\repository\io\springfox\springfox-core\2.9.2\springfox-core-2.9.2.jar;C:\.m2\repository\io\springfox\springfox-schema\2.9.2\springfox-schema-2.9.2.jar;C:\.m2\repository\io\springfox\springfox-swagger-common\2.9.2\springfox-swagger-common-2.9.2.jar;C:\.m2\repository\io\springfox\springfox-spring-web\2.9.2\springfox-spring-web-2.9.2.jar;C:\.m2\repository\com\google\guava\guava\20.0\guava-20.0.jar;C:\.m2\repository\com\fasterxml\classmate\1.4.0\classmate-1.4.0.jar;C:\.m2\repository\org\springframework\plugin\spring-plugin-core\1.2.0.RELEASE\spring-plugin-core-1.2.0.RELEASE.jar;C:\.m2\repository\org\springframework\plugin\spring-plugin-metadata\1.2.0.RELEASE\spring-plugin-metadata-1.2.0.RELEASE.jar;C:\.m2\repository\org\mapstruct\mapstruct\1.2.0.Final\mapstruct-1.2.0.Final.jar;C:\.m2\repository\io\springfox\springfox-bean-validators\2.9.2\springfox-bean-validators-2.9.2.jar;C:\.m2\repository\io\springfox\springfox-swagger-ui\2.9.2\springfox-swagger-ui-2.9.2.jar;C:\.m2\repository\com\github\xiaoymin\swagger-bootstrap-ui\1.9.1\swagger-bootstrap-ui-1.9.1.jar;C:\.m2\repository\org\projectlombok\lombok\1.18.24\lombok-1.18.24.jar;C:\.m2\repository\org\jsoup\jsoup\1.14.3\jsoup-1.14.3.jar;C:\.m2\repository\org\json\json\20211205\json-20211205.jar;C:\.m2\repository\com\azure\azure-ai-openai\1.0.0-beta.6\azure-ai-openai-1.0.0-beta.6.jar;C:\.m2\repository\com\azure\azure-core\1.45.1\azure-core-1.45.1.jar;C:\.m2\repository\com\azure\azure-json\1.1.0\azure-json-1.1.0.jar;C:\.m2\repository\com\azure\azure-core-http-netty\1.13.11\azure-core-http-netty-1.13.11.jar;C:\.m2\repository\io\netty\netty-handler-proxy\4.1.101.Final\netty-handler-proxy-4.1.101.Final.jar;C:\.m2\repository\io\netty\netty-codec-http\4.1.101.Final\netty-codec-http-4.1.101.Final.jar;C:\.m2\repository\io\netty\netty-codec-http2\4.1.101.Final\netty-codec-http2-4.1.101.Final.jar;C:\.m2\repository\io\netty\netty-transport-native-epoll\4.1.101.Final\netty-transport-native-epoll-4.1.101.Final-linux-x86_64.jar;C:\.m2\repository\io\netty\netty-transport-native-kqueue\4.1.101.Final\netty-transport-native-kqueue-4.1.101.Final-osx-x86_64.jar;C:\.m2\repository\io\netty\netty-tcnative-boringssl-static\2.0.62.Final\netty-tcnative-boringssl-static-2.0.62.Final.jar;C:\.m2\repository\io\netty\netty-tcnative-boringssl-static\2.0.62.Final\netty-tcnative-boringssl-static-2.0.62.Final-linux-x86_64.jar;C:\.m2\repository\io\netty\netty-tcnative-boringssl-static\2.0.62.Final\netty-tcnative-boringssl-static-2.0.62.Final-linux-aarch_64.jar;C:\.m2\repository\io\netty\netty-tcnative-boringssl-static\2.0.62.Final\netty-tcnative-boringssl-static-2.0.62.Final-osx-x86_64.jar;C:\.m2\repository\io\netty\netty-tcnative-boringssl-static\2.0.62.Final\netty-tcnative-boringssl-static-2.0.62.Final-osx-aarch_64.jar;C:\.m2\repository\io\netty\netty-tcnative-boringssl-static\2.0.62.Final\netty-tcnative-boringssl-static-2.0.62.Final-windows-x86_64.jar;C:\.m2\repository\org\springframework\boot\spring-boot-starter-validation\2.3.7.RELEASE\spring-boot-starter-validation-2.3.7.RELEASE.jar;C:\.m2\repository\org\glassfish\jakarta.el\3.0.3\jakarta.el-3.0.3.jar;C:\.m2\repository\org\hibernate\validator\hibernate-validator\6.1.6.Final\hibernate-validator-6.1.6.Final.jar;C:\.m2\repository\jakarta\validation\jakarta.validation-api\2.0.2\jakarta.validation-api-2.0.2.jar;C:\.m2\repository\org\jboss\logging\jboss-logging\3.3.2.Final\jboss-logging-3.3.2.Final.jar;C:\.m2\repository\com\alibaba\fastjson\1.2.80\fastjson-1.2.80.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2023.1.1\lib\idea_rt.jar" com.tope365.SpringAppRun
Connected to the target VM, address: '127.0.0.1:64926', transport: 'socket'
11:09:42.415 [main] INFO com.tope365.SpringAppRun - openai web启动中....
org.springframework.boot.SpringApplicationRunListener  starting...
org.springframework.boot.SpringApplicationRunListener  environmentPrepared...
org.springframework.context.ApplicationListener  onApplicationEvent...

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::               (v2.7.11)

org.springframework.context.ApplicationContextInitializer  initialize...
org.springframework.boot.SpringApplicationRunListener  contextPrepared...
org.springframework.boot.SpringApplicationRunListener  contextLoaded...
********
 _ _   |_  _ _|_. ___ _ |    _ 
| | |\/|_)(_| | |_\  |_)||_|_\ 
     /               |         
                        3.4.1 
********
org.springframework.boot.SpringApplicationRunListener  started...
org.springframework.boot.SpringApplicationRunListener  running...
2024-03-13 11:09:51.045  INFO 18344 --- [           main] com.tope365.SpringAppRun                 : openai web启动成功!

源码剖析

@SpringBootConfiguration:组合注解,标记当前类为配置类

@EnableAutoConfiguration:开启自动配置
@ComponentScan:扫描主类所在的同级包以及子级包里的Bean
@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 {
    ...
}
@SpringBootConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {

可以看到@Configuration为@Component注解的子实现,他同样支持被@ComponentScan扫描到。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {

@ComponentScan

1、包扫描路径范围问题:如果是引入的其他jar包,需要加载的bean组件的包路径与配置类的扫描包路径相同则可以扫描到,否则无法扫描到容器。(编译成jar时,同包合并。),一般只有我们自己的maven聚合工程项目才会按照规则创建相同的包,引入第三方jar包时,往往都不一样。
2、包扫描路径覆盖问题:@ComponentScan指定第三方jar包的组件路径,但是@ComponentScan 和@SpringBootApplication注解的包扫描有冲突,@ComponentScan注解包扫描会覆盖掉@SpringBootApplication的包扫描。解决办法就是在@ComponentScan(basePackages={“com.ruoyi.common.swagger.config”,“com.ruoyi.system”})的基础上加上@SpringBootApplication扫描的包。
3、使用 @Configuration与@Bean 注解,必须在com.ruoyi.system包下创建,保证被启动类包扫描到。


@Configuration
public class SwaggerAutoConfiguration
{
    @Bean
    public Docket api(SwaggerProperties swaggerProperties)
    {
    。。。

@EnableAutoConfiguration

@Import加载spring.factories

通过@Import(AutoConfigurationImportSelector.class)导入Selector类,@Import 是 Spring 基于 Java 注解配置的主要组成部分,@Import 注解提供了类似 @Bean 注解的功能,向Spring容器中注入bean,也对应实现了与Spring XML中的元素相同的功能。

其一扫描入口,springboot1.5 低版本使用,高版本已经在run时直接加载spring.factories文件了,spring核心方法invokeBeanFactoryPostProcessors(beanFactory);内部会扫描到并触发AutoConfigurationImportSelector类的selectImports方法。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    ...
}

AutoConfigurationImportSelector中的方法selectImports()调用到loadFactoryNames(),得到待配置的class的类名集合,这个集合就是所有需要进行自动配置的类,而是否自动配置的关键在于META-INF/spring.factories文件中是否存在该配置信息。

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
    Map<String, List<String>> result = cache.get(classLoader);
    if (result != null) {
       return result;
    }
    result = new HashMap<>();
    try {
       Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
       while (urls.hasMoreElements()) {
          URL url = urls.nextElement();
          UrlResource resource = new UrlResource(url);
          Properties properties = PropertiesLoaderUtils.loadProperties(resource);
          for (Map.Entry<?, ?> entry : properties.entrySet()) {
             String factoryTypeName = ((String) entry.getKey()).trim();
             String[] factoryImplementationNames =
                   StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
             for (String factoryImplementationName : factoryImplementationNames) {
                result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
                      .add(factoryImplementationName.trim());
             }
          }
       }
       // Replace all lists with unmodifiable lists containing unique elements
       result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
             .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
       cache.put(classLoader, result);
    }
    catch (IOException ex) {
       throw new IllegalArgumentException("Unable to load factories from location [" +
             FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
    return result;
}

@Import(AutoConfigurationImportSelector.class)自动配置调用链:(spring低版本使用)
@SpringBootApplication
—>@EnableAutoConfiguration
—>@Import(AutoConfigurationImportSelector.class)
—>selectImports(AnnotationMetadata annotationMetadata)
—>getAutoConfigurationEntry(AnnotationMetadata annotationMetadata)
—>getCandidateConfigurations(metadata, attributes)
—>loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()))
—>loadSpringFactories(ClassLoader classLoader)

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());
    }
}

run初始化加载spring.factories

public class SpringApplication {
    public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class<?>[] { primarySource }, args);
    }
}

第一次的初始化加载:
SpringApplication.run(SpringAppRun.class, args);
—>new SpringApplication(primarySources).run(args)
—>this(null, primarySources);
—>getSpringFactoriesInstances(Class type)
—>getSpringFactoriesInstances(type, new Class<?>[] {})

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = getClassLoader();
    // Use names and ensure unique to protect against duplicates
    Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

以下是全是调用返回已经初始化好的factories cache。
static final Map<ClassLoader, Map<String, List>> cache = new ConcurrentReferenceHashMap<>();

public ConfigurableApplicationContext run(String... args) {
    ... 
    try {
       ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
       ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
       ...
       prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
       refreshContext(context);
       ...

spring.factories中的钩子类

以下是factories 缓存集合内容,可以看到自定义的factories文件内容已经加载进去了。
在这里插入图片描述

根据Spring Boot 2.6.x版本中的启动代码步骤,以下是上述22个钩子类在运行时执行的顺序:

// Spring 应用程序上下文初始化器接口。
org.springframework.context.ApplicationContextInitializer
// Spring Boot 日志系统工厂接口。
org.springframework.boot.logging.LoggingSystemFactory
// Spring Boot 属性源加载器接口。
org.springframework.boot.env.PropertySourceLoader
// Spring Boot 环境后置处理器接口。
org.springframework.boot.env.EnvironmentPostProcessor
// Spring Boot 自动配置导入监听器接口。
org.springframework.boot.autoconfigure.AutoConfigurationImportListener
// Spring Boot 自动配置注解。
org.springframework.boot.autoconfigure.EnableAutoConfiguration
// Spring Bean 信息工厂接口。
org.springframework.beans.BeanInfoFactory
// Spring Boot 数据库初始化器检测器。
org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector
// Spring Boot 数据库初始化器依赖检测器。
org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector
// Spring Boot 自动配置导入过滤器接口。
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter
// Spring Boot 失败分析器接口。
org.springframework.boot.diagnostics.FailureAnalyzer
// Spring Boot 失败分析报告器接口。
org.springframework.boot.diagnostics.FailureAnalysisReporter
// Spring Boot 异常报告器接口。
org.springframework.boot.SpringBootExceptionReporter
// Spring Data 定制集合注册器接口。
org.springframework.data.util.CustomCollectionRegistrar
// Spring Boot 配置数据位置解析器。
org.springframework.boot.context.config.ConfigDataLocationResolver
// Spring Boot 配置数据加载器。
org.springframework.boot.context.config.ConfigDataLoader
// Spring Boot 应用程序上下文工厂接口。
org.springframework.boot.ApplicationContextFactory
// Spring Boot 应用程序运行监听器接口。
org.springframework.boot.SpringApplicationRunListener
// Spring 应用程序事件监听器接口。
org.springframework.context.ApplicationListener
// Spring Data 仓库工厂支持类。
org.springframework.data.repository.core.support.RepositoryFactorySupport
// Spring Data Jackson 模块配置类。
org.springframework.data.web.config.SpringDataJacksonModules
// Spring Boot JSON 解析器工厂类。

org.springframework.boot.json.JsonParserFactoryorg.springframework.boot.json.JsonParserFactoryorg.springframework.boot.json.JsonParserFactory:Spring Boot JSON 解析器工厂类。
以上是GPT给的调用顺序,其实不是特别准确,如下是自行验证的效果:

org.springframework.boot.SpringApplicationRunListener  starting...
org.springframework.boot.SpringApplicationRunListener  environmentPrepared...
org.springframework.context.ApplicationListener  onApplicationEvent...
org.springframework.context.ApplicationContextInitializer  initialize...
org.springframework.boot.SpringApplicationRunListener  contextPrepared...
org.springframework.boot.SpringApplicationRunListener  contextLoaded...
org.springframework.boot.SpringApplicationRunListener  started...
org.springframework.boot.SpringApplicationRunListener  running...

spring.factories中的钩子类的框架实现
下图表示有不少的实现类
在这里插入图片描述

比如以下不同包中的实现类:
spring-boot-2.3.12.RELEASE\spring-boot-project\spring-boot-autoconfigure\build\resources\main\META-INF\spring.factories

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
...

spring-boot-2.3.12.RELEASE\spring-boot-project\spring-boot-devtools\src\main\resources\META-INF\spring.factories

# Application Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.devtools.restart.RestartScopeInitializer
...

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【最后2天】京东云游戏云服务器0门槛抽奖送!云服务器选购推荐 京东云 阿里云 腾讯云对比 幻兽帕鲁 雾锁王国 省钱学生党

好消息&#xff1a;抽奖活动开启&#xff01;时间&#xff1a;3月17日——3月24日 最高奖品&#xff1a;16G 6个月&#xff1b;32G 3个月 抽奖规则&#xff1a;B站点赞评论关注即可参与抽奖&#xff0c;3.24日公布获奖名单。 抽奖地址&#xff1a; 【首次抽奖】16G、32G免费…

每日学习笔记:C++ STL 容器的杂谈

三种自定义STL容器 string作为STL容器 C风格数组作为STL容器 C11以后 C11以前 容器元素类型是引用 使用智能指针存储元素 使用引用外覆器 各容器使用时机 如何分别用两种不同的排序准则来存储同批数据&#xff1f; 解决方案&#xff1a;将容器元素改为智能指针即可。 根据排…

CentOS/RHEL 6.5 上 NFS mount 挂起kernel bug

我本身有四台机器做WAS集群&#xff0c;挂载nfs&#xff0c;其中随机一台客户端计算机端口关闭释放将进入不良状态&#xff0c;对 NFSv4 挂载的任何访问都将挂起&#xff08;例如“ls&#xff0c;cd 或者df均挂起”&#xff09;。这意味着没有人并且所有需要访问共享的用户进程…

【笔记】以论文发表形式通俗理解 TCP/IP模型

【笔记】以论文发表形式通俗理解 TCP/IP模型 前言TCP/IP模型理论通俗理解 前言 在网络基础学习过程中&#xff0c;以前只对TCP/IP理解个字面&#xff0c;网上查一下能知道个字面意思&#xff0c;但是连起来到底是什么意思&#xff0c;还是一知半解的&#xff0c;停留在表面&am…

实型数据详解

1 实型常量的表示方法 实数(real number)又称浮点数(floating-point number)。实数有两种表示形式: (1)十进制小数形式。它由数字和小数点组成(注意必须有小数点)。.123、123.、123.0、0.0都是十进制小数形式。 (2)指数形式。如123e3或123E3都代表123x103。但注意字母e(或E)…

gdb和makefile的讲解

Linux调试器-gdb使用 gdb可以用于Linux环境下的程序的调试&#xff0c;就例如vs环境下的打断点&#xff0c;然后逐步分析语句等 1 gdb的背景 程序的发布方式有两种&#xff0c;debug模式和release模式 我们在使用vs21时大家都清楚&#xff0c;release版本是不能被调试的&…

MySQL定时任务Event详解

文章目录 基本概念一、Event事件使用权限二、开启\关闭Event事件三、Event事件定义格式四、事件调度使用案例4.1 准备工作4.2 创建单次定时执行事件4.2.1 创建指定时间单次执行事件任务4.2.2 创建延迟时间单次执行事件任务4.2.3 创建单次执行事件任务[多SQ执行] 4.3 创建循环定…

【机器学习】一文搞懂算法模型之:Transformer

Transformer 1、引言2、Transformer2.1 定义2.2 原理2.3 算法公式2.3.1 自注意力机制2.3.1 多头自注意力机制2.3.1 位置编码 2.4 代码示例 3、总结 1、引言 小屌丝&#xff1a;鱼哥&#xff0c; 你说transformer是个啥&#xff1f; 小鱼&#xff1a;嗯… 啊… 嗯…就是… 小屌…

uni-app攻略:如何对接驰腾打印机

一.引言 在当前的移动开发生态中&#xff0c;跨平台框架如uni-app因其高效、灵活的特点受到了开发者们的青睐。同时&#xff0c;随着物联网技术的飞速发展&#xff0c;智能打印设备已成为许多业务场景中不可或缺的一环。今天&#xff0c;我们就来探讨如何使用uni-app轻松对接驰…

异步爬虫实践攻略:利用Python Aiohttp框架实现高效数据抓取

在当今信息爆炸的时代&#xff0c;数据是无处不在且变化迅速的。为了从海量数据中获取有用的信息&#xff0c;异步爬虫技术应运而生&#xff0c;成为许多数据挖掘和分析工作的利器。本文将介绍如何利用Python Aiohttp框架实现高效数据抓取&#xff0c;让我们在信息的海洋中快速…

怎么才可以实现自定义异常?

在回答怎么才可以自定义异常这个问题之前&#xff0c;我们先看异常处理对象是怎么实现的&#xff1f;下图为运行时异常需要继承 RuntimeException异常类。 而RuntimeException异常类又继承Exception异常类。 所以&#xff0c;要实现自定义异常类&#xff0c;就需要去继承Runtim…

matlab矩形薄板小挠度弯曲有限元编程 |【Matlab源码+理论文本】|板单元| Kirchoff薄板 | 板壳单元

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现&#xff0c;并提供所有案例完整源码&#xff1b;2.单元…

2024年三大主食冻干品牌测评,希喂、SC、K9自费实测综合PK

在现今注重科学养宠的时代背景下&#xff0c;主食冻干已经成为猫咪日常饮食的重要组成部分。主食冻干的高肉含量特性使其易于被猫咪吸收和消化&#xff0c;同时&#xff0c;它还能提供其他猫粮所无法提供的微量物质&#xff0c;满足猫咪的全面营养需求。然而&#xff0c;在众多…

力扣题目训练(23)

2024年2月16日力扣题目训练 2024年2月16日力扣题目训练645. 错误的集合653. 两数之和 IV - 输入二叉搜索树657. 机器人能否返回原点307. 区域和检索 - 数组可修改309. 买卖股票的最佳时机含冷冻期174. 地下城游戏 2024年2月16日力扣题目训练 2024年2月16日第二十三天编程训练&…

【开发环境搭建篇】Redis客户端安装和配置

作者介绍&#xff1a;本人笔名姑苏老陈&#xff0c;从事JAVA开发工作十多年了&#xff0c;带过大学刚毕业的实习生&#xff0c;也带过技术团队。最近有个朋友的表弟&#xff0c;马上要大学毕业了&#xff0c;想从事JAVA开发工作&#xff0c;但不知道从何处入手。于是&#xff0…

AST学习入门

AST学习入门 1.AST在线解析网站 https://astexplorer.net/ 1.type: 表示当前节点的类型&#xff0c;我们常用的类型判断方法t.is********(node)**,就是判断当前的节点是否为某个类型。 2**.start**:表示当前节点的开始位置 3.end:当前节点结束 4.loc : 表示当前节点所在的行…

Qt利用反射机制实现函数调用

QT本身就带有强大的反射功能&#xff0c;如果想通过函数名称字符串调用函数&#xff0c;需要在被调用的函数前添加宏&#xff1a;Q_INVOKABLE 父类 QtInvoke.h 头文件&#xff1a; #pragma once #include <QMainWindow> #include "ui_QtInvoke.h" class Qt…

麒麟系统中使用nginx发布项目

1. 安装Nginx sudo apt-get update #进行所有安装操作前都要执行这一句 sudo apt install nginx #出现询问就Yes参考具体 Nginx—在linux的ubuntu系统上的安装使用 2. 修改发布文件 将打包好的dist文件夹中的所有文件覆盖下面这个文件夹中的所有文件 如果出现没有权限替…

UnityShader(十九) AlphaBlend

上代码&#xff1a; Shader "Shader入门/透明度效果/AlphaBlendShader" {Properties{_MainTex ("Texture", 2D) "white" {}_AlphaScale("AlphaScale",Range(0,1))1.0}SubShader{Tags { "RenderType""Transparent&quo…

java数字城管APP系统源码,智慧执法平台,现代信息技术手段的综合管理平台

智慧城管源码&#xff0c;智慧执法&#xff0c;城管智慧综合执法系统源码 智慧城管系统充分利用物联网、云计算、信息融合、网络通讯、数据分析与挖掘等技术&#xff0c;对城市管理进行全方位覆盖。它通过建立城市综合管理平台&#xff0c;将城市的信息和管理资源有机结合起来&…
最新文章