spring初始化bean时执行某些方法完成特定的初始化操作
程序员文章站
2022-10-20 10:36:54
spring初始化bean时执行某些方法完成特定的初始化操作 ......
在项目中经常会在容器启动时,完成特定的初始化操作,如资源文件的加载等。
一 实现的方式有三种:
1.使用@PostConstruct注解,该注解作用于void方法上
2.在配置文件中配置init-method方法
<bean id="student" class="com.demo.spring.entity.Student" init-method="init2"> <property name="name" value="景甜"></property> <property name="age" value="28"></property> <property name="school" ref="school"></property> </bean>
3.将类实现InitializingBean接口
package com.demo.spring.entity; import javax.annotation.PostConstruct; import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Component; /** * @author chenyk * @date 2018年5月8日 */ @Component("student") public class Student implements InitializingBean{ private String name; private int age; private School school; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public School getSchool() { return school; } public void setSchool(School school) { this.school = school; } //1.使用postconstrtct注解 @PostConstruct public void init(){ System.out.println("执行 init方法"); } //2.在xml配置文件中配置init-method方法 public void init2(){ System.out.println("执行init2方法 "); } //3.实现InitializingBean接口 public void afterPropertiesSet() throws Exception { System.out.println("执行init3方法"); } }
执行结果:
执行 init方法
2018-06-11 10:09:16,195 DEBUG [AbstractAutowireCapableBeanFactory.java:1671] : Invoking afterPropertiesSet() on bean with name 'student'
执行init3方法
2018-06-11 10:09:36,459 DEBUG [AbstractAutowireCapableBeanFactory.java:1731] : Invoking init method 'init2' on bean with name 'student'
执行init2 方法
二 实现原理:
由以上执行结果可知:先执行@PostConstruct注解的方法,然后是实现了InitializingBean接口的afterPropertiesSet方法,最后执行在配置文件中配置的init-method方法。至于为什么是这个顺序,可以看源码:
在 AbstractAutowireCapableBeanFactory 类中
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { invokeAwareMethods(beanName, bean); return null; } }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try {
//调用初始化方法 invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
然后进入到 invokeInitMethods 方法中
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable { boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isDebugEnabled()) { logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { @Override public Object run() throws Exception { ((InitializingBean) bean).afterPropertiesSet(); return null; } }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else {
//直接调用 InitializingBean 接口中的 afterPropertiesSet 方法 ((InitializingBean) bean).afterPropertiesSet(); } } if (mbd != null) { String initMethodName = mbd.getInitMethodName(); if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) {
//进入该方法可知通过反射的方式调用init-method方法 invokeCustomInitMethod(beanName, bean, mbd); } } }
所以,初始化方法的执行顺序 afterPropertiesSet() > init-method()
博客园的第一篇文章。感觉博客园很干净,文章排版特别是插入代码格式看起来很舒服。就不吐槽csdn了。