从源码逐步分析IOC的执行流程(含流程图及总结)
Posted 小艾路西里
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从源码逐步分析IOC的执行流程(含流程图及总结)相关的知识,希望对你有一定的参考价值。
1. IOC执行流程图
2. 从源码分析IOC的执行流程
1.new ClassPathXmlApplicationContext();
或new AnnotationConfigApplicationContext();
创建 ClassPathXmlApplicationContext或AnnotationConfigApplicationContext,并传入配置文件或包名,得到配置信息或类的信息
xml是通过配置信息读取到类的信息,而注解是通过扫描包的方式获取到类的信息
2. refresh()
refresh()即是上述俩种方式中的都会执行的方法,可以说是ioc的核心
补充:在调用refresh()方法前其实还会调用super()(执行父类的构造器)
refresh方法内的主要步骤
(1)prepareRefresh(); //启动前的准备工作
设置容器关闭为false,容器激活为true,
(2)obtainFreshBeanFactory();//准备启动beanFactory
① 调用obtainFreshBeanFactory()方法,获得一个新的空bean工厂
② 调用prepareBeanFactory()方法,读取xml配置文件中的属性值并封装到BeanDefinition中
(3) PostProcessBeanFactory(); //用于在bean初始化前,改变bean的定义信息
调用PostProcessBeanFactory()方法,可以在初始化bean前,改变bean的定义信息,该方法为空,所以需要重写
(4) 中间有很多执行方法,包括执行PostProcess,添加bean创建过程的观察者,初始化特殊的bean等,不过不重要,就省略了…
(5) finishBeanFactoryInitialization(beanFactory); //传入bean工厂,并实例化bean(重点)
调用finishBeanFactoryInitialization(beanFactory)方法,传入bean工厂,并实例化bean(重点)(实例化所有的非懒加载的单例对象)
finishBeanFactoryInitialization(beanFactory)内的步骤
① preInstantiateSingletons(); // 保存并遍历beanName查找是否有现成的,没有就调用getBean()方法
在preInstantiateSingletons()方法中,beanName会使用一个arraylist存储起来,去遍历beanName看有没有现成的bean,如果没有,然后就是调用getBean()方法后的一层层方法的嵌套…直到下一步
② Instaniate(); //bean的实例化
经过自getBean()方法后的一层层嵌套,最终会到达Instaniate()方法中进行实例化
也就是在这个方法中,我们终于见到了反射机制
在这个方法的最后,调用instantiateClass()去完成最后的实例化
③instantiateClass(); // 将初始化的bean实例化成一个完整的bean
在 instantiateClass()方法中,newInstance()实例化!
调用populateBean方法填充属性!
在实例化、填充属性之后,会先执行aware的方法和aop的一系列操作配置(即beforeInitalizetion和afterInitalizetion()方法去截取出切面类),添加方法,最后形成一个完整的bean对象
补充:单例模式的ioc容器就是一个ConcurrentHashMap<String,Object>
3. bean的生命周期
1. ioc启动时,寻找Bean的定义信息并将其实例化
2. 使用依赖注入,spring按照Bean定义信息配置Bean的所有属性
3. 如果Bean实现了BeanNameAware接口,工厂调用Bean的SetBeanName()方法设置BeanName
4. 如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传设置BeanFactory(Bean工厂)
5. 如果BeanPostProcessor和Bean关联,那么调用 postProcessBeforeInitialization()方法
6. 如果Bean指定了init-method方法,将被调用
7. 最后,如果有BeanPostProcessor和Bean关联,那么调用postProcessAfterInitialization()方法
此时,Bean已经可以被应用系统使用,并将被保留在BeanFactory中知道他不再被需要。有两种方式可以将其从BeanFactory中删除掉的方法
① 如果Bean实现了DisposableBean接口,destroy()方法将被调用
② 如指定了定制的销毁方法,就调用这个方法
bean生命周期的简要总结
① 使用BeanDefinition生产bean
② bean实例化前后的操作
③ 实例化bean
④ 配置bean的信息
⑤ setBeanName()
⑥ setBeanFactory()
⑦ 前置处理器和后置处理器(bean初始化前后的操作)
⑧ inti bean(初始化bean)
⑨ 使用bean
⑩ 销毁bean(destroy())
(1)在bean实例化前后进行操作
实例化或初始化前后添加操作,都是实现BeanPostProcessor接口或其子接口
① 创建实体类User,加上ioc注解
@Component
@Data
@AllArgsConstructor
//@NoArgsConstructor
public class User {
public User(){
System.out.println("执行了构造方法,完成了实例化");
}
@Value("123")
int id;
@Value("小明")
String name;
}
② 创建一个类,实现InstantiationAwareBeanPostProcessor子接口
@Component
public class UserBeanAwareInstaniate implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if(beanName.equals("user")){
System.out.println("执行了实例化前的操作");
//return new User(233,"实例化前就构造的bean");
}
return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if(beanName.equals("user")){
System.out.println("执行了实例后的操作");
}
return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);
}
}
③ 在main方法中进行测试
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class); //读取配置类
Object user1 = applicationContext.getBean("user");
User user2 = applicationContext.getBean(User.class);
System.out.println(user1);
System.out.println("=====");
System.out.println(user2);
System.out.println(user1==user2);
System.out.println(user1.equals(user2));
注意:如果实例化前对比beanName中,返回了一个对象,那么这个对象就会成为返回的bean,而且不会执行实例化后的方法,也不会执行初始化前的方法,但是初始化后的方法会执行
(2)在bean初始化前后进行操作
① User类实现InitializingBean接口,用于记录初始化结束的时间
public class User implements InitializingBean {
public User(){
System.out.println("执行了构造方法,完成了实例化");
}
@Value("123")
int id;
@Value("小明")
String name;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化完成");
}
}
② 创建一个类,同样实现InstantiationAwareBeanPostProcessor接口,添加初始化前后的操作
@Component
public class UserBeanInit implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("user")) {
System.out.println("===============");
System.out.println("执行了初始化前的方法");
// return new User(233,"初始化前创建的userBean");
}
return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("user")) {
System.out.println("执行了初始化后的方法");
// return new User(233,"初始化后创建的userBean");
}
return InstantiationAwareBeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
③ 执行
同样的,如果在初始化前后返回一个对象,那么这个对象就会成为bean
AOP也就是在初始化后实现的,调用了getProxy()方法,将对象加工成了一个代理类返回
4. bean的作用域
使用@Scope(“xxx”)或xml配置bean的作用域
作用域 | 描述 |
---|---|
singleton | 在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,bean作用域范围的默认值 |
prototype | 每次从容器中调用Bean时,都返回一个新的实例,相当于每次调用getBean()时,都执行newXxxBean() |
request | 每次HTTP请求都会创建一个新的Bean |
request | 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean |
application | 限定一个Bean的作用域为ServletContext的整个生命周期 |
注意:request、request、application仅适用于web下的Spring WebApplicationContext环境
BeanFactory和FactoryBean,ApplicationContext的区别
① BeanFactory是一个Factory接口,是用来管理bean的IOC容器或对象工厂,较为古老,不支持spring的一些插件。
BeanFactory使用了懒加载,适合多例模式。
懒加载就是BeanFactory在启动的时候不会去实例化Bean,当使用getBean()方法时才会去对应实例化bean;
② FactoryBean是一个Bean接口,是一个可以生产或者装饰对象的工厂Bean,可以通过实现该接口自定义的实例化Bean的逻辑。
③ApplicationConext是BeanFactory的子接口,扩展了其功能,ApplicationContext是立即加载,适合单例模式。ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true来让Bean懒加载;
(1) BeanFactory的使用
① 先创建一个实体类User
@Data
@AllArgsConstructor
//@NoArgsConstructor
public class User {
User(){
System.out.println("执行了构造方法");
}
int id;
String name;
}
② 在main方法中使用BeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); //创建一个Bean工厂
beanFactory.registerSingleton("user",new User()); // 向Bean工厂中注册一个单例bean
Object user1 = beanFactory.getBean("user");
Object user2 = beanFactory.getBean("user");
System.out.println(user1);
System.out.println("=====");
System.out.println(user2);
System.out.println(user1==user2);
System.out.println(user1.equals(user2));
(2) FactoryBean的使用
① 创建一个UserFactoryBean类实现FactoryBean接口
public class UserFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
return new User(233,"这是FactoryBean创建的user对象");
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
② main方法中进行测试
UserFactoryBean userFactoryBean = new UserFactoryBean();
User user1 = null;
User user2 = null;
try {
user1 = (User) userFactoryBean.getObject(); // 从userFactoryBean中获取User的bean
user2 = (User) userFactoryBean.getObject();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(user1);
System.out.println("=====");
System.out.println(user2);
System.out.println(user1==user2);
System.out.println(user1.equals(user2));
这里的equals方法经过调试发现是使用的String里的equals方法,有知道原因的希望评论区说一下
(3) ApplicationContext的使用
ApplicationContext就是ioc现在最常用的方式,有xml、注解方式去使用,下面以注解的方式使用为例
① 创建一个配置类,加上@ComponentScan注解,指定ioc要扫描的包
@ComponentScan("com.ruoxi")
public class Config {
}
② 实体类上加上ioc的注解
@Component
@Data
@AllArgsConstructor
//@NoArgsConstructor
public class User {
User(){
System.out.println("执行了构造方法");
}
@Value("123")
int id;
@Value("小明")
String name;
}
③ main方法中进行测试
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class); //读取配置类
Object user1 = applicationContext.getBean("user");
User user2 = applicationContext.getBean(User.class);
System.out.println(user1);
System.out.println("=====");
System.out.println(user2);
System.ou.println(user1==user2);
5. IOC的执行流程总结
1. 通过xml或注解的方式,获取到类的信息
2. 调用super()方法等
3. 调用refresh()方法
在refresh()方法中的主要操作
(1) 执行创建BeanFactory(bean工厂)
(2) 将类的信息封装成BeanDefinition对象
(3) 创建PostProcessBeanFactory(用于改变bean的定义信息)
(4) 调用finishBeanFactoryInitialization(beanFactory)方法,传入bean工厂,进行一层层的方法嵌套,搜索现有的bean,如果不存在,就最终在Instaniate()方法中使用反射机制,调用InstaniateClass()方法
(5) 在InstaniateClass()方法中,完成创建bean的操作,bean属性的赋值,aop的操作(init初始化bean前后的方法),形成一个完成的bean对象并返回
如有错误望评论区指正
以上是关于从源码逐步分析IOC的执行流程(含流程图及总结)的主要内容,如果未能解决你的问题,请参考以下文章