首页 > 编程知识 正文

springbean生命周期详解,描述一下Spring Bean的生命周期

时间:2023-05-05 16:45:35 阅读:278868 作者:2719

前言

理清Spring容器管理Bean的过程有助于我们更好地根据需求制定更合理的设计方案,提升系统扩展性和执行效率。

Bean生命周期

下面通过简单的示例来理清Bean在Spring容器中的生命周期。

我们从整体到细节,首先是启动容器加载Bean,这是一个整体的过程。

/** * 测试 Spring Bean 生命周期 * @author zyj */public class LifeCycleTest { @Test public void testLifeCycle() { // 通过注解开启容器,并加载Bean AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(GlobalConfig.class); // 关闭容器 context.close(); }}@Configurationpublic class GlobalConfig { @Bean public Calculator calculator() { return new Calculator(); } /** * @Order:加载到容器的优先级,越小代表优先级越高 * @return */ @Order(0) @Bean public FullyBeanPostProcessor fullyBeanPostProcessor() { return new FullyBeanPostProcessor(); }}

接着看看容器在加载Bean的时候都做了哪些处理。

我们需要对Bean加入Spring提供的接口,这些接口可以看做是给开发者干预加载Bean的过程的入口。

public class Calculator implements BeanNameAware, ApplicationContextAware { public Calculator() { System.out.println("<<<构造器执行>>>"); } @Override public void setBeanName(String name) { System.out.println("<<<BeanNameAware.setBeanName执行>>>"); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("<<<ApplicationContextAware.setApplicationContext执行>>>"); } @PostConstruct public void init() { System.out.println("<<<@PostConstruct执行>>>"); }@PreDestroy public void destroy() { System.out.println("<<<@PreDestroy执行>>>"); }}

从代码可以看到这里有以下几个接口以及注解:

BeanNameAware:获取当前Bean在容器中的名字ApplicationContextAware:为当前Bean注入容器@PostConstruct:初始化方法(相当于Spring配置文件中的init-method、接口InitializingBean)@PreDestroy:销毁方法(相当于Spring配置文件中的destroy-method、接口DisposableBean) 执行顺序 三月 06, 2020 3:09:52 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@4f47d241: startup date [Fri Mar 06 15:09:52 CST 2020]; root of context hierarchy三月 06, 2020 3:09:52 下午 org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker postProcessAfterInitialization信息: Bean 'globalConfig' of type [class com.zyj.spring.config.GlobalConfig$$EnhancerBySpringCGLIB$$5aa1013d] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)<<<构造器执行>>><<<BeanNameAware.setBeanName执行>>><<<ApplicationContextAware.setApplicationContext执行>>><<<BeanPostProcessor.postProcessBeforeInitialization执行>>><<<@PostConstruct执行>>><<<BeanPostProcessor.postProcessAfterInitialization执行>>>三月 06, 2020 3:09:52 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@4f47d241: startup date [Fri Mar 06 15:09:52 CST 2020]; root of context hierarchy<<<@PreDestroy执行>>>Process finished with exit code 0

细心的小伙伴肯定注意到了BeanPostProcessor的执行,我在Calculator中没有实现该接口,为什么加载的时候会打印呢?

一开始我理所应当地认为应该由每个Bean来实现BeanPostProcessor,这样就可以在@PostConstruct执行前后进行处理了。

但是我错了,验证的结果就是在加载当前Bean的时候并没有执行它所实现的BeanPostProcessor。

在找了一些资料之后,才了解BeanPostProcessor的用法。

请看上面的配置类,你可能漏掉了GlobalConfig中的FullyBeanPostProcessor。

public class FullyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof Calculator) { System.out.println("<<<BeanPostProcessor.postProcessBeforeInitialization执行>>>"); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof Calculator) { System.out.println("<<<BeanPostProcessor.postProcessAfterInitialization执行>>>"); } return bean; }}

BeanPostProcessor由单独一个类来执行,统一由这个类来判断对哪些Bean执行哪些处理。

应用场景 ApplicationContextAware

作用:通过它,可以获取到Spring容器

应用场景:当实例并没有交给Spring管理时,我们就不能使用自动注入了。比如Utils使用Dao,这个时候就可以通过一个持有Spring容器的组件来获取Dao。

@Componentpublic class SpringJobBeanFactory implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringJobBeanFactory.applicationContext=applicationContext; }public static ApplicationContext getApplicationContext() {return applicationContext; } @SuppressWarnings("unchecked") public static <T> T getBean(String name) throws BeansException {if (applicationContext == null){return null;}return (T)applicationContext.getBean(name);}}使用:TypeDao typeDao = SpringJobBeanFactory.getBean("typeDao");

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。