spring bean初始化扩展之InitializingBean和 init-method源码解析

spring bean初始化扩展之InitializingBean和 init-method源码解析

  • InitializingBean和init-method介绍
    • InitializingBean
    • init-method
  • InitializingBean和init-method的作用执行时机
  • InitializingBean和init-method的比较
  • 代码示例
    • Cat.java
    • Car.java
    • MainConfigOfLifeCycle.java
    • IOCTest_LifeCycle.java
    • 运行结果

InitializingBean和init-method介绍

InitializingBean

InitializingBean是一个接口,它定义了一个afterPropertiesSet方法

public interface InitializingBean {

	/**
	 * Invoked by the containing {@code BeanFactory} after it has set all bean properties
	 * and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
	 * 

This method allows the bean instance to perform validation of its overall * configuration and final initialization when all bean properties have been set. * @throws Exception in the event of misconfiguration (such as failure to set an * essential property) or if initialization fails for any other reason */ void afterPropertiesSet() throws Exception; }

init-method

init-method,一般我们在bean中会定义相关的初始化方法,希望spring容器初始bean时,调用我们定义的初始化方法,而这个方法我们一般会通过在xml配置bean时通过init-method标签来指定对应的初始化方法,或者是现在流行的注解式开发,通过@Bean(initMethod=“xxx”)指定对应的初始化方法。

@Configuration
public class MainConfigOfLifeCycle {
	@Bean(initMethod="init")
	public Car car(){
		return new Car();
	}
}

InitializingBean和init-method的作用执行时机

继续通过AbstractAutowireCapableBeanFactory中初始化bean的源码中,了解一下InitializingBean和init-method的作用执行时机。

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			//调用调用此方法进行部分Aware接口的回调
			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;
	}

可以看到在bean的初始化过程中,执行完Aware扩展和BeanPostProcessor扩展的前置处理后,调用了初始化方法invokeInitMethods

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {

		//如果当前bean实现了InitializingBean
		boolean isInitializingBean = (bean instanceof InitializingBean);
		if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
			if (logger.isTraceEnabled()) {
				logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
			}
			if (System.getSecurityManager() != null) {
				try {
					AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
						((InitializingBean) bean).afterPropertiesSet();
						return null;
					}, getAccessControlContext());
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
				//直接调用afterPropertiesSet
				((InitializingBean) bean).afterPropertiesSet();
			}
		}

		if (mbd != null && bean.getClass() != NullBean.class) {
			//获取bean的初始化方法,也就init-method指定的方法
			String initMethodName = mbd.getInitMethodName();
			if (StringUtils.hasLength(initMethodName) &&
					!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.isExternallyManagedInitMethod(initMethodName)) {
				//使用反射机制调用init-method指定的方法
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}

可以看到这个方法里面,首先是判断当前bean时候实现了InitializingBean接口,是的话,调用其afterPropertiesSet方法,接着获取该bean init-method指定的初始化方法,然后通过反射的方式调用指定的初始化方法。因此我们可以总结InitializingBean和init-method的作用其实就是在bean初始化的时候,可以调用自定义的初始化方法,对bean进行额外的初始化扩展。

InitializingBean和init-method的比较

通过上面的分析,InitializingBean和init-method可以说是具有一样的作用,那它们之间的区别是什么呢,可以看到InitializingBean是一个接口,想要使用它的bean必须继承它,因此,使用InitializingBean是对bean具有侵入性的。而使用init-method,使我们通过标签或者注解的方式去指定,这样的方式是没有侵入性。但是由于前面分析init-method是通过反射的方式去调用初始化方法,因此相对于InitializingBean来说性能会比较差。一般情况下,我们更倾向使用没有侵入性的方式,也就是init-method来做初始化方法。

代码示例

Cat.java

实现InitializingBean接口中的afterPropertiesSet方法。

@Component
public class Cat implements InitializingBean,DisposableBean {
	
	public Cat(){
		System.out.println("cat constructor...");
	}

	@Override
	public void destroy() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("cat...destroy...");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("cat...afterPropertiesSet...");
	}

}

Car.java

定义了init方法

public class Car {
	
	public Car(){
		System.out.println("car constructor...");
	}
	
	public void init(){
		System.out.println("car ... init...");
	}
	
	public void detory(){
		System.out.println("car ... detory...");
	}

}

MainConfigOfLifeCycle.java

1,@ComponentScan配置扫描将Cat由spring容器管理
2,@Bean(initMethod=“init”,destroyMethod=“detory”)配置bean Car并指定初始化方法为init

@ComponentScan("spring.annotation.pobean.lifecycle")
@Configuration
public class MainConfigOfLifeCycle {

	@Bean(initMethod="init",destroyMethod="detory")
	public Car car(){
		return new Car();
	}

}

IOCTest_LifeCycle.java

编写单元测试,创建容器

public class IOCTest_LifeCycle {

    @Test
    public void test01(){
        //1、创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");
        //关闭容器
        applicationContext.close();
    }

}

运行结果

可以看到InitializingBean和init-method都生效了
spring bean初始化扩展之InitializingBean和 init-method源码解析_第1张图片

你可能感兴趣的:(java,spring,spring源码解析)