自制笔记 | JavaWeb——SpringBoot原理(持续更新...)

配置优先级

SpringBoot中支持三种格式的配置文件:properties、yml、yaml

注意:虽然springboot支持多种格式配置文件,但是在项目开发时,推荐统一使用一种格式的配置(yml是主流

SpringBoot除了支持配置文件属性配置,还支持Java系统属性命令行参数的方式进行属性配置

java系统属性:

-Dserver.port=9000

命令行参数:

--server.port=10010

属性配置

项目打包后,在运行时指定java系统属性和命令行参数:

① 执行maven打包指令package
② 执行java指令,运行jar包

java -Dserver.port=9000 -jar tlias-web-management-0.0.1-SNAPSHOT.jar --server.port=10010

java后跟java系统属性,jar文件后跟命令行参数

优先级:命令行参数 > java系统属性 > application.properties > application.yml > application.yaml

Bean管理

1.获取bean:

默认情况下,Spring项目启动时,会把bean都创建好放在IOC容器中,如果想要主动获取这些bean,可以通过如下方式:

根据name获取bean:

Object getBean(String name)

根据类型获取bean:

<T> T getBean(Class<T> requiredType)

根据name获取bean(带类型转换):

<T> T getBean(String name, Class<T> requiredType)

示例:

@Autowired
private ApplicationContext applicationContext; //IOC容器对象

//获取bean对象
@Test
public void testGetBean(){
    
    
    //根据bean的名称获取
    DeptController bean1 = (DeptController) applicationContext.getBean("deptController");
    System.out.println(bean1);

    //根据bean的类型获取
    DeptController bean2 = applicationContext.getBean(DeptController.class);
    System.out.println(bean2);

    //根据bean的名称 及 类型获取
    DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);
    System.out.println(bean3);
}

2.bean作用域:

Spring支持五种作用域,后三种在web环境才生效:

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

可以通过@Scope注解来进行配置作用域

@Scope("prototype")
@RestController
@RequestMapping("/depts")
public class DeptController {
    
    
}

注意:

① 默认singleton的bean,在容器启动时被创建,可以使用@Lazy注解来延迟初始化(延迟到第一次使用时)
② prototype的bean,每一次使用该bean的时候都会创建一个新的实例
③ 实际开发中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性

3.第三方bean:

如果要管理的bean对象来自于第三方(不是自定义的),是无法用@Component及衍生注解声明bean的,就需要用到@Bean注解

若要管理第三方bean对象,建议对这些bean进行集中分类配置,可以通过@Configuration注解声明一个配置类

示例:

@Configuration //配置类
public class CommonConfig {
    
    
    //声明第三方bean
    @Bean //将当前方法的返回值对象交给IOC容器管理,成为IOC容器bean
          //通过@Bean注解的name/value属性指定bean名称,如果未指定,默认是方法名
    public SAXReader saxReader() {
    
    
        return new SAXReader();
    }
}

注意:

① 通过@Bean注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名
② 如果第三方bean需要依赖其他bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配

@Component及衍生注解与@Bean注解使用场景:

① 项目中自定义的,使用@Component及衍生注解
② 项目中引入第三方的,使用@Bean注解

SpringBoot原理

1.起步依赖

若不使用springboot,而使用spring框架进行web程序开发,此时需引入依赖:

若使用springboot,则只需要引入一个依赖:

image-20240310202944538

原理在于:Maven的依赖传递

2.自动配置

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

案例:将依赖中所提供的Bean和配置类加载到当前项目中的IOC容器

image-20240310203011547

<dependency>
    <groupId>com.example</groupId>
    <artifactId>itheima-utils</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

方案一:@ComponentScan组件扫描

即使对应依赖中的类加上了@Component或其他声明Bean的注解,也不能直接加入当前项目的IOC容器。原因在于启动类的@SpringBootApplication注解中的@ComponentScan只会扫描当前包及其子包,不会扫描其他包

因此需要对@ComponentScan的范围进行修改

@ComponentScan({
    
    "com.example", "com.itheima"})
@SpringBootApplication
public class SpringbootWebConfig2Application{
    
    
}

但是如果依赖较多,需要扫描的包就会很多,会比较繁琐;且一个包下可能会有很多类,而Bean以及配置类可能并不多,所以性能也较低

方案二:@Import导入

使用@Import导入的类会被Spring加载到IOC容器中,导入形式主要有以下几种:

① 导入普通类

@Import({
    
    TokenParser.class})
@SpringBootApplication
public class SpringbootWebConfig2Application{
    
    
}

② 导入配置类(此时配置类中所有的Bean对象都会被导入)

@Import({
    
    HeaderConfig.class})
@SpringBootApplication
public class SpringbootWebConfig2Application{
    
    
}

③ 导入ImportSelector接口实现类

public class MyImportSelector implements ImportSelector {
    
    
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    
    
        return new String[]{
    
    "com.example.HeaderConfig"}; //返回类的全类名的数组
    }
}
@Import({
    
    MyImportSelector.class})
@SpringBootApplication
public class SpringbootWebConfig2Application{
    
    
}

@EnableXxxx注解,封装@Import注解(这个注解一般是由第三方依赖提供的),这种方式也是SpringBoot方式采用的

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyImportSelector.class)
public @interface EnableHeaderConfig {
    
    
}
@EnableHeaderConfig
@SpringBootApplication
public class SpringbootWebConfig2Application{
    
    
}

源码跟踪:

@SpringBootApplication
public class SpringbootWebConfig2Application {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(SpringbootWebConfig2Application.class, args);
    }
}
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {
    
    @Filter(
    type = FilterType.CUSTOM,
    classes = {
    
    TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {
    
    AutoConfigurationExcludeFilter.class}
)})
public @interface SpringBootApplication {
    
    
    ...
}

@SpringBootApplication

该注解标识在SpringBoot工程引导类上,是SpringBoot中最重要的注解。该注解由三个部分组成:

@SpringBootConfiguration:该注解与@Configuration注解作用相同,用来声明当前也是一个配置类
@ComponentScan:组件扫描,默认扫描当前引导类所在包及其子包
@EnableAutoConfiguration:SpringBoot实现自动化配置的核心注解

源码跟踪

@EnableAutoConfiguration注解中,底层封装了一个@Import注解,这个注解中指定的是一个ImportSelector接口的实现类,这个实现类实现了接口中的方法selectImports,返回值封装的是要导入到IOC的类的全类名。在这个方法中,加载了两个文件,一个是spring.factories(早期配置文件,后面会被移除),另一个是spring文件夹下的AutoConfiguration.imports文件。这个文件定义的是配置类的全类名,这些配置类中用了@Bean注解来声明Bean对象

注意:这些并不会全部注册为IOC容器的bean,由于有@ConditionalMissingBean注解,使得其能保证按条件装配,当满足一定的条件之后才会将这个bean注册到IOC中

@Conditional

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

位置:方法、类

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

@ConditionalOnClass:判断环境中是否有对应字节码文件,若没有才注册bean到IOC容器
@ConditionalOnMissingBean:判断环境中没有对应的bean(类型或名称),才注册bean到IOC容器
@ConditionalOnProperty: 判断配置文件中有对应属性和值,才注册bean到IOC容器

示例:

@Bean
@ConditionalOnClass(name = "io.jsonwebtoken.Jwts") //环境中存在指定的这个类,才会将该bean加入IOC容器中
public HeaderParser headerParser() {
    
    
    ...
}
@Bean
@ConditionalOnMissingBean //不存在该类型的bean,才会该bean加入IOC容器中 --- 指定类型(value) 或 名称(name)
public HeaderParser headerParser() {
    
    
    ...
}
@Bean
@ConditionalOnProperty(name = "name", havingValue = "itheima") //配置文件中存在指定的属性与值,才会将该bean加入IOC容器中
public HeaderParser headerParser() {
    
    
    ...
}

第一个主要用于判断是否引入了对应的依赖;第二个主要用于声明默认Bean对象,如果用户自定义了该对象,则使用该自定义对象,如果没有用户自定义对象,则使用默认Bean对象;第三个主要用于在引入第三方技术时,只有在配置文件中配置了对应的配置项,才会声明对应的Bean对象

案例:自定义starter

场景:在实际开发中,经常会定义一些公共组件,提供给各个项目团队使用。而在SpringBoot的项目中,一般会将这些公共组件封装为SpringBoot的starter

image-20240310203027605

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

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

步骤:

① 创建aliyun-oss-spring-boot-starter模块

② 创建aliyun-oss-spring-boot-autoconfigure模块,在starter中引入该模块

pom.xml:

<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

③ 在aliyun-oss-spring-boot-autoconfigure模块中定义自动配置功能,并定义自动配置文件META-INF / spring / xxxx.imports

autoconfigure

这个模块中还要加上之前引入的阿里云OSS相关的依赖,因为之后的类需要用到依赖中的方法

AliOSSAutoConfiguration:

@Configuration
@EnableConfigurationProperties(AliOSSProperties.class)
public class AliOSSAutoConfiguration {
    
    
    @Bean
    public AliOSSUtils aliOSSUtils(AliOSSProperties aliOSSProperties) {
    
    
        AliOSSUtils aliOSSUtils = new AliOSSUtils();
        aliOSSUtils.setAliOSSProperties(aliOSSProperties);
        return aliOSSUtils;
    }
}

这里多加了个@EnableConfigurationProperties注解的原因在于,原先在AliOSSProperties类的@ConfigurationProperties注解前是有@Component注解的,而此时需要去掉@Component注解,导致AliOSSProperties这个类没有注入到IOC中,因此无法使用@ConfigurationProperties注解使properties配置文件转化成bean。此时就需要@EnableConfigurationProperties注解来使AliOSSProperties这个类加载到IOC容器中(经过测试,这个注解也可以让引入这个依赖的模块,可以直接去注入这个类。另外,也可以直接使用@Bean将这个类加入到IOC容器中)

而之后在参数声明了这个类的对象,这个对象会被IOC容器直接注入,且这个对象的属性与配置文件中的配置属性是对应的

AliOSSProperties:

跟之前一样,不过要删去Component注解(因为启动类和这个类不在同一个模块中)

AliOSSUtils:

跟之前一样,不过要删去Component注解,以及加上aliOSSProperties这个对象的get和set方法(因为之前是采用自动注入的方式为这个对象赋值的,而现在没有自动注入,则需要手动定义set方法让外界赋值),以及删去这个对象上的Autowired注解

org.springframework.boot.autoconfigure.AutoConfiguration.imports:

com.aliyun.oss.AliOSSAutoConfiguration

猜你喜欢

转载自blog.csdn.net/Vendetta_A_A/article/details/136608270