Жизненный цикл Spring Bean (пример подробно объясняется в сочетании с исходным кодом)

Java

предисловие

Эта статья в основном посвящена тому, как управлять жизненным циклом Spring Bean в контейнере Spring IoC.

При разработке приложений часто необходимо выполнить некоторые специфические задачи инициализации, которые являются относительно фиксированными, например, установить соединение с базой данных, открыть сетевое соединение и т. д. фиксированные задачи уничтожения, которые необходимо выполнить. Чтобы облегчить проектирование этих задач, контейнер Spring IoC предоставляет соответствующие функции, которые позволяют приложениям настраивать процесс инициализации и уничтожения компонентов.

Жизненный цикл Spring Bean

Описание изображения

Давайте сначала посмотрим на блок-схему жизненного цикла Spring Bean. Будет легче увидеть следующее описание в сочетании с изображением.

spring bean life cycle.png

описание слова

  1. Контейнер компонентов находит определение Spring Bean в файле конфигурации.
  2. Контейнеры компонентов используют Java Reflection API для создания экземпляров компонентов bean.
  3. Если объявлены какие-либо свойства, объявленные свойства будут установлены. Если само свойство является bean-компонентом, оно будет проанализировано и установлено.
  4. Если класс Bean реализуетBeanNameAwareинтерфейс, он будет вызываться путем передачи имени бинаsetBeanName()метод.
  5. Если класс Bean реализуетBeanClassLoaderAwareинтерфейс, он будет вызываться путем передачи экземпляра объекта ClassLoader, который загружает этот компонентsetBeanClassLoader()метод.
  6. Если класс Bean реализуетBeanFactoryAwareинтерфейс, он будет вызываться путем передачи экземпляра объекта BeanFactorysetBeanFactory()метод.
  7. Если какие-либо объекты BeanPostProcessors, связанные с BeanFactory, имеют загруженные bean-компоненты, они будут вызываться до того, как будут установлены свойства bean-компонентов.postProcessBeforeInitialization()метод.
  8. Если класс Bean реализуетInitializingBeanинтерфейс, после установки всех свойств компонента, определенных в файле конфигурации, он вызоветafterPropertiesSet()метод.
  9. Если определение bean-компонента в файле конфигурации содержитinit-methodсвойство, значение свойства будет преобразовано в имя метода в классе компонента, и метод будет вызван.
  10. Если к объекту Bean Factory подключены какие-либо постпроцессоры, он будет называтьсяpostProcessAfterInitialization()метод.
  11. Если класс Bean реализуетDisposableBeanинтерфейс, когда приложению больше не нужна ссылка на Bean, оно будет вызыватьсяdestroy()метод.
  12. Если определение bean-компонента в файле конфигурации содержитdestroy-methodсвойство, то будет вызвано соответствующее определение метода в классе Bean.

Пример демонстрации

Затем мы используем простую ДЕМОНСТРАЦИЮ, чтобы продемонстрировать ход всего жизненного цикла, чтобы углубить ваше впечатление.

  1. определитьPersonкласс, реализующийDisposableBean, InitializingBean, BeanFactoryAware, BeanNameAwareЭти 4 интерфейса, а также пользовательскиеinit-methodиdestroy-method. Здесь, если вы не знакомы с этими интерфейсами, вы можете сначала взглянуть на определения этих интерфейсов.

public class Person implements DisposableBean, InitializingBean, BeanFactoryAware, BeanNameAware {

    private String name;

    Person() {
        System.out.println("Constructor of person bean is invoked!");
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("setBeanFactory method of person is invoked");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("setBeanName method of person is invoked");
    }

    public void init() {
        System.out.println("custom init method of person bean is invoked!");
    }

    //Bean initialization code  equals to
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet method of person bean is invoked!");
    }

    //Bean destruction code
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean Destroy method of person bean is invoked!");
    }

    public void destroyMethod() {
        System.out.println("custom Destroy method of person bean is invoked!");
    }

}
  1. определитьMyBeanPostProcessorвыполнитьBeanPostProcessorинтерфейс.
public class MyBeanPostProcessor implements BeanPostProcessor {


    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("post Process Before Initialization is invoked");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("post Process after Initialization is invoked");
        return bean;
    }
}

  1. конфигурационный файл, указавinit-methodиdestroy-methodАтрибуты
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="myBeanPostProcessor" class="ric.study.demo.ioc.life_cycle_demo_set.MyBeanPostProcessor" />
    <bean name="personBean" class="ric.study.demo.ioc.life_cycle_demo_set.Person"
          init-method="init" destroy-method="destroyMethod">
        <property name="name" value="Richard Yi" />
    </bean>

</beans>
  1. Запустить контейнер, уничтожить контейнер
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config-1.xml");
        ((ClassPathXmlApplicationContext) context).destroy();
    }
}
  1. вывод
Constructor of person bean is invoked!
setBeanName method of person is invoked
setBeanFactory method of person is invoked
post Process Before Initialization is invoked
afterPropertiesSet method of person bean is invoked!
custom init method of person bean is invoked!
post Process after Initialization is invoked
DisposableBean Destroy method of person bean is invoked!
custom Destroy method of person bean is invoked!

Вы можете видеть, что этот результат совпадает с тем, что мы описали выше.

Анализ исходного кода

Давайте посмотрим, как описанный выше вызов реализован с точки зрения исходного кода.

На самом деле, если вы читали мою предыдущую статьюАнализ исходного кода внедрения зависимостей Spring IoCЕсли это так, вы должны знать конкретную реализацию вышеуказанного вызова.

Это эквивалентно повторному упоминанию соответствующих частей.

инициализация контейнера

На этапе внедрения зависимости Spring IoC существует три ключевых шага для создания bean-компонента.

  1. Создание экземпляра createBeanInstance()
  2. populateBean(); сборка свойств
  3. initializeBean() обрабатывает различные события обратного вызова после инициализации Bean.

в,initializeBean()Отвечает за обработку различных событий обратного вызова после инициализации Бина.

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 {
            // 涉及到的回调接口点进去一目了然,代码都是自解释的
            // BeanNameAware、BeanClassLoaderAware或BeanFactoryAware
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
            // BeanPostProcessor 的 postProcessBeforeInitialization 回调
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
            // init-methods
            // 或者是实现了InitializingBean接口,会调用afterPropertiesSet() 方法
			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()) {
            // BeanPostProcessor 的 postProcessAfterInitialization 回调
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
		return wrappedBean;
	}

вinvokeAwareMethodsсначала вызовет серию***Awareреализация интерфейса

private void invokeAwareMethods(final String beanName, final Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof BeanNameAware) {
				((BeanNameAware) bean).setBeanName(beanName);
			}
			if (bean instanceof BeanClassLoaderAware) {
				((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
			}
			if (bean instanceof BeanFactoryAware) {
				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
			}
		}
	}

затем выполнитьBeanPostProcessorизpostProcessBeforeInitializationПерезвони

	@Override
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
			result = beanProcessor.postProcessBeforeInitialization(result, beanName);
			if (result == null) {
				return result;
			}
		}
		return result;
	}

Затем вызовите метод инициализации, который включаетInitializingBeanизafterPropertiesSetметод и указанныйinit-methodметод,

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) bean).afterPropertiesSet();
			}
		}

		if (mbd != null) {
			String initMethodName = mbd.getInitMethodName();
			if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.isExternallyManagedInitMethod(initMethodName)) {
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}

наконец выполнитьBeanPostProcessorизpostProcessAfterInitializationПерезвони

	@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
			result = beanProcessor.postProcessAfterInitialization(result, beanName);
			if (result == null) {
				return result;
			}
		}
		return result;
	}

Хорошо, здесь мы представили различные реализации обратного вызова в процессе загрузки bean-компонента процесса инициализации контейнера Spring.Ниже описан этап уничтожения контейнера Spring.

контейнер закрыт

Подобно инициализации бина, когда контейнер закрывается, можно увидеть вызов метода уничтожения бина. Процесс разрушения такой. следитьclose()-> doClose() -> destroyBeans() -> destroySingletons() -> destroySingleton() -> destroyBean() -> bean.destroy(), вы увидите, что наконец вызывается метод уничтожения компонента.

protected void destroyBean(String beanName, DisposableBean bean) {
		// 忽略

		// Actually destroy the bean now...
		if (bean != null) {
			try {
				bean.destroy();
			}
			catch (Throwable ex) {
				logger.error("Destroy method on bean with name '" + beanName + "' threw an exception", ex);
			}
		}

		// 忽略
	}

Обратите внимание, что тип этого компонента на самом делеDisposableBeanAdapter,DisposableBeanAdapterОн управляет уничтожением Spring Beans, фактически здесь используется шаблон адаптера. посмотри сноваdestroy()конкретный метод.

@Override
	public void destroy() {
		if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
			for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
				processor.postProcessBeforeDestruction(this.bean, this.beanName);
			}
		}

		if (this.invokeDisposableBean) {
			if (logger.isDebugEnabled()) {
				logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'");
			}
			try {
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
						@Override
						public Object run() throws Exception {
							((DisposableBean) bean).destroy();
							return null;
						}
					}, acc);
				}
				else {
                    // 调用 DisposableBean 的 destroy()方法
					((DisposableBean) bean).destroy();
				}
			}
			catch (Throwable ex) {
				String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
				if (logger.isDebugEnabled()) {
					logger.warn(msg, ex);
				}
				else {
					logger.warn(msg + ": " + ex);
				}
			}
		}

		if (this.destroyMethod != null) {
            // 调用 设置的destroyMethod
			invokeCustomDestroyMethod(this.destroyMethod);
		}
		else if (this.destroyMethodName != null) {
			Method methodToCall = determineDestroyMethod();
			if (methodToCall != null) {
				invokeCustomDestroyMethod(methodToCall);
			}
		}
	}

Когда BeanPostProcessor регистрируется в контейнере?

Предыдущий только представил реализацию обратного вызова класса BeanPostProcessor в жизненном цикле Spring Bean, но не объяснил, когда BeanPostProcessor был зарегистрирован в контейнере. Давайте представим это ниже.

Когда контейнер Spring IoC инициализируется, контейнер будет выполнять некоторые операции инициализации, включая процесс регистрации BeanPostProcessor. Подробный процесс вы можете посмотреть в моей статьеИнициализация контейнера IoC.

Просто поместите исходный код здесь.

Местоположение источникаAbstractApplicationContext#refresh()

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
                // 在这里
				registerBeanPostProcessors(beanFactory);
			// ....忽略
		}
	}
	protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
	}

Местоположение источникаPostProcessorRegistrationDelegate#registerBeanPostProcessors()

public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// step1
		// Register BeanPostProcessorChecker that logs an info message when
		// a bean is created during BeanPostProcessor instantiation, i.e. when
		// a bean is not eligible for getting processed by all BeanPostProcessors.
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

// step2
		// Separate between BeanPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
		List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
		List<String> orderedPostProcessorNames = new ArrayList<String>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
				priorityOrderedPostProcessors.add(pp);
				if (pp instanceof MergedBeanDefinitionPostProcessor) {
					internalPostProcessors.add(pp);
				}
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}
// step3
		// First, register the BeanPostProcessors that implement PriorityOrdered.
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

		// Next, register the BeanPostProcessors that implement Ordered.
		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
		for (String ppName : orderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			orderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, orderedPostProcessors);

		// Now, register all regular BeanPostProcessors.
		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
		for (String ppName : nonOrderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			nonOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

		// Finally, re-register all internal BeanPostProcessors.
		sortPostProcessors(internalPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, internalPostProcessors);

		// Re-register post-processor for detecting inner beans as ApplicationListeners,
		// moving it to the end of the processor chain (for picking up proxies etc).
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}

Описанный выше процесс можно разделить на четыре этапа:

  1. пройти черезbeanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);Метод получает коллекцию имен в beanFactory, которые наследуют интерфейс BeanPostProcessor;
  2. Разделите бины Poster наPriorityOrdered、Ordered、nonOrderedЕсть три категории, первые две — это пост-кондиционеры, добавляющие условия сортировки; (Spring может пройтиPriorityOrderedиOrderedИнтерфейс управляет приоритетом процессора), здесь на самом деле есть еще один класс, которыйMergedBeanDefinitionPostProcessor, а не основной момент, не расширять.
  3. Третий шаг можно разделить на следующие маленькие шаги
    1. priorityOrderedPostProcessors, сначала отсортируйте, а затем зарегистрируйте
    2. orderedPostProcessors, сначала отсортируйте, а затем зарегистрируйте
    3. регистрnonOrderedPostProcessors, который является общим процессором
    4. internalPostProcessors, сначала отсортируйте, а затем зарегистрируйте
    5. ЗарегистрироватьApplicationListenerDetectorпроцессор

Когда DisposableBeanAdapter регистрируется в контейнере?

DisposableBeanAdapterи вышеBeanPostProcessorУровень абстракции другой.Это привязано к Bean, поэтому время его регистрации находится на этапе внедрения зависимостей Spring Bean.Для получения подробного исходного кода, пожалуйста, обратитесь к этой моей статье.Анализ исходного кода внедрения зависимостей Spring IoC.

Местоположение источника:AbstractAutowireCapableBeanFactory#doCreateBean()

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
			throws BeanCreationException {
		// 省略前面的超多步骤,想了解的可以去看源码或者我的那篇文章

		// Register bean as disposable.
    	// 这里就是DisposableBeanAdapter的注册步骤了
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}

Местоположение источника:AbstractBeanFactory#registerDisposableBeanIfNecessary()

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
		AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
		if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
			if (mbd.isSingleton()) {
                // 注册一个DisposableBean实现,该实现将执行给定bean的所有销毁工作。
                // 包括:DestructionAwareBeanPostProcessors,DisposableBean接口,自定义destroy方法。
				registerDisposableBean(beanName,
						new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
			}
			else {
				// A bean with a custom scope...
				Scope scope = this.scopes.get(mbd.getScope());
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
				}
				scope.registerDestructionCallback(beanName,
						new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
			}
		}
	}

Эпилог

До сих пор был объяснен весь жизненный цикл Spring Bean, от инициализации контейнера до уничтожения контейнера, а также время регистрации событий обратного вызова и т. д., я надеюсь, что это может быть вам полезно.

Эта статья опубликована в блогеOpenWriteвыпуск!