SpringBoot 原理专题

优先级与打包

  1. 命令行参数
  2. 系统环境
  3. properties
  4. yml
  5. yaml

打包插件

xml 复制代码
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>${spring-boot.version}</version>
    <configuration>
        <mainClass>com.example.DemoApplication</mainClass>
        <skip>true</skip>
    </configuration>
    <executions>
        <execution>
            <id>repackage</id>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>

打包后运行,带额外参数

bash 复制代码
java -Dserver.port=9000 -jar dd.jar

Bean 作用域

作用域 说明
singleton 容器内同 名称 的 bean 只有一个实例(单例)(默认)
prototype 每次使用该 bean 时会创建新的实例(非单例/多例)
request 每个请求范围内会创建新的实例(web环境中,了解)
session 每个会话范围内会创建新的实例(web环境中,了解)
application 每个应用范围内会创建新的实例(web环境中,了解)

配置 Scope 注解,选择单例

  • Lazy 表示延迟加载,默认是启动时加载,配置后表示延迟到第一次使用加载
  • SCOPE_SINGLETON 单例
  • SCOPE_PROTOTYPE 非单例
java 复制代码
@Lazy
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
@RestController
public class BasicController {}

注意:

  1. 单例是无状态的,多例是有状态的。
  2. 单例是节约资源,提升性能
  3. 单例bean:如果是无状态的bean,内部不保存任何状态信息,则是线程安全的。
  4. 单例bean:如果是有状态的bean,内部会保存状态信息,多个线程会同时操作该bean时,可能会出现数据不一致的问题,这样的bean则是线程不安全的。

起步依赖

依赖,具有传递性。

自动配置

SpringBoot的自动配置就是当spring项目启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作。

比如:引入了redis依赖,可以直接注入Redis使用。

实现方案一

加入另一个项目的依赖,引入依赖,并在主类上加上包扫描,扫描该依赖的包,不推荐,原因是操作麻烦+性能低

实现方案二

类不需要加任何注解,直接使用 Import 导入,或者使用Imort 导入一个配置类。

java 复制代码
@Import(TokenService.class)
@SpringBootApplication
public class DemoApplication {

配置类代码

java 复制代码
public class MyImportSelector implements ImportSelector {

    // 返回多个类的全限定命名
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.example.aop.RecordTimeAspect2"};
    }
}

实现方案三:加注解的方式,最实用

java 复制代码
// 核心还是用方式二
@Import(MyImportSelector.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableHeaderConfig {
}

条件判断 / 自动配置

有时候我们经常需要判断该类应不应该注入到IOC容器中。

  • 作用:按照一定的条件进行判断,在满足给定条件后才会注册对应的bean对象到Spring IOC容器中。

  • 位置:方法、类

  • @Conditional 本身是一个父注解,派生出大量的子注解:

  • @ConditionalOnClass:判断环境中是否有对应字节码文件,才注册bean到IOC容器。

  • @ConditionalOnMissingBean:判断环境中没有对应的bean(类型 或 名称) ,才注册bean到IOC容器。

  • @ConditionalOnProperty:判断配置文件中有对应属性和值,才注册bean到IOC容器。

java 复制代码
@Bean
// 判断环境中是否存在io.jsonwebtoken.Jwts,如果有就创建该Bean
@ConditionalOnClass(name = "io.jsonwebtoken.Jwts")
// 判断环境中是否存在该类,如果没有就创建该Bean
@ConditionalOnMissingBean
// 判断属性值是否为true,在配置文件中
@ConditionalOnProperty(name = "enable", havingValue = "true")
public RecordTimeAspect2 recordTimeAspect2(){
    return new RecordTimeAspect2();
}

自己定义自动配置类的核心是什么? 如何完成自动配置?

  1. 定义自动配置类
  2. 将自动配置类配置在 META-INF/spring/
  3. org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中

自定义Starter

需求:自定义aliyun-oss-spring-boot-starter,完成阿里云OSS操作工具类 AliyunOSSOperator 的自动配置。

目标:引入起步依赖引入之后,要想使用阿里云OSS,注入 AliyunOSSOperator 直接使用即可。

步骤:

  1. 创建aliyun-oss-spring-boot-starter模块
  2. 创建aliyun-oss-spring-boot-autoconfigure模块,在starter中引入该模块
  3. 在aliyun-oss-spring-boot-autoconfigure模块中的定义自动配置功能,并定义自动配置文件 META-INF/spring/xxxx.imports

注意:选择一个版本,无需要选依赖

只需要依赖是 spring-boot-starter 就可以。

java 复制代码
@Configuration
@EnableConfigurationProperties(OSSProperties.class) // 引入配置类
public class OSSConfig {

    @Bean
    public OSS endpoint(OSSProperties ossProperties) {
        DefaultCredentialProvider defaultCredentialProvider =
                new DefaultCredentialProvider(ossProperties.getAccessKeyId(), ossProperties.getSecretAccessKey());
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
        return OSSClientBuilder.create()
                .endpoint("https://" + ossProperties.getEndpoint())
                .credentialsProvider(defaultCredentialProvider)
                .clientConfiguration(clientBuilderConfiguration)
                .region(extractRegion(ossProperties.getEndpoint()))
                .build();
    }

    /**
     * 获取 region
     */
    private String extractRegion(String endpoint) {
        if (endpoint == null) return null;
        int start = endpoint.indexOf("oss-");
        int end = endpoint.indexOf(".aliyuncs.com");
        if (start == -1 || end == -1 || start + 4 >= end)
            throw new IllegalArgumentException("Invalid endpoint: " + endpoint);
        return endpoint.substring(start + 4, end);
    }

}
java 复制代码
@Data
@ConfigurationProperties(prefix = "aliun.oss")
public class OSSProperties {

    private String endpoint;
    private String accessKeyId;
    private String secretAccessKey;
}
相关推荐
luming-0210 小时前
java报错解决:sun.net.utils不存
java·经验分享·bug·.net·intellij-idea
北海有初拥10 小时前
Python基础语法万字详解
java·开发语言·python
alonewolf_9910 小时前
Spring IOC容器扩展点全景:深入探索与实践演练
java·后端·spring
super_lzb10 小时前
springboot打war包时将外部配置文件打入到war包内
java·spring boot·后端·maven
毛小茛10 小时前
芋道管理系统学习——项目结构
java·学习
东北小狐狸-Hellxz10 小时前
解决java客户端连接ssh失败问题
java·网络·ssh
悟能不能悟10 小时前
HttpServletRequest request获取整个headers有什么方法
java
__万波__10 小时前
二十三种设计模式(二十)--解释器模式
java·设计模式·解释器模式
网安_秋刀鱼10 小时前
【java安全】反序列化 - CC1链
java·c语言·安全
零度@10 小时前
Java消息中间件-Kafka全解(2026精简版)
java·kafka·c#·linq