栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

spring boot自动装配和启动流程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

spring boot自动装配和启动流程

自动装配的原理 @EnableAutoConfiguration注解

我们先关注下这个注解的内容,主要由三个核心的注解:@SpringBootConfiguration:内置@Configurantion注解,表示是一个配置类;@EnableAutoConfiguration:自动装配;@ComponentScan:扫描路径以及排除和包含的类。

@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 {
    ...
}

接下来重点关注@EnableAutoConfiguration注解:

@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 {};
}

spring boot在启动的过程中,底层无非也是在创建spring容器,故也就是会启动spring。我们知道spring在启动过程中会解析配置类,而当启动springboot时,会将被@SpringBootApplication注解的类当做配置类进行解析,那么就会解析@EnableAutoConfiguration注解,这个注解还注解了@import注解。点开AutoConfigurationimportSelector.class时,发现他是实现了DeferredimportSelector接口,DeferredimportSelector接口还有一个分组接口以及默认方法getimportGroup(),AutoConfigurationimportSelector类实现了getimportGroup()方法,并指定一个Group类返回,然后会先后调用AutoConfigurationGroup#process()和selectimports()方法,process()方法会去读取引入的所有包中的spring.factories包配置的自动装配类。那么为什么会选择实现这个接口呢?

1、spring解析配置类时,会判断如果被导入的类实现的是DeferredimportSelector接口,会被延期加载,也就是等其他需要解析的类都加载为BeanDefinition被存入到beanDefinitionMap中后,再去执行AutoConfigurationGroup#process()和selectimports()方法,并将返回的数组解析为BeanDefinition并注册到spring容器中,当然这里会有判断,如果已经类已经解析过了,则会舍弃,也就是保证程序员配置的bean优先加载。

2、调用AutoConfigurationGroup#selectimports()方法对最终以EnableAutoConfiguration.class为key解析的类进行排除和排序。

 自定义starter

首先创建父maven项目:spring-boot-starter-rick

接下来创建两个子项目:rick-spring-boot-starter,rick-spring-boot-starter-autoconfigure

其中rick-spring-boot-starter是在resources目录下创建了spring.factories文件,并指定自动装配的类(HelloServiceAutoConfiguration),并且pom.xml引入了rick-spring-boot-starter-autoconfigure项目

而rick-spring-boot-starter-autoconfigure项目分别创建了三个类:HelloProperties,HelloService,HelloServiceAutoConfiguration。

HelloProperties:中注解了@ConfigurationProperties(prefix = "rick.hello")表示这个类属性与配置文件中前缀为rick.hello的属性进行一一对应。然后注册为bean

@ConfigurationProperties(prefix = "rick.hello")
public class HelloProperties {
    private String prefix;
    private String suffix;

    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public String getSuffix() {
        return suffix;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }
}

HelloServiceAutoConfiguration:springboot启动会解析该类并将HelloService绑定HelloProperties然后注册为bean。

@Configuration
@ConditionalOnWebApplication //web应用生效
@EnableConfigurationProperties(HelloProperties.class)
public class HelloServiceAutoConfiguration {
    @Autowired
    HelloProperties helloProperties;

    @Bean
    public HelloService helloService(){
        HelloService service = new HelloService();
        service.setHelloProperties(helloProperties);
        return service;
    }
}

HelloService:最终会被程序员所调用。

public class HelloService {
    HelloProperties helloProperties;

    public HelloService() {
    }

    public HelloProperties getHelloProperties() {
        return this.helloProperties;
    }

    public void setHelloProperties(HelloProperties helloProperties) {
        this.helloProperties = helloProperties;
    }

    public String sayHello(String name) {
        return this.helloProperties.getPrefix() + name + this.helloProperties.getSuffix();
    }
}

最后将两个子项目进行install,当starter被其他springboot应用引入后,就可以通过HelloService进行依赖注入进行调用sayHello()方法了

java -jar是如何启动spring boot jar的?

JarLauncher通过加载BOOT-INF/classes目录及BOOT-INF/lib目录下jar文件,实现了fat jar的启动。

SpringBoot通过扩展JarFile、JarURLConnection及URLStreamHandler,实现了jar in jar中资源的加载。

SpringBoot通过扩展URLClassLoader–LauncherURLClassLoader,实现了jar in jar中class文件的加载。

WarLauncher通过加载WEB-INF/classes目录及WEB-INF/lib和WEB-INF/lib-provided目录下的jar文件,实现了war文件的直接启动及web容器中的启动。

spring boot启动

springboot运行后,会new SpringApplication()将传入的配置类缓存到primarySources中,接下来执行run()方法,创建AnnotationConfigServletWebServerApplicationContext的spring上下文,接下来调用refresh()方法创建spring容器

在此期间会解析配置类,也就是spring boot启动传入的类,这里就会去执行解析@EnableAutoConfiguration注解的信息,完成所需要加载的bean。

当执行到onrefresh()方法时,判断当前servletContext(可以理解为tomcat中servlet容器上下文)是否为空,为空代表tomcat内置启动,需要创建新的tomcat,如果不为空,代表tomcat外置启动应用;此时是springboot启动,servletContext为空,故需要new Tomcat()。当tomcat启动以后会调用函数指针(ServletContextInitializer接口函数),这里执行相关类的onStartup()方法,向servletContext注册DispatchServlet处理器。

而外置tomcat启动容器是通过spi的机制来实现的,返回得到指定的接口的实现类SpringServletContainerInitializer,并实例化调用它的onStartup()方法,会调用SpringBootServletInitializer#onStartup()方法,这里会重新创建一个SpringApplication对象,并调用run方法,相当于启动spring boot应用。

个人笔记

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/667209.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号