您的位置:首页 > 编程语言 > Java开发

Spring Bean的初始化和销毁方式详解

2016-10-26 22:51 417 查看
最近在项目中需要封装kafka的服务,其中使用到了工厂模式,该模式涉及到了Spring Bean的初始化和销毁,如是研究了一番,总结如下,和大家共勉之

Spring Bean的初始化和销毁Bean有几种方法了?答案是3种

方法一:使用@PostConstruct注解初始化,使用@PreDestroy注解销毁Bean

示例代码如下:

public class PostConstructInit {
@PostConstruct
public void PostConstruct() {
System.out.println("执行PostConstructInit: PostConstruct");
}

@PreDestroy
public void PreDestory(){
System.out.println("执行PostConstructInit: PreDestory");
}

public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"classpath:beans.xml");
context.close();
}
}

配置文件如下:

<context:annotation-config/>
<context:component-scan base-package="com.chhliu.myself.spring.test"></context:component-scan>
<bean id="postConstructor" class="com.chhliu.myself.spring.test.PostConstructInit"></bean>
测试结果如下:

执行PostConstructInit: PostConstruct

执行PostConstructInit: PreDestory

方法二:实现InitializingBean, DisposableBean这两个接口,并复写afterPropertiesSet()和destroy()方法

示例代码如下:

public class InitializingDisposableInit implements InitializingBean,
DisposableBean {

@Override
public void destroy() throws Exception {
System.out.println("执行InitializingDisposableInit: destroy");
}

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("执行InitializingDisposableInit: afterPropertiesSet");
}

public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"classpath:beans-impl.xml");
context.close();
}
}
测试结果如下:
执行InitializingDisposableInit: afterPropertiesSet

执行InitializingDisposableInit: destroy

方法三:使用init-method和destroy-method配置方法

示例代码如下:

public class MethodInit {

public void initMethod() {
System.out.println("执行MethodInit: init-method");
}

public void destroyMethod() {
System.out.println("执行MethodInit: destroy-method");
}

public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"classpath:beans-method.xml");
context.close();
}
}

配置文件如下:

<bean id="methodInit" class="com.chhliu.myself.spring.test.MethodInit" init-method="initMethod" destroy-method="destroyMethod"></bean>测试结果如下:
执行MethodInit: init-method

执行MethodInit: destroy-method

那么三种初始化和销毁Spring Bean的方式就讲完了,那么这三种方式的执行顺序是如何了,我们接着来做个测试

测试代码如下:

public class InitAndDestroySeqBean implements InitializingBean, DisposableBean {
public InitAndDestroySeqBean() {
System.out.println("执行InitAndDestroySeqBean: 构造方法");
}

@PostConstruct
public void postConstruct() {
System.out.println("执行InitAndDestroySeqBean: postConstruct");
}

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("执行InitAndDestroySeqBean: afterPropertiesSet");
}

public void initMethod() {
System.out.println("执行InitAndDestroySeqBean: init-method");
}

@PreDestroy
public void preDestroy() {
System.out.println("执行InitAndDestroySeqBean: preDestroy");
}

@Override
public void destroy() throws Exception {
System.out.println("执行InitAndDestroySeqBean: destroy");
}

public void destroyMethod() {
System.out.println("执行InitAndDestroySeqBean: destroy-method");
}

public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"classpath:applicationContext.xml");
context.close();
}
}

测试结果如下:

执行InitAndDestroySeqBean: 构造方法
执行InitAndDestroySeqBean: postConstruct
执行InitAndDestroySeqBean: afterPropertiesSet
执行InitAndDestroySeqBean: init-method
执行InitAndDestroySeqBean: preDestroy
执行InitAndDestroySeqBean: destroy
执行InitAndDestroySeqBean: destroy-method
最后我们得出的结果如下:

初始化顺序:
Constructor > @PostConstruct >InitializingBean > init-method
销毁的顺序如下:
@PreDestroy > DisposableBean > destroy-method
最后,我们总结下这几种方式的特点
1、如果我们在afterPropertiesSet()方法中抛出异常,那么初始化会被终止,不会执行后面的init-method对应的初始化方法

2、Spring中初始化的Bean的类为

Org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

3、afterPropertiesSet()方法的效率比init-method高,因为init-method使用的是反射来寻找对应的方法,而afterPropertiesSet()则是直接执行的,相关源码如下:

init-method:
String initMethodName = mbd.getInitMethodName();
final Method initMethod = (mbd.isNonPublicAccessAllowed() ?
BeanUtils.findMethod(bean.getClass(), initMethodName) :
ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));
从上面的代码可以看出,使用的是放射方式

afterPropertiesSet():
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
throws Throwable {
// 如果存在afterPropertiesSet方法且实例是InitializingBean类型的话,就直接执行afterPropertiesSet()方法
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>() {
public Object run() throws Exception {
((InitializingBean) bean).afterPropertiesSet();
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
}
4、init-method只能是无参无返回的public方法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: