1 启动中的CommondLinerRun和ApplicationRunner接口
1)他的作用:
项目启动之前,预先加载数据或做一些事情,比如:权限容器、特殊用户数据等。通常我们可以使用监听器、事件来操作。但是,springboot提供了一个简单的方式来实现此类需求,即,CommandLineRunner。
官方文档介绍:
- 这是一个接口,用户可以自定义实现该接口,具体实现run方法
- 任何在上下文容器之内的bean都可以实现run方法
- 如果在上下文中,存在多个该接口实现类,可以通过@order注解,指定加载顺序
@Component //必须使用这个注解
@Order(value = 2)
public class MyStartupRunner1 implements CommandLineRunner{
@Override
public void run(String... strings) throws Exception {
System.out.println(">>>>>>>>>>>>>>>服务启动执行,执行加载数据等操作 MyStartupRunner1 order 2 <<<<<<<<<<<<<");
}
}
@Component
@Order(value = 1)
public class MyStartupRunner2 implements CommandLineRunner {
@Override
public void run(String... strings) throws Exception {
System.out.println(">>>>>>>>>>>>>>>服务启动执行,执行加载数据等操作 MyStartupRunner2 order 1 <<<<<<<<<<<<<");
}
}
// 启动将线执行MyStartupRunner2 类的run方法
2) ApplicationRunner
若想在springBoot项目启动之后直接执行某一段代码,直接实现 ApplicationRunner接口,和上面一样如果在上下文中,存在多个该接口实现类,可以通过@order注解,指定加载顺序
@Component //此类一定要交给spring管理
@Order(value=1) //首先执行
public class ConsumerRunnerA implements Application{
@Oberride
public void run(ApplicationArgumers args) throws Exception{
//代码
System.out.println("需要在springBoot项目启动时执行的代码1---");
}
}
SpringIoc容器
接口Beanfactory 和 Applicationcontext 都可以通过 T getBean(String name, Class requiredType) 方法从 Spring 容器中获取bean,区别是,前者是懒加载形式(只有直接调用它的getBean() 方法时才进行实例化),后者是预加载的形式(每一个 bean 都在 ApplicationContext 启动之后实例化)。
ApplicationContext(应用上下文):继承BeanFactory接口,简单来说就是Spring中的容器,是Spring的一个更高级的容器。可以用来获取容器中的各种bean组件,注册监听事件,加载资源文件等功能。
BeanFactory:是Spring里面最底层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能;
SpringBoot中我们通常使用@Autowired注解获取ApplicationContext中的springbean。
Spring Bean
Spring 为啥把bean默认设计成单例?为了提高性能少创建实例垃圾回收缓存快速获取,但是这样会导致线程不安全。
Java Bean + 元数据配置( 通常以XML,Java 注解或代码的形式表示)注入SpringIoc容器,容器实例化后就是Spring Bean。下面是Spring 容器实例化java Bean的三种方式:
1) 在方法上使用@PostConstruct,通常将该方法定义为init()。spring提倡我们用这种方式
@PostConstruct
public void init() {
//业务代码
}
2) 实现InitializingBean 接口,然后在afterPropertiesSet
内完成实例化的工作,但是 Spring Framework 官方并不建议通过这种方式,它是强耦合的,通常只有框架层面才会用。
public class initMyBean implement InitializingBean {
@Override
public void afterPropertiesSet() throws Exception{
//自己的业务
}
}
3)init-method方式
public class MyClass {
public void init() {
// 业务逻辑
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public MyClass myclass() {
return new MyClass ();
}
}
或者在xml文件配置
<bean id="myClass" class="com.demo.MyClass" init-method="init"/>
上次的顺序也代表了他们的优先级。
若我们想在初始化前后嵌入业务逻辑,可以实现BeanPostProcessor接口
public class myBussiness implement BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object var1, String var2) throws
BeansException{
//初始化前的工作
}
@Overrride
public Object postProcessAfterInitialization(Object var1, String var2) throws
BeansException{
//初始化后的逻辑
}
}
所以完整的过程是:
postProcessBeforeInitialization ()-> @PostConstruct -> afterPropertiesSet
()-> @Bean(initMethod = "方法名")->postProcessAfterInitialization()