spring 核心一 IOC容器
spring的核心是IOC容器,即控制反转Inverse of control,将bean实例统一管理,无需在代码里手动New对象。
IOC构建流程
1、整体流程
1、获取一个新的bean工厂,通常是ApplicationContext,就是IOC容器
2、加载解析bean配置,将解析的bean封装到BeanDefinition中,并放到本地缓存中。
3、将bean放到IOC容器,包括如下:
(1) 实例化所有的bean(非懒加载)
(2) bean的属性填充
(3) 初始化bean
4、刷新ApplicationContext。
2、流程细分
(1) 获取一个新的bean工厂
通常是ApplicationContext,就是IOC容器,ApplicationContext是BeanFactory的实现类,是spring最核心的接口。用getBean来加载bean。BeanFactory相当于是IOC的基础类,。
注意FactoryBean是另一个东西,可以用来手动注入类实例
事例通过FactoryBean注入类实例
/**
*
*/
//1. 这里的接口泛型参数为要注入Bean的类型
public class MyFactoryBean implements FactoryBean<Person> {
//2.重写的第一个方法返回Bean的实例
@Override
public Person getObject() throws Exception {
return new Person("123");
}
//3.重写的第二个方法返回Bean的类型
@Override
public Class<?> getObjectType() {
return Person.class;
}
//4.重写的第三个方法返回一个boolean值,决定该Bean的类型是单例还是多实例。这里返回true,为单例。
@Override
public boolean isSingleton() {
return true;
}
}
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Configuration
public class FactoryBeanConfig {
/**
* 把MyFactoryBean类的Bean注入容器,即实现了把Person类Bean注入容器。
* @return
*/
@Bean
public MyFactoryBean PersonBean(){//这里的方法名称是Person类Bean的ID
return new MyFactoryBean();
}
}
测试代码
ApplicationContext applicationContext = SpringApplication.run(BasicApplication.class, args);
// 测试通过继承factorybean方式注入IOC容器
Person personBean = (Person)applicationContext.getBean("PersonBean");
System.out.println(personBean.getName());
(2) 加载解析bean配置
加载的bean配置解析封装到BeanDefinition中,并放到本地缓存中。加载完所有bean配置后触发如下方法:
实现接口BeanFactoryPostProcessor#postProcessBeanFactory方法
/**
* postProcessBeanFactory 方法,在步骤二加载完bean的配置后触发,即在步骤三前。
* 通常可以使用这个方法来加载自己的bean定义
*/
@Component
public class BeanFactoryPostProcessorTest implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("此处通常可以使用这个方法来加载自己的bean定义");
}
}
(3) 将bean放到IOC容器
步骤一:实例化所有的bean(非懒加载方式)
步骤二:bean的属性填充
初始化前触发方法有:
1、实现接口 BeanPostProcessor#postProcessBeforeInitialization方法
@Component
public class BeanPostProcessorTest implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("执行bean的初始化方法前触发");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
2、实现接口 InitializingBean#afterPropertiesSet方法
/**
* afterPropertiesSet 方法,在bean的属性填充之后,初始化方法(init-method)之前被触发
* 该方法的作用基本等同于init-mehod,主要用于执行初始化相关操作。
*/
@Component
public class InitializingBeanTest implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("在bean的属性填充之后,初始化方法(init-method)之前被触发");
}
}
3、注入类指定初始化方法 @Bean指定initMethod
@Configuration
public class ConfigBean {
// initMethod指向Cat里的init()方法,destroyMethod指向Cat里的destroy()方法
@Bean(initMethod = "init", destroyMethod = "destroy")
public Cat cat() {
return new Cat();
}
}
public class Cat {
public Cat() {
System.out.println("Cat‘s 构造方法。。。");
}
public void init() {
System.out.println("Cat‘s init()方法。。。");
}
}
4、类中指定@PostConstruct注解指定方法
public class Cat {
@PostConstruct
public void postConstruct() {
System.out.println("Cat‘s postConstruct()方法。。。");
}
}
步骤三:初始化bean
初始化后触发:1、实现接口BeanPostProcessor#postProcessAfterInitialization方法
/**
* postProcessBeforeInitialization方法,执行bean的初始化方法前触发
* postProcessAfterInitialization方法,执行bean的初始化方法后触发
*/
@Component
public class BeanPostProcessorTest implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("执行bean的初始化方法前触发");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("执行bean的初始化方法后触发");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
2、实现接口 DisposableBean#destroy方法(销毁前)
/**
* destroy 方法,在bean被销毁之前被触发,相当于 destroyMethod 方法
*
*/
@Component
public class DisposableBeanTest implements DisposableBean {
@Override
public void destroy() throws Exception {
}
}
3、注入类指定初始化方法 @Bean指定destroyMethod(销毁前)
@Configuration
public class ConfigBean {
// initMethod指向Cat里的init()方法,destroyMethod指向Cat里的destroy()方法
@Bean(initMethod = "init", destroyMethod = "destroy")
public Cat cat() {
return new Cat();
}
}
public class Cat {
public void destroy() {
System.out.println("Cat‘s destroy() 方法。。。");
}
}
4、类中指定@PreDestroy注解指定方法(销毁前)
public class Cat {
@PreDestroy
public void preDestroy() {
System.out.println("Cat‘s preDestroy()方法。。。");
}
}
5、实现接口SmartLifecycle#start()方法
/**
* 当Spring容器加载所有bean并完成初始化之后,会接着回调实现该接口的类中对应的方法(start()方法)。
*/
@Component
public class SmartLifecycleTest implements SmartLifecycle {
private boolean isRunning = false;
/**
* 步骤一:
* 当上下文被刷新(所有对象已被初始化之后)时,将调用此方法
* 1、默认生命周期处理器将检查每个SmartLifecycle对象的 isAutoStartup()方法返回的布尔值。
* 如果为“true”,则start()方法会被调用,在 SmartLifecycle接口中默认值为true;
* @return
*/
@Override
public boolean isAutoStartup() {
return true;
}
/**
* 步骤二:
* 如果工程中有多个实现接口SmartLifecycle的类,则这些类的start的执行顺序按getPhase方法返回值从小到大执行。<br/>
* 例如:1比2先执行,-1比0先执行。 stop方法的执行顺序则相反,getPhase返回值较大类的stop方法先被调用,小的后被调用。
*/
public int getPhase() {
// 默认为0
return 0;
}
/**
* 步骤三:
* 1. 我们主要在该方法中启动任务或者其他异步服务,比如开启MQ接收消息<br/>
*/
@Override
public void start() {
System.out.println("start");
// 执行完其他业务后,可以修改 isRunning = true
isRunning = true;
}
/**
* SmartLifecycle子类的才有的方法,当 isRunning() 方法返回true时,该方法才会被调用。
*/
@Override
public void stop(Runnable callback) {
System.out.println("stop(Runnable)");
callback.run();
isRunning = false;
}
/**
* 接口Lifecycle的子类的方法,只有非SmartLifecycle的子类才会执行该方法。<br/>
* 1. 该方法只对直接实现接口Lifecycle的类才起作用,对实现SmartLifecycle接口的类无效。<br/>
* 2. 方法stop()和方法stop(Runnable callback)的区别只在于,后者是SmartLifecycle子类的专属。
*/
@Override
public void stop() {
System.out.println("stop()");
isRunning = false;
}
/**
* 1. 只有该方法返回false时,start方法才会被执行。<br/>
* 2. 只有该方法返回true时,stop(Runnable callback)或stop()方法才会被执行。
*/
@Override
public boolean isRunning() {
return isRunning;
}
}
(4) 刷新ApplicationContext
刷新IOC容器,执行refresh方法
刷新IOC容器前触发:
1、实现接口ApplicationContextInitializer#initialize的方法
/**
*
*
* initialize 方法,在spring容器刷新前触发,也就是refresh方法前触发。
*/
@Component
public class ApplicationContextInitializerTest implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("刷新IOC容器前可以加自己的扩展点。");
}
}
刷新IOC容器完成后触发:
1、实现接口ApplicationListener#onApplicationEvent的方法可以监听容器刷新完成事件ContextRefreshedEvent
/**
* onApplicationEvent 监听容器启动过程中的事件
* 事件一如ContextRefreshedEvent :上下文刷新完毕的事件,通常用于IOC容器构建结束后处理一些逻辑
*/
@Component
public class ApplicationListenerTest implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if(event instanceof ContextRefreshedEvent){
// IOC容器启动完成刷新事件
System.out.println("ContextRefreshedEvent :上下文刷新完毕的事件,通常用于IOC容器构建结束后处理一些逻辑");
}
System.out.println("spring event :"+event);
}
}