Spring

7 篇文章 0 订阅

Spring 启动过程

spring boot启动类

 @SpringBootApplication	
 public class Application {	
     public static void main(String[] args) {	
         SpringApplication.run(Application.class, args);	
     }	
 }

可以看出,Annotation定义(@SpringBootApplication)和类定义(SpringApplication.run)承担着主要的角色,从以上入手进行分析。

@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 = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

虽然定义使用了多个Annotation进行了原信息标注,但实际上重要的只有三个Annotation:

  • @Configuration(@SpringBootConfiguration点开查看发现里面还是应用了@Configuration)
  • @EnableAutoConfiguration
  • @ComponentScan
    即 @SpringBootApplication = (默认属性)@Configuration + @EnableAutoConfiguration + @ComponentScan。

所以,如果我们使用如下的SpringBoot启动类,整个SpringBoot应用依然可以与之前的启动类功能对等:

@Configuration	
@EnableAutoConfiguration	
@ComponentScan	
public class Application {	
         public static void main(String[] args) {	
             SpringApplication.run(Application.class, args);	
         }	
}

@Configuration

JavaConfig形式的Spring Ioc容器的配置类。

  1. @Configuration的注解类标识这个类可以使用Spring IoC容器作为bean定义的来源。

  2. @Bean注解告诉Spring,一个带有@Bean的注解方法将返回一个对象,该对象应该被注册为在Spring应用程序上下文中的bean。

@ComponentScan

自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。
可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。所以SpringBoot的启动类最好是放在root package下,因为默认不指定basePackages。

@EnableAutoConfiguration

借助@Import的支持,收集和注册特定场景相关的bean定义。

  1. @EnableAutoConfiguration借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器!

  2. @EnableAutoConfiguration会根据类路径中的jar依赖为项目进行自动配置,如:添加了spring-boot-starter-web依赖,会自动添加Tomcat和Spring MVC的依赖,Spring Boot会对Tomcat和Spring MVC进行自动配置。

  3. 借助于Spring框架原有的一个工具类:SpringFactoriesLoader的支持,@EnableAutoConfiguration可以智能的自动配置

SpringFactoriesLoader详解

SpringFactoriesLoader属于Spring框架私有的一种扩展方案,其主要功能就是从指定的配置文件META-INF/spring.factories加载配置。
配合@EnableAutoConfiguration使用,行使配置查找的功能支持。

  1. 从classpath中搜寻所有的META-INF/spring.factories配置文件
  2. 并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类
  3. 汇总为一个并加载到IoC容器

SpringApplication.run()

创建SpringApplication对象实例

SpringApplication实例初始化的时候,它会提前做几件事情:

  1. 根据classpath里面是否存在某个特征类(ConfigurableWebApplicationContext)来决定是否应该创建一个为Web应用使用的ApplicationContext类型。
  2. 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer。
  3. 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener。

执行run方法

方法执行伊始,首先遍历执行所有通过SpringFactoriesLoader可以查找到并加载的SpringApplicationRunListener。调用它们的started()方法,告诉这些SpringApplicationRunListener,“嘿,SpringBoot应用要开始执行咯!”。

创建并配置Environment

包括配置要使用的PropertySource以及Profile。

SpringApplicationRunListener.environmentPrepared()

遍历调用所有SpringApplicationRunListener的environmentPrepared()的方法,
告诉他们:“当前SpringBoot应用使用的Environment准备好了咯!”。

打印banner

如果SpringApplication的showBanner属性被设置为true,则打印banner。

ApplicationContext使用配置好的环境

根据用户是否明确设置了applicationContextClass类型以及初始化阶段的推断结果,决定该为当前SpringBoot应用创建什么类型的ApplicationContext,然后根据条件决定是否添加ShutdownHook,决定是否使用自定义的BeanNameGenerator,决定是否使用自定义的ResourceLoader,最重要的,将之前准备好的Environment设置给创建好的ApplicationContext使用。

initialize

ApplicationContext创建好之后,SpringApplication会再次借助Spring-FactoriesLoader,查找并加载classpath中所有可用的ApplicationContextInitializer,然后遍历调用这些ApplicationContextInitializer的initialize(applicationContext)方法来对已经创建好的ApplicationContext进行进一步的处理。

SpringApplicationRunListener.contextPrepared()

遍历调用所有SpringApplicationRunListener的contextPrepared()方法。

加载进ApplicationContext

核心的一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备完毕的ApplicationContext。

遍历所有SpringApplicationRunListener.contextLoaded()

调用ApplicationContext.refresh()方法

CommandLineRunner

查找当前ApplicationContext中是否注册有CommandLineRunner,如果有,则遍历执行它们。

SpringApplicationRunListener.finished()

正常情况下,遍历执行SpringApplicationRunListener的finished()方法、(如果整个过程出现异常,则依然调用所有SpringApplicationRunListener的finished()方法,只不过这种情况下会将异常信息一并传入处理)

Spring启动初始化

启动加载

启动成功后可以通过以下方法运行自己的初始代码

@PostConstruct注解

修饰初始化后,依赖关系注入完成之后需要执行的方法, 也可以理解为在spring容器启动的时候执行,可作为一些数据的常规化加载,比如数据字典之类的

  • 执行顺序为:构造方法 > @Autowired > @PostConstruct
    @Component  
    public class StartUpInit {  
      
      @Autowired  
      private SomeService service;  
      
      @PostConstruct  
      public void init(){  
         // ...  
      }  
      
    }  

@Configuration和@Bean来初始化资源

初始化资源,配置文件通过@Value进行注入。

  • @Configuration:用于定义配置类,可替换xml配置文件,被注解的类内部一般是包含了一个或者多个@Bean注解的方法。
  • @Bean:产生一个Bean对象,然后将Bean对象交给Spring管理,被注解的方法是会被AnnotationConfigApplicationContext或者AnnotationConfgWebApplicationContext扫描,用于构建bean定义,从而初始化Spring容器。产生这个对象的方法Spring只会调用一次,之后Spring就会将这个Bean对象放入自己的Ioc容器中。

补充@Configuration加载Spring:

@Configuration配置spring并启动spring容器
@Configuration启动容器+@Bean注册Bean
@Configuration启动容器+@Component注册Bean
使用 AnnotationConfigApplicationContext 注册 AppContext 类的两种方法
配置Web应用程序(web.xml中配置AnnotationConfigApplicationContext)

CommandLineRunner

创建自定义类实现 CommandLineRunner接口,重写run()方法。springboot启动之后会默认去扫描所有实现了CommandLineRunner的类,该接口中的Component会在所有Spring的Beans都初始化之后,在SpringApplication的run()完成之前执行。

@Component
@Order(2)   //通过order值的大小来决定启动的顺序
public class AskForLeave implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        askForLeave();
    }

    public void askForLeave(){
        System.out.println("项目启动了,执行了方法");
    }
}

ApplicationRunner接口

@Component
@Order(3)
public class Hello implements ApplicationRunner {
   @Override
   public void run(ApplicationArguments args) throws Exception {

       hello();
   }

   public void hello(){
       System.out.println("项目又启动了,这次使用的是:继承 ApplicationRunner");
   }
}

链接: Spring Boot 入门 - 进阶篇(6)- 启动加载(CommandLineRunner) .
https://blog.csdn.net/zlc3323/article/details/100137222

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值