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应用。

个人笔记

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值