一直想整理一下相关的点,囿于时间问题及担心理解不是太全面所以没整理,后来一想先整理出来,将这一方面的东西记录下来。其实这篇文章不应该体现spring boot,因为自动执行方式不仅限于spring boot,java spring细化到bean的初始化都可以完成。
不纠结名称了,开整!!
Java启动时加载方式
-
static代码块
static静态代码块,在类加载的时候即自动执行。 由于静态代码块没有名字,我们并不能主动调用,它会在类加载的时候,自动执行。所以静态代码块,可以更早的给类中的静态属性,进行初始化赋值操作。并且,静态代码块只会自动被执行一次,因为JVM在一次运行中,对一个类只会加载一次!
验证static自动执行及是否只执行一次:
测试类里面定义static代码块,bean的scope定义为prototype(Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域),main方法new两次发现static代码块仅执行一次,验证通过。 -
构造函数constructor
在对象初始化时执行。执行顺序在static静态代码块之后。
-
@PostConstruct注解
PostConstruct注解使用在方法上,这个方法在对象依赖注入初始化之后执行。执行节点在BeanPostProcessor的postProcessBeforeInitialization之后,在postProcessAfterInitialization之前。
@PostConstruct注解好多人以为是Spring提供的。其实是Java自己的注解。Java中该注解的说明:@PostConstruct该注解被用来修饰一个非静态的void()方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。
**注意:**加了postconstruct注解的方法,如果执行失败,整个程序会无法正常启动!这个方法执行不完,整个程序也启动不了!!!也不建议将耗时逻辑放到这里面来。
spring启动时加载
-
InitializingBean接口
Spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中通过init-method指定,两种方式可以同时使用。
实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率要高一点,但是init-method方式消除了对spring的依赖。先调用afterPropertieSet()方法,然后再调用init-method中指定的方法。 -
ApplicationRunner和CommandLineRunner
SpringBoot提供了两个接口来实现Spring容器启动完成后执行的功能,两个接口分别为CommandLineRunner和ApplicationRunner。这两个接口需要实现一个run方法,将代码在run中实现即可。这两个接口功能基本一致,其区别在于run方法的入参。ApplicationRunner的run方法入参为ApplicationArguments,为CommandLineRunner的run方法入参为String数组。
当有多个类实现了CommandLineRunner和ApplicationRunner接口时,可以通过在类上添加@Order注解来设定运行顺序。
**注意:**使用ApplicationRunner或者CommandLineRunner时如果报错或者出现超时的情况会导致整个程序崩溃。可以将run内的逻辑单独开一个线程使用。
总结一下:
顺序为static>constructor>初始化前>@PostConstruct>InitializingBean>初始化后>ApplicationRunner和CommandLineRunner。
如果有不准确的地方欢迎大家指正讨论!!!