初识springboot两大特性

一.依赖管理

1.父项目做依赖管理:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

凭借以上的父项目依赖,可以使之后想添加的依赖不需要添加版本号。追究其原因,在于它也有父项目,即:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.4.3</version>
  </parent>

这个依赖的properties属性下包含了常用的各类jar包的多个版本,而且这些版本适用于当前springboot的版本。如果存在需要的jar包版本不在这些范围内,可以先去官网下载,再通过在pom文件中用,在其中添加<xxx.version></xxx.version>即可.

2.开发导入starter场景启动器:
根据官方文档,官方的启动器格式为spring-boot-start-*,它是一组依赖,通过引入它,其场景下的相关依赖都被引入,这一点也可以从它的内部看出。例如spring-boot-start-web,其中就包括了json,tomcat等依赖。相关连接:https://docs.spring.io/spring-boot/docs/2.4.3/reference/html/using-spring-boot.html#using-boot-starter

二.自动配置

1.底层注解(基础准备):

1.1 @Configuration:
用在一个类上,告诉spring boot这是一个配置文件,然后就可以把这个类当成配置文件用。
例如用@Bean这个注解在这个配置类中进行操作。

@Configuration
public class MyConfig {
    @Bean
    public Pet pet(){
        return new Pet("pet");
    }
}

以上操作相当于向容器中添加了Pet这个组件,对应于原来spring的IOC形式,就是以这个方法名作为组件id,返回类型作为组件类型,返回值就是容器中的实例。容易忽略的是,其实被@Configuration标注的类也是一个组件。
除此之外,spring5.2之后给@Configuration增加了一个proxyBeanMethods属性,默认为true,即让这个注解标注的类最终获取的是代理对象,这使得该对象获取到的@Bean标注的组件对象始终为单实例,即如果有如下代码:

@SpringBootApplication
public class StartApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(StartApplication.class, args);
        MyConfig bean = run.getBean(MyConfig.class);
        Pet pet = bean.pet();
        Pet pet1 = bean.pet();
        System.out.println(user == user1);
}

输出结果是正确的。当然,如果这个属性值被设置成false,则获得的MyConfig对象不再是代理对象,以上输出结果自然不对。而以上现象是由于通过改变这个属性值,会影响springboot的行为。即值为true时,它会检查容器中是否有相应的组件,这个检查过程会使其运行速度相对较慢;值为false,跳过这个过程,运行速度相对较快。

1.2 @Import:
标注在容器的组件上,也就是带有@Configuration,@Controller等注解的类上,源码为:

Class<?>[ ] value();

可知其作用是,通过无参构造,向容器中自动创建组件,组件名字与@Bean导入的名字有所不同。即@Import创建的组件名为全类名,而@Bean导入的名为构造方法名。其添加组件格式为:@Import(xx.class或{xx.class,bb.class...})

1.4 @Conditionalxx:
标注在一个组件上,其作用见名知义,当满足xx这个条件时,则执行操作,例如:

    @Bean
    @ConditionalOnBean(name="tom")
    public User user01(){
        User zhangsan = new User("zhangsan", 18);
        //user组件依赖了Pet组件
        zhangsan.setPet(tomcatPet());
        return zhangsan;
    }
    @Bean("tom22")
    public Pet tomcatPet(){
        return new Pet("tomcat");
    }

由于user01的这个注解要求它需要在容器中存在tom组件时,才注入到容器,而此时容器中只有tom22,不满足条件,因此,运行之后,容器得不到user01组件。

1.5 @ConfigurationProperties:
需要注意的是,这个注解也得标注在容器中的一个组件上才有效。它可以把一个组件的属性与配置文件的属性一一绑定。例如:

//配置文件中
pet.height=fsi
pet.length=50
//组件中
@Component
@ConfigurationProperties(prefix = "pet")
public class Pet{
    private String height;
    private Integer length;
    public String getHeight() {
        return height;
    }
    public void setHeight(String Height) {
        this.Height = Height;
    }
    public Integer getLength() {
        return length;
    }
    public void setLength(Integer length) {
        this.length = length;
    }

通过这个注解的prefix属性识别配置文件中的前缀,再进行匹配即可完成属性注入。除此之外,@EnableConfigurationProperties(xx.class) + @ConfigurationProperties也有同样作用。需要注意的是,这两个注解不是标注在一个类上的,第二个标注在需要绑定的类上,第一个标注在另一个组件上,而xx即是被第二个注解标注的类。@EnableConfigurationProperties同时具有两个功能,即自动注入到容器和配置绑定

2.自动配置源码分析:

2.1 @EnableAutoConfiguration:

  1. @AutoConfigurationPackage:通过如下源码
1.@Import({Registrar.class})
-------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------
2.static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }

        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
        }

        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
        }
    }

注意AnnotationMetadata 这个类,虽然根据名称看来,这个注解指的是当前1(以上两段代码的编号)标注的@AutoConfigurationPackage,但由于这个注解又标注在@EnableAutoConfiguration上,最终到达@SpringBootApplication,则注解原信息以此注解为基础。而以上第一个方法获取的包名即是主类(@SpringBootApplication标注的类)所在的包名,然后将包名封装到数组中进行返回,相当于将其下所有组件注册进去。

  1. @Import({AutoConfigurationImportSelector.class}):调用流程如下:
    在这里插入图片描述
    利用getAutoConfigurationEntry(annotationMetadata),给容器中批量导入一些组件;调用 List configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类;利用工厂加载 Map<String, List> loadSpringFactories(@Nullable ClassLoader classLoader)(这是SpringFactoriesLoader.loadFactoryNamesd的方法),得到相关所有的组件,这个方法中有一个参数为FACTORIES-RESOURCE-LOCATION,它被赋了资源文件的位置为值,为META-INF/spring.factories,会使springboot默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件**(当然不是所有引入的jar包都有这个文件)**,然后进行加载。spring-boot-autoconfigure这个jar包里面也有META-INF/spring.factories,实为自动配置的核心jar包。
    注意点:虽然springboot加载了一百多个jar包,但不是每个都能用,这得益于它的按需加载配置,也就是之前说的@Conditionalxx,需要满足相关条件才能生效,否则会报红。

2.1 自动配置流程:

  1. SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration;
  2. 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定,例如:
 @EnableConfigurationProperties({WebMvcProperties.class})
    @Import({DispatcherServletAutoConfiguration.DispatcherServletConfiguration.class})
    protected static class DispatcherServletRegistrationConfiguration {
        protected DispatcherServletRegistrationConfiguration() {
        }

        @Bean(
            name = {"dispatcherServletRegistration"}
        )
        @ConditionalOnBean(
            value = {DispatcherServlet.class},
            name = {"dispatcherServlet"}
        )
        public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet, WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
            DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet, webMvcProperties.getServlet().getPath());
            registration.setName("dispatcherServlet");
            registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
            multipartConfig.ifAvailable(registration::setMultipartConfig);
            return registration;
        }
    }

可以看出绑定了WebMvcProperties配置文件;

  1. 由条件注解扫描后,生效的配置类就会给容器中装配很多组件;
  2. 只要容器中有这些组件,相当于这些功能就有了;
  3. 定制化配置:
    • 用户直接自己@Bean替换底层的组件
    • 用户去看这个组件是获取的配置文件什么值就去修改(这点看参考2所说的绑定配置文件,需要修改的值的格式可以去xxxProperties中了解,之后在你的application.properties中添加修改成你想要的值)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值