一文解读Spring Bean的生命周期
作者:山河亦问安
1. Spring IOC容器
1.1 Spring IOC 容器的设计
Spring IOC 容器的设计主要是基于BeanFactory和ApplicationContext两个接口,其中ApplicationContext是BeanFactory的子接口之一,换句话说BeanFactory是Spring IOC容器所定义的最顶层接口,而ApplicationContext是其高级接口之一,并且对于BeanFactory功能做了许多有用的扩展,所以在绝大部分的工作场景中,都会使用ApplicationContext作为Spring IOC 容器,如下图所示:
首先我们定义一个User实体类:
public class User { String username; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @Override public String toString() { return "User{" + "username='" + username + '\'' + '}'; } }
1.1.1 BeanFactory
BeanFactory的使用注册Bean对象以及获取Bean对象代码如下:
DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory(); RootBeanDefinition rootBeanDefinition=new RootBeanDefinition(User.class); beanFactory.registerBeanDefinition("user",rootBeanDefinition); System.out.println(beanFactory.getBean("user",User.class));
1.1.2 ApplicationContext
ApplicationContext的使用注册Bean对象以及获取Bean对象代码如下:
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); applicationContext.register(User.class); applicationContext.refresh(); System.out.println(applicationContext.getBean("user", User.class));
1.2 Spring Bean的生命周期
Spring 容器可以管理 singleton 作用域 Bean 的生命周期,在此作用域下,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成,以及何时被销毁。
而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。每次客户端请求 prototype 作用域的 Bean 时,Spring 容器都会创建一个新的实例,并且不会管那些被配置成 prototype 作用域的 Bean 的生命周期。
生命周期主要是为了了解Spring IOC容器初始化和销毁Bean的过程,通过对它的学习就可以知道如何在初始化和销毁的时候加入自定义的方法,以满足特定的需求。如下图:
从上图可以看到,Spring IoC容器对Bean 的管理还是比较复杂的,Spring loC容器在执行了初始化和依赖注入后,会执行一定的步骤来完成初始化,通过这些步骤我们就能自定义初始化,而在Spring IoC 容器正常关闭的时候,它也会执行一定的步骤来关闭容器,释放资源。除需要了解整个生命周期的步骤外,还要知道这些生命周期的接口是针对什么而言的,首先介绍生命周期的步骤。
1. 如果 Bean 实现了接口 BeanNameAware的setBeanName方法,那么它就会调用这个方法。
2. 如果 Bean 实现了接口 BeanFactoryAware 的 setBeanFactory方法,那么它就会调用这个方法。
3. 如果 Bean实现了接口 ApplicationContextAware 的 setApplicationContext方法,且
Spring loC容器也必须是一个ApplicationContext 接口的实现类,那么才会调用这个方法,否则是不调用的。
4. 如果 Bean 实现了接口 BeanPostProcessor 的 postProcessBeforeInitialization方法,那么它就会调用这个方法。
5 .如果 Bean实现了接口BeanFactoryPostProcessor的afterPropertiesSet方法,那么它就会调用这个方法。
6. 如果 Bean自定义了初始化方法,它就会调用已定义的初始化方法。
7. 如果Bean 实现了接口 BeanPostProcessor 的postProcessAfterInitialization方法,完成了这些调用,这个时候Bean 就完成了初始化,那么 Bean就生存在Spring loC的容器中了,使用者就可以从中获取 Bean的服务。
8. 当服务器正常关闭,或者遇到其他关闭 Spring loC 容器的事件,它就会调用对应的方完成Bean 的销毁,其步骤如下:
如果Bean实现了接口 DisposableBean 的 destroy方法,那么就会调用它。
如果定义了自定义的销毁方法,那么就会调用它。
1.2.1 BeanDefinition
Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构。不管是是通过xml配置文件的<Bean>标签,还是通过注解配置的@Bean,还是@Compontent标注的类,还是扫描得到的类,它最终都会被解析成一个BeanDefinition对象,最后我们的Bean工厂就会根据这份Bean的定义信息,对bean进行实例化、初始化等等操作。
你可以把BeanDefinition丢给Bean工厂,然后Bean工厂就会根据这个信息帮你生产一个Bean实例,拿去使用。
BeanDefinition里面里面包含了bean定义的各种信息,如:bean对应的class、scope、lazy信息、dependOn信息、autowireCandidate(是否是候选对象)、primary(是否是主要的候选者)等信息。
RootBeanDefinition类:表示根bean定义信息,通常bean中没有父bean的就使用这种表示。
ChildBeanDefinition类:表示子bean定义信息,如果需要指定父bean的,可以使用ChildBeanDefinition来定义子bean的配置信息,里面有parentName属性,用来指定父bean的名称。
GenericBeanDefinition类:通用的bean定义信息,既可以表示没有父bean的bean配置信息,也可以表示有父bean的子bean配置信息,这个类里面也有parentName属性,用来指定父bean的名称。
ConfigurationClassBeanDefinition类:表示通过配置类中@Bean方法定义bean信息
可以通过配置类中使用@Bean来标注一些方法,通过这些方法来定义bean,这些方法配置的bean信息最后会转换为ConfigurationClassBeanDefinition类型的对象。
AnnotatedBeanDefinition接口:表示通过注解的方式定义的bean信息。
BeanDefinitionBuilder:构建BeanDefinition的工具类
1.2.2 InstantiationAwareBeanPostProcessor和BeanPostProcessor
InstantiationAwareBeanPostProcessor实际上继承了BeanPostProcessor接口。InstantiationAwareBeanPostProcessor作用于实例化阶段的前后,BeanPostProcessor作用于初始化阶段的前后。如下图:
BeanPostProcessor是一个接口,还有很多子接口,这些接口中提供了很多方法,spring在bean生命周期的不同阶段,会调用BeanPostProcessor中的一些方法,来对生命周期进行扩展,bean生命周期中的所有扩展点都是依靠这个集合中的BeanPostProcessor来实现的。该接口提供了两个函数:postProcessBeforeInitialzation( Object bean, String beanName ) 当前正在初始化的bean对象会被传递进来,我们就可以对这个bean作任何处理。 这个函数会先于InitialzationBean执行,因此称为前置处理。 所有Aware接口的注入就是在这一步完成的。postProcessAfterInitialzation( Object bean, String beanName ) 当前正在初始化的bean对象会被传递进来,我们就可以对这个bean作任何处理。 这个函数会在InitialzationBean完成后执行,因此称为后置处理。
Spring Aware是Spring定义的回调接口。何为回调?就是客户程序C调用服务程序S中的某个函数A,然后S又在某个时候反过来调用C中的某个函数B,对于C来说,这个B便叫做回调函数。
1.2.3 测试生命周期
我们自定义一个User实体类,要求Spring容器使用我们自定义的@MyAutowired注解标注的构造方法进行构造Bean对象,然后我们观察在Bean周期的日志打印,更好的理解Bean周期过程。
自定义@MyAutowired注解
@Retention(RetentionPolicy.RUNTIME) @Documented @Target(ElementType.CONSTRUCTOR) public @interface MyAutowired { }
定义User实体类
public class User implements InitializingBean, DisposableBean { String username; //Spring为了降低对客户代码的侵入性,给bean的配置提供了init-method属性, // 该属性指定了在这一阶段需要执行的函数名。Spring便会在初始化阶段执行我们设置的函数。 // init-method本质上仍然使用了InitializingBean接口。 public void init(){ System.out.println(this.getClass().getSimpleName()+" 执行自定义初始化方法"); } public User() { } @MyAutowired public User(String username) { this.username = username; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @Override public String toString() { return "User{" + "username='" + username + '\'' + '}'; } @Override public void destroy() throws Exception { System.out.println("调用DisposableBean接口的destroy方法"); } //afterPropertiesSet()这一阶段也可以在bean正式构造完成前增加我们自定义的逻辑, // 但它与前置处理不同,由于该函数并不会把当前bean对象传进来,因此在这一步没办法处理对象本身, // 只能增加一些额外的逻辑。 若要使用它,我们需要让bean实现该接口,把要增加的逻辑写在该函数中。 // 然后Spring会在前置处理完成后检测当前bean是否实现了该接口,并执行afterPropertiesSet函数 @Override public void afterPropertiesSet() throws Exception { System.out.println("调用afterPropertiesSet方法"); } }
测试代码
public class MyTest { public static void main(String[] args) { DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory(); //InstantiationAwareBeanPostProcessor接口在Bean对象实例化前的方法 beanFactory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor() { public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { if(beanName.equals("user")) System.out.println(beanName+" Bean对象在实例化之前操作**"); return null; } }); //InstantiationAwareBeanPostProcessor接口在Bean对象实例化后的方法 beanFactory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor() { public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { if(beanName.equals("user")) System.out.println(beanName+" Bean对象在实例化之后操作**"); return false; } }); //使用自己自定义含有@MyAutowired注解的构造方法,实例化Bean对象 beanFactory.addBeanPostProcessor(new SmartInstantiationAwareBeanPostProcessor() { public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException { if(beanName.equals("user")) System.out.println("实例化Bean对象"); Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors(); List<Constructor<?>> collect = Arrays.stream(declaredConstructors).filter(i -> i.isAnnotationPresent(MyAutowired.class)).collect(Collectors.toList()); Constructor[] constructors = collect.toArray(new Constructor[collect.size()]); return constructors.length>0?constructors:null; } }); //BeanPostProcessor接口在Bean对象初始化之前的方法调用 beanFactory.addBeanPostProcessor(new BeanPostProcessor() { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if(beanName.equals("user")) System.out.println(beanName+" Bean对象在初始化之前操作**"); return null; } }); //BeanPostProcessor接口在Bean对象初始化之后的方法调用 beanFactory.addBeanPostProcessor(new BeanPostProcessor() { @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(beanName.equals("user")) System.out.println(beanName+" Bean对象在初始化之后操作**"); return null; } }); RootBeanDefinition rootBeanDefinition= (RootBeanDefinition) BeanDefinitionBuilder.rootBeanDefinition(User.class).setInitMethodName("init").getBeanDefinition(); beanFactory.registerBeanDefinition("user",rootBeanDefinition); beanFactory.registerBeanDefinition("username", BeanDefinitionBuilder.genericBeanDefinition(String.class) .addConstructorArgValue("admin").getBeanDefinition()); System.out.println(beanFactory.getBean("user",User.class)); beanFactory.destroySingletons(); } }
测试截图
到此这篇关于一文解读Spring Bean的生命周期的文章就介绍到这了,更多相关Spring Bean生命周期内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!