温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

使用spring容器在初始化Bean时前和后的操作是怎样的

发布时间:2021-09-24 14:54:32 来源:亿速云 阅读:191 作者:柒染 栏目:开发技术

本篇文章给大家分享的是有关使用spring容器在初始化Bean时前和后的操作是怎样的,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧

spring容器初始化Bean操作

在某些情况下,Spring容器在初始化Bean的时候,希望在初始化bean前和销毁bean前进行一些资源的加载和释放的操作。可以通过一下三种方式完成。

  • Bean的方法加上@PostConstruct和@PreDestroy注解

  • 在xml中定义init-method和destory-method方法

  • Bean实现InitializingBean和DisposableBean接口

@PostConstruct和@PreDestroy注解

JavaBean代码

@Component public class PersonService {     private String message;     public String getMessage() {         return message;     }     public void setMessage(String message) {         this.message = message;     }     @PostConstruct     public void init() {         System.out.println("PersonService.class init method ...");     }     @PreDestroy     public void cleanUp() {         System.out.println("PersonService.class cleanUp method ...");     } }

spring配置文件

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"     xsi:schemaLocation="         http://www.springframework.org/schema/beans          http://www.springframework.org/schema/beans/spring-beans-4.2.xsd                 http://www.springframework.org/schema/context          http://www.springframework.org/schema/context/spring-context-4.2.xsd         http://www.springframework.org/schema/aop          http://www.springframework.org/schema/aop/spring-aop-4.2.xsd         http://www.springframework.org/schema/mvc          http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd">     <!-- spring扫描的路径 -->     <context:component-scan base-package="spring.zhujie" /> </beans>

测试代码和结果

测试代码

public static void main(String[] args) {      AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring-zhujie.xml");      context.registerShutdownHook(); }

运行结果

PersonService.class init method ...

PersonService.class cleanUp method ...

在XML中定义init-method和destory-method方法

JavaBean代码

public class PersonService {     private String message;     public String getMessage() {         return message;     }     public void setMessage(String message) {         this.message = message;     }     public void init() {         System.out.println("PersonService.class init method ...");     }     public void cleanUp() {         System.out.println("PersonService.class cleanUp method ...");     } }

spring配置文件

<bean class="spring.zhujie.PersonService" init-method="init" destroy-method="cleanUp"/>

测试代码和结果

测试代码

public static void main(String[] args) {         AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring-xml.xml");         context.registerShutdownHook(); }

运行结果

PersonService.class init method ...

六月 23, 2017 9:42:06 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose

信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@7a94c5e7: startup date [Fri Jun 23 21:42:06 CST 2017]; root of context hierarchy

PersonService.class cleanUp method ...

Bean实现InitializingBean和DisposableBean接口

JavaBean代码

public class PersonService implements InitializingBean, DisposableBean {     private String message;     public String getMessage() {         return message;     }     public void setMessage(String message) {         this.message = message;     }     @Override     public void afterPropertiesSet() throws Exception {         System.out.println("PersonService.class init method ...");     }     @Override     public void destroy() throws Exception {         System.out.println("PersonService.class cleanUp method ...");     } }

spring配置文件

<bean id="personService" class="spring.zhujie.PersonService" />

测试代码和结果

测试代码

public static void main(String[] args) {         AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring-interface.xml");         context.registerShutdownHook();     }

运行结果

PersonService.class init method ...

PersonService.class cleanUp method ...

Spring bean 初始化顺序

InitializingBean, init-method 和 PostConstruct

1、概述

从接口的名字上不难发现,InitializingBean 的作用就是在 bean 初始化后执行定制化的操作。

Spring 容器中的 Bean 是有生命周期的,Spring 允许在 Bean 在初始化完成后以及 Bean 销毁前执行特定的操作,常用的设定方式有以下三种:

通过实现 InitializingBean/DisposableBean 接口来定制初始化之后/销毁之前的操作方法;

通过 <bean> 元素的 init-method/destroy-method 属性指定初始化之后 /销毁之前调用的操作方法;

在指定方法上加上@PostConstruct 或@PreDestroy注解来制定该方法是在初始化之后还是销毁之前调用。

2、InitializingBean vs init-method

接口定义如下:

public interface InitializingBean {     void afterPropertiesSet() throws Exception; }

接口只有一个方法afterPropertiesSet,

此方法的调用入口是负责加载 spring bean 的AbstractAutowireCapableBeanFactory,源码如下:

protected void invokeInitMethods(String beanName, Object bean,    RootBeanDefinition mbd) throws Throwable {   boolean isInitializingBean = bean instanceof InitializingBean;   if ((isInitializingBean)     && (((mbd == null) || (!(mbd       .isExternallyManagedInitMethod("afterPropertiesSet")))))) {    if (this.logger.isDebugEnabled()) {     this.logger       .debug("Invoking afterPropertiesSet() on bean with name '"         + beanName + "'");    }    //先调用afterPropertiesSet()进行初始化    if (System.getSecurityManager() != null) {     try {      AccessController.doPrivileged(        new PrivilegedExceptionAction(bean) {         public Object run() throws Exception {          ((InitializingBean) this.val$bean)            .afterPropertiesSet();          return null;         }        }, getAccessControlContext());     } catch (PrivilegedActionException pae) {      throw pae.getException();     }    } else {     ((InitializingBean) bean).afterPropertiesSet();    }   }      //然后调用InitMethod()进行初始化   if (mbd != null) {    String initMethodName = mbd.getInitMethodName();    if ((initMethodName == null)      || ((isInitializingBean) && ("afterPropertiesSet"        .equals(initMethodName)))      || (mbd.isExternallyManagedInitMethod(initMethodName)))     return;    invokeCustomInitMethod(beanName, bean, mbd);   }  }

从这段源码可以得出以下结论:

spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中通过init-method指定,两种方式可以同时使用

实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率相对来说要高点。但是init-method方式消除了对spring的依赖

先调用afterPropertiesSet,再执行 init-method 方法,如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法

3、@PostConstruct

通过 debug 和调用栈找到类InitDestroyAnnotationBeanPostProcessor, 其中的核心方法,即 @PostConstruct 方法调用的入口:

@Override     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {         LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());         try {             metadata.invokeInitMethods(bean, beanName);         }         catch (InvocationTargetException ex) {             throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());         }         catch (Throwable ex) {             throw new BeanCreationException(beanName, "Failed to invoke init method", ex);         }         return bean;     }

从命名上,我们就可以得到某些信息——这是一个BeanPostProcessor。BeanPostProcessor的postProcessBeforeInitialization是在Bean生命周期中afterPropertiesSet和init-method之前被调用的。另外通过跟踪,@PostConstruct方法的调用方式也是通过反射机制。

4、小结一下吧

spring bean的初始化执行顺序:构造方法 --> @PostConstruct注解的方法 --> afterPropertiesSet方法 --> init-method指定的方法。具体可以参考例子

afterPropertiesSet通过接口实现方式调用(效率上高一点),@PostConstruct和init-method都是通过反射机制调用

同理,bean销毁过程的顺序为:@PreDestroy > DisposableBean > destroy-method

不再展开,看源码就好

测试代码如下:

@Slf4j public class InitSequenceBean implements InitializingBean {     public InitSequenceBean() {         log.info("InitSequenceBean: construct");     }     @Override     public void afterPropertiesSet() throws Exception {         log.info("InitSequenceBean: afterPropertiesSet");     }     @PostConstruct     public void postConstruct() {         log.info("InitSequenceBean: postConstruct");     }     public void initMethod() {         log.info("InitSequenceBean: initMethod");     } } @Configuration public class SystemConfig {     @Bean(initMethod = "initMethod", name = "initSequenceBean")     public InitSequenceBean initSequenceBean() {         return new InitSequenceBean();     } } @Slf4j public class InitSequenceBeanTest extends ApplicationTests {     @Autowired     private InitSequenceBean initSequenceBean;     @Test     public void initSequenceBeanTest() {         log.info("Finish: {}", initSequenceBean.toString());     } }

以上就是使用spring容器在初始化Bean时前和后的操作是怎样的,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI