JavaWeb合集10-StringBoot原理

时间:2024-10-18 08:24:37

十、StringBoot原理

1、配置优先级

SpringBoot中支持三种格式的配置文件:①application. properties;②application.yml ;③application.yaml

配置优先级:properties > yml > yaml

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

在这里插入图片描述
在这里插入图片描述

注意:Springboot项目进行打包时,需要引入插件spring-boot-maven-plugin (基于官网骨架创建项目,会自动添加该插件)

在这里插入图片描述

2、Bean管理

2.1 从IOC容器中获取Bean对象

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

  1. 根据名字获取Bean

    Object getBean(String  name)
    
  2. 根据类型获取Bean

    <T> T  getBean(Class<T>  requiredType)
    
  3. 根据name获取bean ( 带类型转换)

    <T>  T  getBean (String  name , Class<T> requiredType)
    
@SpringBootTest
class MybatisTestApplicationTests {

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

    @Test
    void  getBean(){

        //通过IOC对象调用方法获取对应的Bean对象
        //1、根据Bean名称获取Bean对象(如果没有指定Bean对象名称,那么默认就是类名首字母小写).返回类型是Object需要强转
        UserController uc1= (UserController) applicationContext.getBean("userController");
        System.out.println(uc1);

         //2、根据Bean的类型来获取Bean对象
        UserController uc2=applicationContext.getBean(UserController.class);
        System.out.println(uc2);

        //3、根据name获取bean ( 带类型转换)
        UserController uc3=applicationContext.getBean("userController",UserController.class);
        System.out.println(uc3);
    }
}

注意:上述所说的[Spring项目启动时, 会把其中的bean都创建好] 还会受到作用域及延迟初始化影响,这里主要针对于默认的单例非延迟加载的bean而言。

2.2 Bean的作用域

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

作用域 说明
singleton 容器内 同名称的Bean只有一个实例(单例) 默认
prototype 每次使用Bean时都会创建新的实例(非单例)
request 每个请求范围内都会创建新的实例(web环境中,了解)
session 每个会话范围内都会创建新的实例(web环境中,了解)
application 每个应用范围内会创建新的实例(web环境中,了解)
  1. 默认情况下Bean的初始化是在项目启动的时候进行的,不过在对应类上使用注解:@Lazy (懒惰的),可以使Bean的初始化延迟到获取Bean对象的时候才进行初始化。
  2. 在对应类上使用注解:@Scope(“作用域”) 来设置作用域的类型:如:@Scope(“prototype”)
  3. 实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性。
@Scope("prototype")
@RestController 
@RequestMapping("/users")
public class UserController {
}
2.3 第三方Bean的配置

需要下载第三方的jar包时,通常都是只读的,无法在其中加@Component注解,加类交给IOC容器管理。

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

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

//定义一个配置类
@Configuration
public class CommonConfig {
@Bean   //将方法返回值交给IOC容器管理,成为IOC容器的bean对象
       //通过@Bean注解的name/value,属性指定bean名称,如果未指定,默认是方法名
public SAXReader saxReader(){
return new SAXReader();
   }
}
//如果要使用,直接使用@Autowird 注入就行

如果想要在方法中进行注入对应的Bean,那么直接使用形参的方式来注入:

//定义一个配置类
@Configuration
public class CommonConfig {
@Bean  
    //根据形参自动注入userController对象
public SAXReader saxReader(UserController userController){
    System.out.println(userController)
  return new SAXReader();
   }
}

注意:

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

3、SpringBoot原理

3.1 起步依赖原理

通过Maven的依赖传递的特性来进行自动依赖的导入,意思就是导入很少的依赖,就可以依次导入他们相关联的依赖。

3.2 自动配置原理

在这里插入图片描述

SpringBoot的原理就是,自动配置的原理,也就是如何将jar包中的配置类、Bean交给IOC容器管理的。

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

3.2.1 @ComponentScan组件扫描

在项目中不是所有被导入的依赖加上对应的配置Bean都会交给IOC容器管理,在启动类中:@SpringBootApplication会进行扫描,默认只有在该项目包中的依赖才会被扫描到,并且加入到IOC容器中。不过可以在启动类中使用注解:@ServletComponentScan 来配置扫描包的范围。

@ComponentScan( {"com.examp1e", " com.yhzy"})
@SpringBootApplication
public class SpringbootWebConfig2Application {
}

3.2.1 @lmport导入

使用@Import导入的类会被Spring加载到IOC容器中,导入形式主要有以下几种:普通类、配置类、ImportSelector接口实现类;@EnableXxxx注解,封装@Import注解

@Import ({TokenParser.class}) //导入普通类,交给IOC容器管理
@Import ({HeaderConfig.class}) //导入配置类,交给IOC容器管理
@Import ( {MyImportSelector.class}) //导入ImportSelector接口实现类
@SpringBootApplication
public class SpringbootWebCon fig2Appl ication {
public static void main (String[] args) {
SpringApp1ication.run(SpringbootWebConfig2Application.class, args) ;
}
}

3.2.2 @Conditional

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

位置:方法、类

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

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

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

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

@Configuration
public class HeaderConfig {
    
@Bean 
@Conditional0nClass (name= "io.jsonwebtoken.Jwts") //环境中存在指定的这个类,才会将该bean加入IOC容器中

public HeaderParser headerParser () {
return new HeaderParser() ;
}
@Bean
@ConditionalOnMissingBean //不存在该类型的bean,才会将该bean加入IOC容器中 --- 指定类型(value属性)或名称(name属性)
 @ConditionalOnProperty (name="name" havingValue="yhzy")//配置文件中存在指定的属性与值, 才会将该bean加入IOC容器中
public HeaderGenerator headerGenerator() {
return new HeaderGenerator() ;
}
}                                      
3.3 自定义starter

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

案例:

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

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

实现步骤:

  1. 创建aliyun-oss-spring-boot-starter模块(主要作用依赖管理)
  2. 创建aliyun-oss-spring-boot-autoconfigure模块,在starter中引入该模块
  3. 在aliyun-oss-spring-boot-autoconfigure模块中的定义自动配置功能,并定义自动配置文件META-INF/spring/ xxxx.imports

具备实现步骤如下:

一、创建aliyun-oss-spring-boot-starter模块

1、按照规范创建对应的项目,不需要提前选择任何依赖。

在这里插入图片描述

2、删不需要文件和目录,只保留 (.iml 和pom.xml文件)

3、清理pom.xml 里面不需要的依赖(后面需要引入创建的aliyun-oss-spring-boot-autoconfigure依赖)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-oss-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>
    
</project>

二、创建aliyun-oss-spring-boot-autoconfigure模块,在starter中引入该模块(需要web开发依赖)

1、创建对应模块,将除sec目录和.iml、配置文件、pom.xml文件删除;将src下的启动类和测试类也删除

在这里插入图片描述

在这里插入图片描述

2、将pom文件中无用的依赖进行删除,并去aliyun-oss-spring-boot-starter模块的依赖文件中引入该模块

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

三、在aliyun-oss-spring-boot-autoconfigure模块中的定义自动配置功能

1、引用阿里云OSS相关依赖

 <!--        阿里云OSS-->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.17.4</version>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>
        <!-- no more than 2.3.3-->
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.3</version>
        </dependency>

2、将阿里云OSS的工具类和参数实体类导入进来,并进行修改

在这里插入图片描述

package com.aliyun.oss;

import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.UUID;

//将类交给IOC容器管理(这样就用于去创建对象来调用其方法了)
//@Component
//通过样例将OSS打造为一个工具类
public class AliyunOSS {
    // Endpoint以华北2(北京)为例,其它Region请按实际情况填写。 概括->外网访问
//    @Value("${aliyun.oss.endpoint}")
//    private String endpoint;
//    // 填写Bucket名称,例如examplebucket。
//    @Value("${aliyun.oss.bucketName}")
//    private String bucketName;



    private  AliOSSProperties aliOSSProperties;

    public AliOSSProperties getAliOSSProperties() {
        return aliOSSProperties;
    }

    public void setAliOSSProperties(AliOSSProperties aliOSSProperties) {
        this.aliOSSProperties = aliOSSProperties;
    }


    //文件上方法(返回上传后文件的访问路径)
    public  String upload(MultipartFile file) throws Exception {

        //获取阿里云oss参数
        String endpoint = aliOSSProperties.getEndpoint() ;
        String bucketName = aliOSSProperties.getBucketName () ;



        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();

        //1、获取上传文件的输入流
        InputStream inputStream=file.getInputStream();

        //2、避免覆盖,生成UUID作为文件名
        String fileFullName=file.getOriginalFilename();
        String fileName= UUID.randomUUID().toString()+fileFullName.substring(fileFullName.lastIndexOf("."));

        // 上传到OSS
        OSS ossClient=new OSSClientBuilder().build(endpoint,credentialsProvider);
        ossClient.putObject(bucketName,fileName,inputStream);

        //获取文件上传后的路径:https://bucket的名字.地区的路径/文件名字
        String url=endpoint.split("//")[0]+"//"+bucketName+"."+endpoint.split("//")[1]+"/"+fileName;
        //关闭 ossClient
        ossClient.shutdown();

        //返回文件访问的路径
        return url;
    }

    //文件上方法(返回上传后文件的访问路径)
    public  String update(MultipartFile file,String filePath) throws Exception {

        //获取阿里云oss参数
        String endpoint = aliOSSProperties.getEndpoint() ;
        String bucketName = aliOSSProperties.getBucketName () ;


       // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();

        //1、获取上传文件的输入流
        InputStream inputStream=file.getInputStream();

        //2、从文件路径中截取出文件名,使其覆盖远有我文件,达到修改的效果。
        String fileName =filePath.substring(filePath.lastIndexOf("/")+1);

        // 上传到OSS
        OSS ossClient=new OSSClientBuilder().build(endpoint,credentialsProvider);
        ossClient.putObject(bucketName,fileName,inputStream);

        //关闭 ossClient
        ossClient.shutdown();

        //返回文件访问的路径
        return fileName;
    }
}
//  AliOSSProperties配置参数实体类
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSProperties {
  private  String endpoint;
  private String bucketName;

    public String getEndpoint() {
        return endpoint;
    }

    public void setEndpoint(String endpoint) {
        this.endpoint = endpoint;
    }

    public String getBucketName() {
        return bucketName;
    }

    public void setBucketName(String bucketName) {
        this.bucketName = bucketName;
    }
}

3、在目录aliyun\oss创建一个配置类,并配置对应的工具类对象

//配置类
@Configuration
@EnableConfigurationProperties(AliOSSProperties.class) //将AliOSSProperties其交给IOC管理
public class AliOSSAutoConfiguration {

    //外部Bean对象
    @Bean
    //注入对象直接通过参数形式
    public AliyunOSS  aliyunOSS(AliOSSProperties aliOSSProperties){
        AliyunOSS aliyunOSS=new AliyunOSS();
         aliyunOSS.setAliOSSProperties(aliOSSProperties);
        return aliyunOSS;
    }
}

4、在resource目录下创建目录META-INF\spring,并在创建的目录下创建名为(org.springframework.boot.autoconfigure.AutoConfiguration.imports)的文件

在这里插入图片描述

org.springframework.boot.autoconfigure.AutoConfiguration.imports文件内容:是自动配置类的全类名

com.aliyun.oss.AliOSSAutoConfiguration

四、测试

1、创建一个测试模块,导入web依赖、lombok依赖和创建的阿里云oss-starter依赖

     <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

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

2、在yml配置文件中填写oss的配置

#阿里云OSS配置
aliyun:
  oss:
    endpoint: https://oss-cn-beijing.aliyuncs.com
    bucketName: yhzy-resource

3、创建Controller层,并写一POST接口,注入阿里云OSS的bean对象,通过接口测试工具对其测试

@RestController
@RequestMapping("/upload")
public class Upload {

    @Autowired
    private AliyunOSS aliyunOSS;

    @PostMapping
    public String  upload(MultipartFile file) throws Exception {

       String path= aliyunOSS.upload(file);
        return path;
    }
}