一、概念
Bean创建的流程图
Bean的创建生命周期
UserService.class —> 无参构造方法—>普通对象—>依赖注入(属性赋值、BeanNameAware接口、BeanClassLoaderAware接口、BeanFactoryAware接口)—>初始化前(postconstruct)—>初始化(initializingBean)—>初始化后(aop)—>代理对象—>Bean
1. 构造方法创建对象
利用该类的构造方法来实例化得到一个对象(但是如何一个类中有多个构造方法,Spring则会进行选择,这个叫做推断构造方法)
2.依赖注入
得到一个对象后,Spring会判断该对象中是否存在被@Autowired注解了的属性,把这些属性找出来并由Spring进行赋值(依赖注入)
3.回调
依赖注入后,Spring会判断该对象是否实现了BeanNameAware接口、BeanClassLoaderAware接口、BeanFactoryAware接口,如果实现了,就表示当前对象必须实现该接口中所定义的setBeanName()、setBeanClassLoader()、setBeanFactory()方法,那Spring就会调用这些方法并传入相应的参数(Aware回调)
4.@PostConstruct
Aware回调后,Spring会判断该对象中是否存在某个方法被@PostConstruct注解了,如果存在,Spring会调用当前对象的此方法(初始化前)
5.InitializingBean
紧接着,Spring会判断该对象是否实现了InitializingBean接口,如果实现了,就表示当前对象必须实现该接口中的afterPropertiesSet()方法,那Spring就会调用当前对象中的afterPropertiesSet()方法(初始化)
6.AOP
最后,Spring会判断当前对象需不需要进行AOP,如果不需要那么Bean就创建完了,如果需要进行AOP,则会进行动态代理并生成一个代理对象做为Bean(初始化后)
创建完成后,Bean对象会存储在一个Map集合里
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
二、spring生命周期的流程
示例详解:
步骤1、
豆子工厂(BeanFactory)从xml文件、java配置或注解配置中读取“各种豆子的生产方法说明(BeanDefinition)
步骤2、
这些豆子分为“特殊豆子(实现spring指定的某些接口)”和“普通豆子”, 豆子工厂先生产出这些特殊豆子
步骤3和4
特殊豆子调用特定接口(例如BeanFactoryPostProcessor接口),可以对豆子工厂(BeanFactory)进行修改,或添加一些新豆子生产方法(即注册新的BeanDefinition到BeanFactory中)
步骤5
豆子工厂(BeanFactory)执行getBean方法生产其他的普通裸豆子。(调用类的构造方法,或FactoryBean的getObject方法,以及@Bean注解的方法)
步骤6
设置豆子的依赖关系以及属性值。
步骤7
调用豆子的@PostConstruct指定的方法
步骤8
调用豆子的InitializingBean接口方法
步骤9
调用豆子的initMethod指定的方法。总结上述过程, 我们可以得到以下执行顺序 :
BeanFactoryPostProcessor ---> 普通Bean构造方法 ---> 设置依赖或属性 ---> @PostConstruct ---> InitializingBean ---> initMethod
三、BeanPostProcessor 与 BeanFactoryPostProcessor的区别
BeanFactoryPostProcessor:
是针对于beanFactory的扩展点,即spring会在beanFactory初始化之后,beanDefinition都已经loaded,但是bean还未创建前进行调用,可以修改,增加beanDefinition
BeanPostProcessor:
是针对bean的扩展点,即spring会在bean初始化前后 调用方法对bean进行处理
示例:
1.实体类
public class MyUser implements InitializingBean {
private String name;
private String desc;
public MyUser() {
System.out.println("2.无参构造,创建对象");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("3.调用setName()方法");
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
System.out.println("4.调用setDesc()方法");
this.desc = desc;
}
@Override
public String toString() {
return "MyUser{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("6.调用afterPropertiesSet() 初始化对象");
this.name="韦小宝";
this.desc="老子不干了";
}
//创建对象时指定initMethod
public void initMethod(){
System.out.println("7.调用initMethod()方法");
}
}
2.BeanFactoryPostProcessor实现类
@Component
public class MyUserBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("1.调用 BeanFactoryPostProcessor 的 postProcessBeanFactory(),执行时机:Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行");
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("myUser");
MutablePropertyValues pv = beanDefinition.getPropertyValues();
if (pv.contains("desc")) {
pv.addPropertyValue("desc", "在BeanFactoryPostProcessor中修改之后的备忘信息");
}
}
}
3.BeanPostProcessor实现类
@Component
public class MyUserBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("myUser")) {
System.out.println("5.BeanPostProcessor,对象:" + beanName + ",在调用初始化(afterPropertiesSet)之前的数据:" + bean.toString());
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("myUser")) {
System.out.println("8.BeanPostProcessor,对象:" + beanName + ",在调用初始化(initMethod)之后的数据:" + bean.toString());
}
return bean;
}
}
4.配置类
@Configuration
@ComponentScan(value = "com.attuling.postprocessor")
public class PostProcessorConfig {
@Bean(initMethod = "initMethod")
public MyUser myUser(){
MyUser myUser = new MyUser();
myUser.setName("至尊宝");
myUser.setDesc("他好像一条狗");
return myUser;
}
}
5.启动类
public class PostProcessorTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PostProcessorConfig.class);
System.out.println("实例化、初始化bean完成");
MyUser myUser = (MyUser)context.getBean("myUser");
System.out.println("Name:"+myUser.getName());
System.out.println("Desc:"+myUser.getDesc());
}
}
输出结果:
1.
调用 BeanFactoryPostProcessor 的 postProcessBeanFactory(),执行时机:Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行
2.无参构造,创建对象
3.调用setName()方法
4.调用setDesc()方法
5.
BeanPostProcessor,对象:myUser,在调用初始化之前的数据:MyUser{name=‘至尊宝’, desc=‘他好像一条狗’}
6.调用afterPropertiesSet() 初始化对象
7.调用initMethod()方法
8.
BeanPostProcessor,对象:myUser,在调用初始化之后的数据:MyUser{name=‘韦小宝’, desc=‘老子不干了’}
实例化、初始化bean完成
Name:韦小宝
Desc:老子不干了
结论:
BeanFactoryPostProcessor
实现类是在加载完beanDefinition,但还未调用构造创建对象的时候执行postProcessBeanFactory()
BeanPostProcessor
实现类是在Bean实例化之后、初始化(包括afterPropertiesSet和initMethod)前后分别执行postProcessBeforeInitialization和postProcessAfterInitialization
BeanPostProcessor执行时机
四、BeanFactory与FactoryBean的区别
BeanFactory
BeanFactory创建对象的核心是:工厂、反射
在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
我们通过getBean()方法,传入参数——bean的名称或者类型,便可以从Spring容器中来获取bean。
BeanFactory是用于访问Spring容器的根接口,是从Spring容器中获取Bean对象的基础接口,提供了IOC容器最基本的形式,给具体的IOC容器的实现提供了规范。
BeanFactory只是个接口,并不是IOC容器的具体实现,Spring容器给出了很多种 BeanFactory的 扩展实现,如:DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等
FactoryBean
Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口,然后在getObject()方法中灵活配置,来定制实例化Bean的逻辑
上面提到,我们可以通过BeanPostPorcessor来干涉Spring创建Bean的过程,但是如果我们想一个Bean完完全全由我们来创造,也是可以的,比如通过FactoryBean。但是通过这种方式创造出来的UserService的Bean,只会经过初始化后,其他Spring的生命周期步骤是不会经过的,比如依赖注入
五、Spring事务
当我们在某个方法上加了@Transactional注解后,就表示该方法在调用时会开启Spring事务,而这个方法所在的类所对应的Bean对象会是该类的代理对象。
Spring事务的代理对象执行某个方法时的步骤:
- 判断当前执行的方法是否存在@Transactional注解
- 如果存在,则利用事务管理器(TransactionMananger)新建一个数据库连接
- 修改数据库连接的autocommit为false
- 执行target.test(),执行程序员所写的业务逻辑代码,也就是执行sql
- 执行完了之后如果没有出现异常,则提交,否则回滚
六、spring中的扩展点
1.自定义拦截器
实现HandlerInterceptor 接口 重写 preHandle 目标方法执行前执行 postHandle 目标方法执行后执行 afterCompletion 请求完成时执行
2.获取spring容器对象
实现BeanFactoryAware接口 ApplicationContextAware接口 ApplicationListener接口
3.全局异常处理
@RestControllerAdvice
4.类型转换器
spring目前支持3中类型转换器: Converter<S,T>:将 S 类型对象转为 T 类型对象 ConverterFactory<S, R>:将 S 类型对象转为 R 类型及子类对象
GenericConverter:它支持多个source和目标类型的转化,同时还提供了source和目标类型的上下文,这个上下文能让你实现基于属性上的注解或信息来进行类型转换
5.导入配置
@Import 注解
6.项目启动时
CommandLineRunner ApplicationRunner
7.修改BeanDefinition
实现BeanFactoryPostProcessor接口,重写postProcessBeanFactory 方法
8.初始化Bean前后
实现BeanPostProcessor接口,重写 postProcessBeforeInitialization 该在初始化方法之前调用。 postProcessAfterInitialization 该方法再初始化方法之后调用。
9.初始化
@PostConstruct
实现InitializingBean接口
10.关闭容器前
DisposableBean接口,并且重写它的destroy方法
11.自定义作用于
实现Scope接口
七、spring中的bean是线程安全的吗?
作用域。
Spring中的Bean可以分为单例(singleton)和原型(prototype)两种作用域。对于原型(prototype)作用域的Bean,每次获取都会创建一个新的实例,因此这些Bean不是线程安全的。而单例(singleton)作用域的Bean在所有线程中共享同一个实例,如果有状态(即保存了数据),则可能存在线程安全问题。
状态。
如果Bean是无状态的,那么它通常是线程安全的,因为无状态的Bean不会保存任何数据,不会影响多线程环境下的数据一致性。
因此,不能一概而论地说Spring的Bean是线程安全的,需要具体分析Bean的作用域
和是否具有状态
。