Application Context 와 Bean 의 초기 화 및 소각

이 절 에 서 는 Application Context 와 Bean 의 초기 화 와 소각 을 배 웁 니 다.
우선 애플 리 케 이 션 Context 용기 의 초기 화 와 소각 닫 기 과정 을 살 펴 보 자.
응용 프로그램 Context 가 시작 되 는 과정 은 Abstract 응용 프로그램 Context 에서 이 루어 집 니 다.응용 컨 텍스트 를 사용 할 때 준비 작업 이 필요 합 니 다. 이 준비 작업 은 prepareBeanFactory 방법 에서 이 루어 집 니 다.이 방법 은 용기 에 ClassLoader, Property Editor, BeanPostProcessor 등 을 설정 합 니 다.
	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		beanFactory.setBeanClassLoader(getClassLoader());
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

		// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		// Register early post-processor for detecting inner beans as ApplicationListeners.
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		// Detect a LoadTimeWeaver and prepare for weaving, if found.
		if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// Set a temporary ClassLoader for type matching.
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		// Register default environment beans.
		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
	}

용 기 를 닫 을 때 도 시스템 작업 을 완료 해 야 합 니 다. 이 작업 은 doClose () 방법 에서 이 루어 집 니 다.
이 방법 에서 먼저 용기 가 닫 힌 다 는 신 호 를 보 낸 다음 빈 을 하나씩 닫 고 마지막 으로 용기 자 체 를 닫 습 니 다.
	protected void doClose() {
		if (this.active.get() && this.closed.compareAndSet(false, true)) {
			if (logger.isInfoEnabled()) {
				logger.info("Closing " + this);
			}

			LiveBeansView.unregisterApplicationContext(this);

			try {
				// Publish shutdown event.
				publishEvent(new ContextClosedEvent(this));
			}
			catch (Throwable ex) {
				logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
			}

			// Stop all Lifecycle beans, to avoid delays during individual destruction.
			if (this.lifecycleProcessor != null) {
				try {
					this.lifecycleProcessor.onClose();
				}
				catch (Throwable ex) {
					logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
				}
			}

			// Destroy all cached singletons in the context's BeanFactory.
			destroyBeans();

			// Close the state of this context itself.
			closeBeanFactory();

			// Let subclasses do some final clean-up if they wish...
			onClose();

			this.active.set(false);
		}
	}

용기 구현 은 빈 의 라 이 프 사이클 을 IOC 관리 로 이 뤄 진다.Spring IOC 용 기 는 Bean 수명 주 기 를 관리 할 때 Bean 수명 주기 각 시간 대의 리 셋 을 제공 합 니 다.
IOC 용기 에서 Bean 의 라 이 프 사이클 을 간단히 소개 해 드 리 겠 습 니 다.
  • Bean 인 스 턴 스 생 성
  • Bean 의 인 스 턴 스 설정 속성
  • Bean 초기 화 방법 호출
  • 응용 은 IOC 용 기 를 통 해 Bean
  • 을 사용 할 수 있다.
  • 용기 가 꺼 졌 을 때 Bean 의 소각 방법
  • 을 호출 합 니 다.
    Bean 의 초기 화 방법 은 Abstract AutowireCapableBean Factory 의 initializeBean 방법 에서 이 루어 집 니 다.
    	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    		if (System.getSecurityManager() != null) {
    			AccessController.doPrivileged((PrivilegedAction) () -> {
    				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;
    	}
    	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) {
    				ClassLoader bcl = getBeanClassLoader();
    				if (bcl != null) {
    					((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
    				}
    			}
    			if (bean instanceof BeanFactoryAware) {
    				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
    			}
    		}
    	}

    Bean 의 초기 화 방법 을 호출 하기 전에 일련의 aware 인 터 페 이 스 를 호출 하여 관련 BeanName, BeanClassLoader, BeanFactory 를 Bean 에 주입 합 니 다.
    이 어 빈 의 사후 처 리 를 통 해 애플 리 케 이 션 빈 포스트 프로 세 서 스 Before Initialization 방법 을 볼 수 있 습 니 다.
    BeanPostProcessor 는 Bean 의 백 엔 드 프로세서 로 용기 가 촉발 하 는 사건 을 감청 할 수 있 는 모니터 입 니 다.이 를 IOC 용기 에 등록 하면 용기 에서 관리 하 는 빈 은 IOC 용기 이 벤트 를 리 셋 받 는 능력 을 갖 췄 다.
    이 BeanPost Processor 는 하나의 인터페이스 로 두 개의 인터페이스 방법 이 있 습 니 다. 하 나 는 post Process Before Initialization 입 니 다. Bean 의 초기 화 전에 리 셋 입 구 를 제공 합 니 다.하 나 는 post Process After Initialization 으로 Bean 의 초기 화 후 리 셋 입 구 를 제공 합 니 다. 이 두 리 셋 의 트리거 는 모두 용기 관리 Bean 의 수명 주기 와 관련 이 있 습 니 다.두 방법의 매개 변 수 는 같은 것 으로 각각 Bean 의 실례 화 대상 과 bean 의 이름 이다.
    	@Override
    	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
    			throws BeansException {
    
    		Object result = existingBean;
    		for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
    			Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
    			if (current == null) {
    				return result;
    			}
    			result = current;
    		}
    		return result;
    	}

    빈 포스트 프로세서 의 post Process Before Initialization 방법 을 순서대로 호출 합 니 다.
    이 어 invoke InitMethods 호출 을 볼 수 있 습 니 다. 이 때 는 after PropertiesSet 을 시작 하 는 과정 도 볼 수 있 습 니 다. 물론 이 는 Bean 이 InitialingBean 의 인 터 페 이 스 를 실현 해 야 합 니 다. 해당 하 는 초기 화 처 리 는 after PropertiesSet 방법 에서 이 루어 질 수 있 습 니 다.
    	protected void invokeInitMethods(String beanName, final Object bean, @Nullable 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((PrivilegedExceptionAction) () -> {
    						((InitializingBean) bean).afterPropertiesSet();
    						return null;
    					}, getAccessControlContext());
    				}
    				catch (PrivilegedActionException pae) {
    					throw pae.getException();
    				}
    			}
    			else {
    				((InitializingBean) bean).afterPropertiesSet();
    			}
    		}
    
    		if (mbd != null && bean.getClass() != NullBean.class) {
    			String initMethodName = mbd.getInitMethodName();
    			if (StringUtils.hasLength(initMethodName) &&
    					!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
    					!mbd.isExternallyManagedInitMethod(initMethodName)) {
    				invokeCustomInitMethod(beanName, bean, mbd);
    			}
    		}
    	}

    마지막 으로 빈 이 initMethod 를 설정 하 는 지 여 부 를 판단 합 니 다. 있 으 면 invoke CustomInitMethod 방법 으로 호출 하여 빈 의 초기 화 를 완료 합 니 다.
    	protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)
    			throws Throwable {
    
    		String initMethodName = mbd.getInitMethodName();
    		Assert.state(initMethodName != null, "No init method set");
    		final Method initMethod = (mbd.isNonPublicAccessAllowed() ?
    				BeanUtils.findMethod(bean.getClass(), initMethodName) :
    				ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));
    
    		if (initMethod == null) {
    			if (mbd.isEnforceInitMethod()) {
    				throw new BeanDefinitionValidationException("Couldn't find an init method named '" +
    						initMethodName + "' on bean with name '" + beanName + "'");
    			}
    			else {
    				if (logger.isDebugEnabled()) {
    					logger.debug("No default init method named '" + initMethodName +
    							"' found on bean with name '" + beanName + "'");
    				}
    				// Ignore non-existent default lifecycle methods.
    				return;
    			}
    		}
    
    		if (logger.isDebugEnabled()) {
    			logger.debug("Invoking init method  '" + initMethodName + "' on bean with name '" + beanName + "'");
    		}
    
    		if (System.getSecurityManager() != null) {
    			AccessController.doPrivileged((PrivilegedAction) () -> {
    				ReflectionUtils.makeAccessible(initMethod);
    				return null;
    			});
    			try {
    				AccessController.doPrivileged((PrivilegedExceptionAction) () ->
    					initMethod.invoke(bean), getAccessControlContext());
    			}
    			catch (PrivilegedActionException pae) {
    				InvocationTargetException ex = (InvocationTargetException) pae.getException();
    				throw ex.getTargetException();
    			}
    		}
    		else {
    			try {
    				ReflectionUtils.makeAccessible(initMethod);
    				initMethod.invoke(bean);//        
    			}
    			catch (InvocationTargetException ex) {
    				throw ex.getTargetException();
    			}
    		}
    	}
    마지막 호출 후 프로세서 applyBeanPostProcessors AfterInitialization
    	@Override
    	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
    			throws BeansException {
    
    		Object result = existingBean;
    		for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
    			Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
    			if (current == null) {
    				return result;
    			}
    			result = current;
    		}
    		return result;
    	}

    후 처리 장 치 는 빈 포스트 프로세서 의 post Process After Initialization 방법 을 순서대로 호출 합 니 다.
    다음은 Bean 의 소각 과정 을 살 펴 보 겠 습 니 다. AbstractApplication Context 류 의 doClose 방법 을 보십시오.
    	protected void doClose() {
    		if (this.active.get() && this.closed.compareAndSet(false, true)) {
    			if (logger.isInfoEnabled()) {
    				logger.info("Closing " + this);
    			}
    
    			LiveBeansView.unregisterApplicationContext(this);
    
    			try {
    				// Publish shutdown event.
    				publishEvent(new ContextClosedEvent(this));
    			}
    			catch (Throwable ex) {
    				logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
    			}
    
    			// Stop all Lifecycle beans, to avoid delays during individual destruction.
    			if (this.lifecycleProcessor != null) {
    				try {
    					this.lifecycleProcessor.onClose();
    				}
    				catch (Throwable ex) {
    					logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
    				}
    			}
    
    			// Destroy all cached singletons in the context's BeanFactory.
    			destroyBeans();
    
    			// Close the state of this context itself.
    			closeBeanFactory();
    
    			// Let subclasses do some final clean-up if they wish...
    			onClose();
    
    			this.active.set(false);
    		}
    	}
    

    destroy Beans 방법, Bean 소각 처리.결국 Disposable Bean Adapter 의 destroy 방법 으로 이 루어 졌 습 니 다.
    	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((PrivilegedExceptionAction) () -> {
    						((DisposableBean) bean).destroy();
    						return null;
    					}, acc);
    				}
    				else {
    					((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) {
    			invokeCustomDestroyMethod(this.destroyMethod);
    		}
    		else if (this.destroyMethodName != null) {
    			Method methodToCall = determineDestroyMethod(this.destroyMethodName);
    			if (methodToCall != null) {
    				invokeCustomDestroyMethod(methodToCall);
    			}
    		}
    	}

    여기 서 Bean 에 대한 소각 과정 을 볼 수 있 습 니 다. 먼저 post Process BeforeDestruction 을 호출 한 다음 에 Bean 의 destroy 방법 을 호출 합 니 다. DisposableBean 인 터 페 이 스 를 실현 하고 마지막 으로 Bean 의 사용자 정의 소각 방법 을 호출 해 야 합 니 다.

    좋은 웹페이지 즐겨찾기