ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring Event 동작 원리 -3
    Spring Framework 2023. 9. 13. 00:01

    [1] Spring Event 동작 원리 - 1

    [2] Spring Event 동작 원리 - 2

     

    이전 포스팅에 이어 Spring EventListener의 등록과정에 대해 알아보고자 합니다.

     

    AbstractApplicationEventMulticaster

    protected Collection<ApplicationListener<?>> getApplicationListeners(
    			ApplicationEvent event, ResolvableType eventType) {
    
    		Object source = event.getSource();
    		Class<?> sourceType = (source != null ? source.getClass() : null);
    		ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
    
    		// Potential new retriever to populate
    		CachedListenerRetriever newRetriever = null;
    
    		// Quick check for existing entry on ConcurrentHashMap
    		CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
    		if (existingRetriever == null) {
    			// Caching a new ListenerRetriever if possible
    			if (this.beanClassLoader == null ||
    					(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
    							(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
    				newRetriever = new CachedListenerRetriever();
    				existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
    				if (existingRetriever != null) {
    					newRetriever = null;  // no need to populate it in retrieveApplicationListeners
    				}
    			}
    		}
    
    		if (existingRetriever != null) {
    			Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
    			if (result != null) {
    				return result;
    			}
    			// If result is null, the existing retriever is not fully populated yet by another thread.
    			// Proceed like caching wasn't possible for this current local attempt.
    		}
    
    		return retrieveApplicationListeners(eventType, sourceType, newRetriever);
    	}

    retriverCache로부터 listener들을 가져오고 없다면 ConcurrentHashMap을 활용하여 저장합니다.

     

    이후에 existingRetriver가 null이 아닌 경우에 getApplicationListeners메서드에서 BeanFactory를 통해  bean이름과 타입으로 listener들을 추가합니다.

     

    이후 retrieveApplicationListeners 메서드가 까지 도달한다면 getApplicationListeners 메서드와 유사하게 BeanFactory를 통하여 bean이름과 타입으로 listener들을 추가합니다.

     

    그러면 listener bean들을 어떻게 등록될까요?

     

    AbstractApplicationContext

    public abstract class AbstractApplicationContext extends DefaultResourceLoader
    	@Override
    	public void refresh() throws BeansException, IllegalStateException {
        	try {
              ....
              ....
              registerListeners(); 
              ....
              .... 
            }
        }
    }

    refresh 메서드에서 registerListeners 메서드를 호출합니다.

    registerListener 메서드에서는 ApplicationContext에 등록된 Listener들을 가져오고, AbstractApplicationEventMulticaster에 주입합니다.

     

    ApplicationContext에 Listener들이 등록되는 과정은?

     

    EventListenerMethodProcessor

    public class EventListenerMethodProcessor
    		implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
    	...
    	...
    }

    SmartInitializingSingleton, BeanFactoryPostProcessor 클래스들을 상속받고 있습니다.

     

    EventListenerMethodProcessor는 EventListener 메서드들을 ApplicationListener 인스턴스로 등록합니다.

     

    invokeBeanFactoryPostProcessors

    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    
    		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
    		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
    		if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
    			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
    			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    		}
    	}

    registerListener메서드와 동일하게 refresh() 메서드 안에 있습니다. (빈을 등록하기 위해 registerListener 보다 위에서 호출됩니다)

     

    PostProcessorRegisterationDelegete 클래스의 invokeBeanFactoryPostProcessors로 타고 들어가고내부에서 한번 더 invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory) 메서드로 들어갑니다.

     

    InvokeBeanFactoryPostProcessors

    private static void invokeBeanFactoryPostProcessors(
    			Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
    
    		for (BeanFactoryPostProcessor postProcessor : postProcessors) {
    			StartupStep postProcessBeanFactory = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process")
    					.tag("postProcessor", postProcessor::toString);
    			postProcessor.postProcessBeanFactory(beanFactory);
    			postProcessBeanFactory.end();
    		}
    	}

     

    해당 메서드에서는 postProcessors를 순회하면서 postProcessBeanFactory를 호출합니다.

    여기서 postProcessors의 클래스로 보이는 BeanFactoryPostProcessor는 인터페이스입니다.

    해당 인터페이스를 구현한것이 바로 EventListenerMethodProcessor클래스입니다.

     

    EventListenerMethodProcessor - postProcessBeanFactory

    @Override
    	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    		this.beanFactory = beanFactory;
    
    		Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
    		List<EventListenerFactory> factories = new ArrayList<>(beans.values());
    		AnnotationAwareOrderComparator.sort(factories);
    		this.eventListenerFactories = factories;
    	}

     

    이렇게 빈이 등록되고나면 refresh() 메서드에서 registerListener를 수행한 후 finishBeanFactoryInitailization을 호출합니다.

    이 과정에서 SmartInitializingSingleton 타입에 대하여 afterSingletonInstantiated를 호출하는데 processBean메서드에서 @EventListener 타입의 Bean인 경우에 factory.createApplicationListener 메서드를 통해 ApplicationListener(ApplicationListenerMethodAdapter)로 만들어줍니다.

     

     

     

    DefaultEventListenerFactory - createApplicationListener를 구현한다

    @Override
    	public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
    		return new ApplicationListenerMethodAdapter(beanName, type, method);
    	}

     

     

     

     

     

    댓글

Designed by Tistory.