javaSpringbootWeb--原理

配置优先级

  • 文件配置
    命令行 > java系统属性 >properties > yml > yaml
  • java系统属性
-Dserver.port = 9000
  • 命令行参数
--server.port = 9001

javaSpringbootWeb--原理_第1张图片


Bean 管理

  • 获取bean
    javaSpringbootWeb--原理_第2张图片
@Autowired
    private  ApplicationContext applicationContext; //IOC容器对象

    @Test
    void testGetBean(){
        //根据bean名称获取
        EmpController bean1 = (EmpController) applicationContext.getBean("eptController");
        //根据bean的类型获取
        EmpController bean2 = applicationContext.getBean(EmpController.class);
        //根据bean的名称和类型获取
        EmpController bean3 = applicationContext.getBean("eptController", EmpController.class);
    }

Bean 作用域

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

配置Bean的作用域

@Scope(“prototype”) 非单例
@Lazy 延迟初始化 ,第一次使用时再初始化。
在这里插入图片描述

第三方Bean @Bean

javaSpringbootWeb--原理_第3张图片
javaSpringbootWeb--原理_第4张图片
通过@Bean注解的name/value属性指定bean名称,如果未指定,默认是方法名

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

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

Springboot原理

起步依赖原理

依赖传递

自动配置

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

自动配置原理

方案一: @ComponentScan 组件扫描
方案二: @lmport导入。使用@lmport导入的类会被Spring加载到10C容器中,导入形式主要有以 下几种:

  1. 导入普通类
  2. 导入配置类
  3. 导入 ImportSelector 接口实现类
    在这里插入图片描述
    javaSpringbootWeb--原理_第5张图片
    javaSpringbootWeb--原理_第6张图片
  4. @EnableXxxx注解,封装@Import注解
    javaSpringbootWeb--原理_第7张图片
    javaSpringbootWeb--原理_第8张图片
源码跟踪

@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 {
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    Class<?>[] exclude() default {};

    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    String[] excludeName() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanBasePackages() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class<?>[] scanBasePackageClasses() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "nameGenerator"
    )
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

@SpringBootConfiguration // 当前类是一个配置类,可以在@SpringBootApplication中声明第三方bean(@Bean)

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration //声明配置类
@Indexed //加速应用启动
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

@ComponentScan //组件扫描

@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

@EnableAutoConfiguration//底层通过import导入类或者配置类

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

//AutoConfigurationImportSelector 
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered 

// DeferredImportSelector 
public interface DeferredImportSelector extends ImportSelector 

// ImportSelector 
public interface ImportSelector {
    String[] selectImports(AnnotationMetadata importingClassMetadata); //类的全类名

    @Nullable
    default Predicate<String> getExclusionFilter() {
        return null;
    }
}

//AutoConfigurationImportSelector 中的selectImports
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }
//getAutoConfigurationEntry
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

// configurations
//List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));
        ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }
//META-INF/spring.factories
//META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports.

javaSpringbootWeb--原理_第9张图片
javaSpringbootWeb--原理_第10张图片
javaSpringbootWeb--原理_第11张图片
选中双击shift
javaSpringbootWeb--原理_第12张图片

@AutoConfiguration
@ConditionalOnClass({Gson.class})
@EnableConfigurationProperties({GsonProperties.class})
public class GsonAutoConfiguration {}

//AutoConfiguration 
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration(
    proxyBeanMethods = false
) //配置类
@AutoConfigureBefore
@AutoConfigureAfter
public @interface AutoConfiguration {

//GsonAutoConfiguration 
    @Bean //可以使用Autowired注入
    @ConditionalOnMissingBean
    public Gson gson(GsonBuilder gsonBuilder) {
        return gsonBuilder.create();
    }

javaSpringbootWeb--原理_第13张图片
javaSpringbootWeb--原理_第14张图片
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports.中的配置类不是全部注册为IOC容器的bean,而是会根据@ConditionalOnMissingBean按条件装配

条件装配注解 @Conditional
  • 作用:按照一定的条件进行判断,在满足给定条件后才会注册对应的bean对象到SpringIOC容器中
  • 位置:方法、类
  • @Conditional 本身是一个父注解,派生出大量的子注解!
  1. @ConditionalOnClass: 判断环境中是否有对应字节码文件,才注册bean到IOC容器。
  2. @ConditionalOnMissingBean: 判断环境中没有对应的bean (类型或名称),才注册bean到IOC容器
  3. @ConditionalOnProperty: 判断配置文件中有对应属性和值,才注册bean到IOC容器。
    javaSpringbootWeb--原理_第15张图片
    javaSpringbootWeb--原理_第16张图片

自定义starter

javaSpringbootWeb--原理_第17张图片
需求:

  • 需求:自定义aliyun-oss-spring-boot-starter,完成阿里云0SS操作工具类Aliyun0SSUtils 的自动配置
  • 目标:引入起步依赖引入之后,要想使用阿里云开源软件,注入阿里云开源软件直接使用即可。
    以往操作
		//依赖
       <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.15.1</version>
        </dependency>
	// 参考官方SDK改写工具类
	@Component
	public class AliOSSUtils {
	    @Autowired
	    private AliOSSProperties aliOSSProperties;
	
	    public String upload(MultipartFile file) throws IOException {
	        String endpoint = aliOSSProperties.getEndpoint();
	        String accessKeyId = aliOSSProperties.getAccessKeyId();
	        String accessKeySecret = aliOSSProperties.getAccessKeySecret();
	        String bucketName = aliOSSProperties.getBucketName();
	        //获取上传文件输入流
	        InputStream inputStream = file.getInputStream();
	        //避免文件覆盖
	        String originalFilename = file.getOriginalFilename();
	        String fileName = UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));
	
	        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId,accessKeySecret);
	        ossClient.putObject(bucketName,fileName,inputStream);
	        String url = endpoint.split("//")[0]+"//"+bucketName+"."+endpoint.split("//")[1]+"/"+fileName;
	        ossClient.shutdown();
	        return url;
	
	    }
	}


//yml 配置
#自定义
aliyun:
  oss:
    endpoint: https://oss-cn-hangzhou.aliyuncs.com
    accessKeyId: xxx
    accessKeySecret: xxx
    bucketName: xxx

//实体类加载yml配置参数
@Data
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSProperties {
    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String bucketName;

}

//@component 交给ioc容器

现在实现步骤

  • 创建aliyun-oss-spring-boot-starter 模块
  • 创建aliyun-oss-spring-boot-autoconfigure模块,在starter中引入该模块
  • 在aliyun-oss-spring-boot-autoconfigure 模块中的定义自动配置功能,并定义自动配置文件 META-INF/spring/xxxx.imports
  1. 创建aliyun-oss-spring-boot-starter 模块 只留下pom 引入aliyun-oss-sping-boot-autoconfigure
    在这里插入图片描述
 	<dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starterartifactId>
        dependency>
        <dependency>
            <groupId>com.aliyun.ossgroupId>
            <artifactId>aliyun-oss-sping-boot-autoconfigureartifactId>
            <version>0.0.1-SNAPSHOTversion>
        dependency>
  1. aliyun-oss-spring-boot-autoconfigure模块
    javaSpringbootWeb--原理_第18张图片
    pom.xml
 <dependency>
           <groupId>org.springframework.bootgroupId>
           <artifactId>spring-boot-starterartifactId>
       dependency>

       <dependency>
           <groupId>org.springframework.bootgroupId>
           <artifactId>spring-boot-starter-webartifactId>
       dependency>

       <dependency>
           <groupId>org.projectlombokgroupId>
           <artifactId>lombokartifactId>
           <optional>trueoptional>
       dependency>

       <dependency>
           <groupId>com.aliyun.ossgroupId>
           <artifactId>aliyun-sdk-ossartifactId>
           <version>3.15.1version>
       dependency>

AliOSSUtils


public class AliOSSUtils {

    private AliOSSProperties aliOSSProperties;

    public AliOSSProperties getAliOSSProperties() {
        return aliOSSProperties;
    }

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

    public String upload(MultipartFile file) throws IOException {
        String endpoint = aliOSSProperties.getEndpoint();
        String accessKeyId = aliOSSProperties.getAccessKeyId();
        String accessKeySecret = aliOSSProperties.getAccessKeySecret();
        String bucketName = aliOSSProperties.getBucketName();
        //获取上传文件输入流
        InputStream inputStream = file.getInputStream();
        //避免文件覆盖
        String originalFilename = file.getOriginalFilename();
        String fileName = UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));

        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId,accessKeySecret);
        ossClient.putObject(bucketName,fileName,inputStream);
        String url = endpoint.split("//")[0]+"//"+bucketName+"."+endpoint.split("//")[1]+"/"+fileName;
        ossClient.shutdown();
        return url;

    }
}

AliOSSProperties

@Data
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSProperties {
    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String bucketName;
}

  1. 模块中的定义自动配置功能
@Configuration
@EnableConfigurationProperties(AliOSSProperties.class)
public class AliOSSAutoConfiguration {
    @Bean
    public AliOSSUtils aliOSSUtils(AliOSSProperties aliOSSProperties){
        AliOSSUtils aliOSSUtils = new AliOSSUtils();
        aliOSSUtils.setAliOSSProperties(aliOSSProperties);
        return aliOSSUtils;
    }
}

  1. 并定义自动配置文件 META-INF/spring/xxxx.imports
    resources文件下新建
META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports

内容javaSpringbootWeb--原理_第19张图片

com.aliyun.oss.AliOSSAutoConfiguration
  1. 测试
    新建module–pom引入自定义starter aliyun-oss-sping-boot-starter
@RestController
public class UploadController {
    @Autowired
    private AliOSSUtils aliOSSUtils;
    @PostMapping("/upload")
    public String upload(MultipartFile image) throws Exception{
        return  aliOSSUtils.upload(image);
    }
}

错误提示

javaSpringbootWeb--原理_第20张图片

javaSpringbootWeb--原理_第21张图片
idea可能会出现上述提示,不用管直接运行测试。知道怎么解决的铁子们可以留言

你可能感兴趣的:(跟着黑马学javaweb,spring,boot)