๐Ÿƒ Spring์ด ์‹คํ–‰๋˜๋Š” ๋ฒ•์„ ํ•ด๋ถ€ํ•ด๋ณด์ž.. (2, ์™„๋ฃŒ)

tlsยท2025๋…„ 10์›” 5์ผ

Tech

๋ชฉ๋ก ๋ณด๊ธฐ
5/7

Spring์ด ์‹คํ–‰๋˜๋Š” ๋ฒ•์„ ํ•ด๋ถ€ํ•ด๋ณด์ž.. (1)์—์„œ ์ด์–ด์ง‘๋‹ˆ๋‹ค.

Spring Boot๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ณผ์ •

์ง€๊ธˆ๊นŒ์ง€์˜ ์ง„ํ–‰ ์ƒํ™ฉ

  1. Spring Container๊ฐ€ ์ƒ์„ฑ ๋œ๋‹ค.
  2. ์ƒ์„ฑํ•œ Spring Container๋ฅผ refresh()ํ•œ๋‹ค. << ํ˜„์žฌ ์—ฌ๊ธฐ!

refresh() ๋ฉ”์„œ๋“œ์—์„œ๋Š” ๋นˆ ์ •์˜, ์˜์กด์„ฑ ์ฃผ์ž…, ๋นˆ ์ƒ์„ฑ ๋“ฑ๋“ฑ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋‹ค์–‘ํ•œ ์ž‘์—…์„ ์ง„ํ–‰ํ•œ๋‹ค. ์ €๋ฒˆ 1ํŽธ์—์„œ๋Š” Bean definition์ด ๋“ฑ๋ก๋œ Bean Factory๋ฅผ ๋“ค๊ณ  ์˜ค๋Š” ๊ฒƒ๊นŒ์ง€ ํ•จ๊ป˜ ์ง€์ผœ๋ดค๋‹ค.

public void refresh() throws BeansException, IllegalStateException {
	this.startupShutdownLock.lock();
	try {
		this.startupShutdownThread = Thread.currentThread();

		StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

		// 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);

			StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");

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

			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);
			beanPostProcess.end();

			// Initialize message source for this context.
			initMessageSource();

			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context subclasses.
			onRefresh();

			// Check for listener beans and register them.
			registerListeners();
// -------------------------------------------- 1ํŽธ์—์„œ ์—ฌ๊ธฐ๊นŒ์ง€ ์ง„ํ–‰ํ–ˆ์Œ! -------
			// Instantiate all remaining (non-lazy-init) singletons.
			finishBeanFactoryInitialization(beanFactory);

			// Last step: publish corresponding event.
			finishRefresh();
		}

		catch (RuntimeException | Error ex ) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}

			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();

			// Reset 'active' flag.
			cancelRefresh(ex);

			// Propagate exception to caller.
			throw ex;
		}

		finally {
			contextRefresh.end();
		}
	}
	finally {
		this.startupShutdownThread = null;
		this.startupShutdownLock.unlock();
	}
}

์ด์ œ ์˜์กด์„ฑ ์ฃผ์ž…๋ถ€ํ„ฐ ์‹คํ–‰๊นŒ์ง€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด์ž.

3. DI ์„ค์ • & Bean ์ƒ์„ฑ

์‹ค์ œ๋กœ ๋นˆ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ƒ์„ฑ๋œ ๊ฐ์ฒด์— ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜๋Š” ๋‹จ๊ณ„์ด๋‹ค.

finishBeanFactoryInitialization()

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// Initialize bootstrap executor for this context.
	if (beanFactory.containsBean(BOOTSTRAP_EXECUTOR_BEAN_NAME) &&
			beanFactory.isTypeMatch(BOOTSTRAP_EXECUTOR_BEAN_NAME, Executor.class)) {
		beanFactory.setBootstrapExecutor(
				beanFactory.getBean(BOOTSTRAP_EXECUTOR_BEAN_NAME, Executor.class));
	}

	// Initialize conversion service for this context.
	if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
			beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
		beanFactory.setConversionService(
				beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
	}

	// Register a default embedded value resolver if no BeanFactoryPostProcessor
	// (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
	// at this point, primarily for resolution in annotation attribute values.
	if (!beanFactory.hasEmbeddedValueResolver()) {
		beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
	}

	// Call BeanFactoryInitializer beans early to allow for initializing specific other beans early.
	String[] initializerNames = beanFactory.getBeanNamesForType(BeanFactoryInitializer.class, false, false);
	for (String initializerName : initializerNames) {
		beanFactory.getBean(initializerName, BeanFactoryInitializer.class).initialize(beanFactory);
	}

	// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
	for (String weaverAwareName : weaverAwareNames) {
		try {
			beanFactory.getBean(weaverAwareName, LoadTimeWeaverAware.class);
		}
		catch (BeanNotOfRequiredTypeException ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Failed to initialize LoadTimeWeaverAware bean '" + weaverAwareName +
						"' due to unexpected type mismatch: " + ex.getMessage());
			}
		}
	}

	// Stop using the temporary ClassLoader for type matching.
	beanFactory.setTempClassLoader(null);

	// Allow for caching all bean definition metadata, not expecting further changes.
	beanFactory.freezeConfiguration();

	// Instantiate all remaining (non-lazy-init) singletons.
	beanFactory.preInstantiateSingletons();
}
  1. Bootstrap executor๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
  2. Conversion Service(ํƒ€์ž… ๋ณ€ํ™˜ ์‹œ์Šคํ…œ)๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
  3. ๋งŒ์•ฝ EmbeddedValueResolver๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ, default embedded value resolver๋ฅผ ๋“ฑ๋กํ•œ๋‹ค.
    Value Resolver๋Š” ๋นˆ ์„ค์ • ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋‚ด์˜ ${ }๋ฅผ ์‹ค์ œ ๊ฐ’์œผ๋กœ ๋Œ€์ฒดํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.
  4. BeanFactoryInitializer.class์ธ ๋นˆ์„ ํ˜ธ์ถœํ•œ๋‹ค.
    BeanFactoryInitializer.class๋ฅผ ๊ตฌํ˜„ํ•œ ๋นˆ์€ ๋‹ค๋ฅธ ๋นˆ๋“ค๋ณด๋‹ค ๋จผ์ € ์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š” ์šฐ์„ ์ˆœ์œ„๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋จผ์ € ์‹คํ–‰ํ•œ๋‹ค.
  5. LoadTimeWeaverAware ์ดˆ๊ธฐํ™”
    ๋Ÿฐํƒ€์ž„ ์‹œ์ ์— AOP๋ฅผ ์ ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์ธ LoadTimeWeaving๊ณผ ๊ด€๋ จ๋œ ๋นˆ์ด๋‹ค. ๋‹น์—ฐํžˆ ๋จผ์ € ํ•ด์•ผ๊ฒ ์ง€?
  6. Bean ํƒ€์ž…์„ ๋ถ„์„ํ•  ๋•Œ ์‚ฌ์šฉํ–ˆ๋˜ ์ž„์‹œ classloader๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค.
  7. ๋ชจ๋“  bean definition๋“ค์„ ์บ์‹ฑํ•œ๋‹ค.
    ์ด์ œ ๋ฐ”๋€Œ์ง€ ์•Š์„ ๊ฑฐ๋ผ๋Š” ์ ๋„ ์žˆ๊ณ , ์ถ”๊ฐ€์ ์ธ ๋ณ€๊ฒฝ์„ ๋ง‰์•„ ๋นˆ ์ƒ์„ฑ ๊ณผ์ • ์†๋„๋ฅผ ๋น ๋ฅด๊ฒŒ ํ•œ๋‹ค.
  8. preInstantiateSingletons()์—์„œ ๋นˆ์„ ์ƒ์„ฑ, ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•œ๋‹ค.

preInstantiateSingletons()

public void preInstantiateSingletons() throws BeansException {
	// Iterate over a copy to allow for init methods which in turn register new bean definitions.
	// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	// Trigger initialization of all non-lazy singleton beans...
	List<CompletableFuture<?>> futures = new ArrayList<>();

	this.preInstantiationThread.set(PreInstantiation.MAIN);
	this.mainThreadPrefix = getThreadNamePrefix();
	try {
		for (String beanName : beanNames) {
			RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			if (!mbd.isAbstract() && mbd.isSingleton()) {
				CompletableFuture<?> future = preInstantiateSingleton(beanName, mbd);
				if (future != null) {
					futures.add(future);
				}
			}
		}
	}
	finally {
		this.mainThreadPrefix = null;
		this.preInstantiationThread.remove();
	}

	if (!futures.isEmpty()) {
		try {
			CompletableFuture.allOf(futures.toArray(new CompletableFuture<?>[0])).join();
		}
		catch (CompletionException ex) {
			ReflectionUtils.rethrowRuntimeException(ex.getCause());
		}
	}


	// Trigger post-initialization callback for all applicable beans...
	for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName, false);
		if (singletonInstance instanceof SmartInitializingSingleton smartSingleton) {
			StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
					.tag("beanName", beanName);
			smartSingleton.afterSingletonsInstantiated();
			smartInitialize.end();
		}
	}
}

๊ธฐ์กด์— ๋“ฑ๋ก๋œ bean definitions๋ฅผ ํ†ตํ•ด bean name๋“ค์„ ๊ฐ€์ ธ์˜จ๋‹ค.
๊ทธ๋ฆฌ๊ณ  Thread, Future์„ ๋ณด์•„ํ•˜๋‹ˆ ๋นˆ ์ƒ์„ฑ, ์˜์กด์„ฑ ์ฃผ์ž…์„ ๋น ๋ฅด๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” ๊ฒƒ ๊ฐ™๊ณ ... try ๋ธ”๋ก ๋‚ด์˜ ๋ฉ”์„œ๋“œ๋“ค์„ ํ†ตํ•ด ๋นˆ์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

CompletableFuture.allOf(futures.toArray(new CompletableFuture<?>[0])).join();์„ ํ†ตํ•ด ๋น„๋™๊ธฐ ๋นˆ ์ƒ์„ฑ ์ž‘์—…์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.

์ดํ›„ for๋ฌธ์œผ๋กœ bean name๋ณ„๋กœ afterSingletonsInstantiated()๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. ์ด๋ฆ„๋งŒ ๋ณด์•„๋„ ์•Œ ์ˆ˜ ์žˆ๊ฒ ์ง€๋งŒ, singleton ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋œ ๋’ค ํ•„์š”ํ•œ ์ดˆ๊ธฐํ™” ๋กœ์ง์„ ํ•˜๋‚˜์”ฉ ์‹คํ–‰ํ•œ๋‹ค.

๊ทธ๋Ÿผ ์ด์ œ try ๋ธ”๋ก ๋‚ด์˜ ๋ฉ”์„œ๋“œ๋“ค์„ ํ•˜๋‚˜์”ฉ ๋ณด์ž.
์šฐ์„  getMergedLocalBeanDefinition()

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
	// Quick check on the concurrent map first, with minimal locking.
	RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
	if (mbd != null && !mbd.stale) {
		return mbd;
	}
	return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}

getMergedLocalBeanDefinition()์€ ํ˜„์žฌ ๋นˆ์ด child bean์ธ ๊ฒฝ์šฐ parent bean definition๊นŒ์ง€ ์ฐพ์•„๋‚ด merged definition์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. (๋งŒ์•ฝ ๋ถ€๋ชจ๊ฐ€ ์—†๋Š” bean์ธ ๊ฒฝ์šฐ ๊ทธ๋ƒฅ ์Šค์Šค๋กœ๋ฅผ RootBeanDefinition์œผ๋กœ ๋ณ€ํ™˜ํ•ด์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.)

RootBeanDefinition์„ ํ™•์ธํ•ด๋ณด๋‹ˆ ๋Ÿฐํƒ€์ž„์— ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์—ฌ๋Ÿฌ bean definition๋ฅผ ํ†ตํ•ฉ(unified) bean definition์ด๋ผ๊ณ  ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ... child bean definition์„ ์‚ฌ์šฉํ•  ๋•Œ, parent bean definition์„ ์ผ์ผ์ด ์กฐํšŒํ•  ํ•„์š”๊ฐ€ ์—†๋„๋ก child bean definition์— parent bean definition์„ ํ•ฉ์ณ merge๋œ ์ƒํƒœ๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์ด๋ ‡๊ฒŒ ๋ฐ›์•„์˜จ merged bean definition(์ดํ•˜ mbd)๊ฐ€ abstract(์ถ”์ƒ)์ด ์•„๋‹ˆ๊ณ  singleton์ด๋ฉด preInstantiateSingleton()๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

@Nullable
private CompletableFuture<?> preInstantiateSingleton(String beanName, RootBeanDefinition mbd) {
	if (mbd.isBackgroundInit()) {
		Executor executor = getBootstrapExecutor();
		if (executor != null) {
			String[] dependsOn = mbd.getDependsOn();
			if (dependsOn != null) {
				for (String dep : dependsOn) {
					getBean(dep);
				}
			}
			CompletableFuture<?> future = CompletableFuture.runAsync(
					() -> instantiateSingletonInBackgroundThread(beanName), executor);
			addSingletonFactory(beanName, () -> {
				try {
					future.join();
				}
				catch (CompletionException ex) {
					ReflectionUtils.rethrowRuntimeException(ex.getCause());
				}
				return future;  // not to be exposed, just to lead to ClassCastException in case of mismatch
			});
			return (!mbd.isLazyInit() ? future : null);
		}
		else if (logger.isInfoEnabled()) {
			logger.info("Bean '" + beanName + "' marked for background initialization " +
					"without bootstrap executor configured - falling back to mainline initialization");
		}
	}
    
	if (!mbd.isLazyInit()) {
		try {
			instantiateSingleton(beanName);
		}
		catch (BeanCurrentlyInCreationException ex) {
			logger.info("Bean '" + beanName + "' marked for pre-instantiation (not lazy-init) " +
					"but currently initialized by other thread - skipping it in mainline thread");
		}
	}
	return null;
}
  • mbd๊ฐ€ background์—์„œ ์ดˆ๊ธฐํ™”๋˜์–ด๋„ ๊ดœ์ฐฎ๋‹ค๋ฉด(isBackgroundInit()) dependsOn์„ ํ†ตํ•ด mbd๊ฐ€ ์˜์กดํ•˜๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๋“ค์„ ํŒŒ์•…ํ•˜๊ณ , ํ•˜๋‚˜์”ฉ getํ•ด ์˜จ๋‹ค... getBean()์€ ํ•˜๋‹จ์—์„œ ์ถ”๊ฐ€ ์„œ์ˆ ํ•˜๊ฒ ๋‹ค.
    future๋ฅผ ํ†ตํ•ด ๋น„๋™๊ธฐ์ ์œผ๋กœ instantiateSingletonInBackgroundThread()๋ฅผ ์‹คํ–‰ํ•ด bean์„ ๊ฐ€์ ธ์˜จ๋‹ค. ๋งŒ์•ฝ lazyInit ์„ค์ •์ด ๋˜์–ด์žˆ๋‹ค๋ฉด future ๊ฐ’์ด ์•„๋‹Œ null์„ ๋ฐ›์•„๊ฐ„๋‹ค.
  • mbd๊ฐ€ background์—์„œ ์ดˆ๊ธฐํ™”๋˜๋ฉด ์•ˆ ๋œ๋‹ค๋ฉด,
    ๊ทธ๋ƒฅ instantiateSingleton()๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.
private void instantiateSingletonInBackgroundThread(String beanName) {
	this.preInstantiationThread.set(PreInstantiation.BACKGROUND);
	try {
		instantiateSingleton(beanName);
	}
	catch (RuntimeException | Error ex) {
		if (logger.isWarnEnabled()) {
			logger.warn("Failed to instantiate singleton bean '" + beanName + "' in background thread", ex);
		}
		throw ex;
	}
	finally {
		this.preInstantiationThread.remove();
	}
}

instantiateSingletonInBackgroundThread()์€ ์Šค๋ ˆ๋“œ์—์„œ instantiateSingleton()๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋ฉฐ,

private void instantiateSingleton(String beanName) {
	if (isFactoryBean(beanName)) {
		Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
		if (bean instanceof SmartFactoryBean<?> smartFactoryBean && smartFactoryBean.isEagerInit()) {
			getBean(beanName);
		}
	}
	else {
		getBean(beanName);
	}
}

instantiateSingleton()์€ getBean()์„ ํ†ตํ•ด bean์„ ๊ฐ€์ ธ์˜จ๋‹ค.

getBean

Bean์„ ์–ด๋–ป๊ฒŒ ๊ฐ€์ ธ์˜ค๋Š”์ง€ ์•Œ์•„๋ณผ ์ฐจ๋ก€๋‹ค.

@Override
public Object getBean(String name) throws BeansException {
	return doGetBean(name, null, null, false);
}

@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
	return doGetBean(name, requiredType, null, false);
}

@Override
public Object getBean(String name, Object... args) throws BeansException {
	return doGetBean(name, null, args, false);
}

๋‹จ์ˆœํ•˜๋‹ค. ์ผ๋‹จ doGetBean์„ ํ˜ธ์ถœํ•œ๋‹ค.

doGetBean

protected <T> T doGetBean(
	String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
		throws BeansException {

	String beanName = transformedBeanName(name);
	Object beanInstance;

	// Eagerly check singleton cache for manually registered singletons.
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
	// Check if bean definition exists in this factory.
	BeanFactory parentBeanFactory = getParentBeanFactory();
	if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
		// Not found -> check parent.
		String nameToLookup = originalBeanName(name);
		if (parentBeanFactory instanceof AbstractBeanFactory abf) {
			return abf.doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
		} else if (args != null) {
			// Delegation to parent with explicit args.
			return (T) parentBeanFactory.getBean(nameToLookup, args);
		}
		else if (requiredType != null) {
		// No args -> delegate to standard getBean method.
			return parentBeanFactory.getBean(nameToLookup, requiredType);
		}
		else {
			return (T) parentBeanFactory.getBean(nameToLookup);
		}
	}

	if (!typeCheckOnly) {
		markBeanAsCreated(beanName);
	}

	StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
			.tag("beanName", name);
	try {
		if (requiredType != null) {
			beanCreation.tag("beanType", requiredType::toString);
		}
		RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
		checkMergedBeanDefinition(mbd, beanName, args);

		// Guarantee initialization of beans that the current bean depends on.
		String[] dependsOn = mbd.getDependsOn();
		if (dependsOn != null) {
			for (String dep : dependsOn) {
				if (isDependent(beanName, dep)) {
					throw new "์ƒ๋žต";
				}
				registerDependentBean(dep, beanName);
				try {
					getBean(dep);
				} // ์ƒ๋žต
			}
			throw ex;
		}
	}

	// Create bean instance.
	if (mbd.isSingleton()) {
		sharedInstance = getSingleton(beanName, () -> {
			try {
				return createBean(beanName, mbd, args);
			}
		});
		beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
	}

	else if (mbd.isPrototype()) {
		// It's a prototype -> create a new instance.
		Object prototypeInstance = null;
		try {
			beforePrototypeCreation(beanName);
			prototypeInstance = createBean(beanName, mbd, args);
		}
		finally {
			afterPrototypeCreation(beanName);
		}
		beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
	}
	// ์ƒ๋žต
	return adaptBeanInstance(name, beanInstance, requiredType);
}

์•ˆ ๋‹จ์ˆœํ•˜๋‹ค.. ์ฝ”๋“œ๊ฐ€ ๋„ˆ๋ฌด ๊ธธ์–ด ์ผ๋ถ€ ์ฝ”๋“œ๋ฅผ ์ƒ๋žตํ–ˆ๋‹ค.

  1. transformedBeanName(name);์„ ํ†ตํ•ด bean name์„ ์ •๊ทœํ™”ํ•œ๋‹ค.
  2. getSingleton(beanName);์„ ํ†ตํ•ด ์ด๋ฏธ ์ƒ์„ฑ๋œ ๋นˆ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
  3. getParentBeanFactory();๋ฅผ ํ†ตํ•ด Parent Bean Factory๋ฅผ ์ฐพ์•„์˜จ๋‹ค.
    ๋งŒ์•ฝ parent bean factory๊ฐ€ ์กด์žฌํ•˜๋ฉด ๋นˆ ์ •์˜๋ฅผ ์ฐพ์•„์˜จ๋‹ค.
  4. dependsOn๊ณผ isDependent()๋ฅผ ํ†ตํ•ด ์ˆœํ™˜ ์ฐธ์กฐ ๋ฌธ์ œ๋ฅผ ๋จผ์ € ํ™•์ธํ•œ ๋’ค, ์ˆœํ™˜ ์ฐธ์กฐ ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค๋ฉด ์˜์กดํ•˜๊ณ  ์žˆ๋Š” ๋นˆ์„ ๋จผ์ € ๊ฐ€์ ธ์˜จ๋‹ค.
  5. ๊ฐ€์ ธ์˜จ mbd๊ฐ€ singleton์ธ ๊ฒฝ์šฐ sharedInstance์— ๋“ฑ๋ก(2๋ฒˆ์—์„œ ์ƒ์„ฑ๋œ ๋นˆ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ ๊ณณ)ํ•˜๊ณ  createBean()ํ•œ๋‹ค.
  6. ๋งŒ์•ฝ mbd๊ฐ€ prototype์ธ ๊ฒฝ์šฐ, ํ•„์š”ํ•œ ์ž‘์—…๊ณผ ํ•จ๊ป˜ createBean() ํ•œ๋‹ค.
  7. ์ƒ๋žต๋œ ์ฝ”๋“œ์ง€๋งŒ ๋งŒ์•ฝ ์Šค์ฝ”ํ”„๊ฐ€ ์ปค์Šคํ…€ ์Šค์ฝ”ํ”„์ธ ๊ฒฝ์šฐ ํ•ด๋‹น ์Šค์ฝ”ํ”„์˜ ๊ด€๋ฆฌ์ž๊ฐ€ ์ฒ˜๋ฆฌํ•œ๋‹ค.

getSingleton

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	// Quick check for existing instance without full singleton lock.
	Object singletonObject = this.singletonObjects.get(beanName);
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		singletonObject = this.earlySingletonObjects.get(beanName);
		if (singletonObject == null && allowEarlyReference) {
			if (!this.singletonLock.tryLock()) {
				// Avoid early singleton inference outside of original creation thread.
				return null;
			}
			try {
				// Consistent creation of early reference within full singleton lock.
				singletonObject = this.singletonObjects.get(beanName);
				if (singletonObject == null) {
					singletonObject = this.earlySingletonObjects.get(beanName);
					if (singletonObject == null) {
						ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
						if (singletonFactory != null) {
							singletonObject = singletonFactory.getObject();
							// Singleton could have been added or removed in the meantime.
							if (this.singletonFactories.remove(beanName) != null) {
								this.earlySingletonObjects.put(beanName, singletonObject);
							}
							else {
								singletonObject = this.singletonObjects.get(beanName);
							}
						}
					}
				}
			}
			finally {
				this.singletonLock.unlock();
			}
		}
	}
	return singletonObject;
}

lock์„ ์‚ฌ์šฉํ•˜์—ฌ ์›ํ•˜๋Š” bean์ด ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

  1. singletonObjects์—์„œ beanName์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐ€์ ธ์™€๋ณธ๋‹ค.
  2. ์—†์œผ๋ฉด earlySingletonObjects์—์„œ beanName์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐ€์ ธ์™€๋ณธ๋‹ค.
  3. ๋˜ ์—†๊ณ  allowEarlyReference์ธ ๊ฒฝ์šฐ, ๋ฝ์„ ๊ฑธ๊ณ 
    3-1. singletonObjects, earlySingletonObjects, singletonFactories์—์„œ ์ฐพ์•„๋ณธ๋‹ค.
    3-2. singletonFactories์—์„œ ๊ฐ€์ ธ์˜จ Factory๋ฅผ ํ†ตํ•ด singletonObject๋ฅผ ์ƒˆ๋กœ ๊ฐ€์ ธ์˜ค๊ณ  earlySingletonObjects์— ์ƒˆ๋กญ๊ฒŒ ์ง‘์–ด๋„ฃ๋Š”๋‹ค. ๐Ÿ”— doCreateBean()์—์„œ ์ˆœํ™˜ ์ฐธ์กฐ์„ฑ์„ ์–˜๊ธฐํ•  ๋•Œ ๋˜ ๋‚˜์˜จ๋‹ค.
  4. ๊ทธ๋ฆฌ๊ณ  ๋ฝ์„ ํ‘ผ๋‹ค.

์™œ ์ด๋ ‡๊ฒŒ ํ•˜๋‚˜ ์ƒ๊ฐํ•ด๋ดค๋”๋‹ˆ, B ๋นˆ์„ ์ฐธ์กฐํ•˜๋Š” A ๋นˆ๊ณผ A ๋นˆ์„ ์ฐธ์กฐํ•˜๋Š” B ๋นˆ์ด ์žˆ์„ ๋•Œ์˜ ์ˆœํ™˜ ์ฐธ์กฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ์ด๋‹ค. A ๋นˆ๋„ B ๋นˆ๋„ ์„œ๋กœ ์™„์ „ํžˆ ์™„๋ฃŒ๋œ ๋นˆ์„ ์ฃผ์ž… ๋ฐ›์œผ๋ ค๊ณ ๋งŒ ํ•œ๋‹ค๋ฉด ์˜์›ํžˆ ์„œ๋กœ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ๋œ๋‹ค.
๊ทธ๋ž˜์„œ ์ข€ ๋œ ์™„์„ฑ๋๋”๋ผ๋„ factory์— ์žˆ๋Š” ๋žŒ๋‹ค๋ฅผ ์‹คํ–‰ํ•ด ๋ฏธ๋ฆฌ ์ฃผ์ž… ๋ฐ›๊ณ , earlySingletonObjects์— ๋„ฃ์–ด๋†“๋Š”๋‹ค. ๋‚˜์ค‘์— ์•Œ๊ฒŒ ๋˜๊ฒ ์ง€๋งŒ(doCreateBean()), ๋ชจ๋“  ๋นˆ๋“ค์€ ์ดˆ๊ธฐํ™”๋ฅผ ์ง„ํ–‰ํ•˜๊ธฐ ์ „ํ›„๋กœ earlySingletonObjects๋ฅผ ํ•œ ๋ฒˆ ํ™•์ธํ•œ๋‹ค.

์ˆœํ™˜ ์ฐธ์กฐ ๋ฌธ์ œ ํ•ด๊ฒฐ ์•ˆ ๋˜๋˜๋ฐ? -> ๊ทธ๊ฑด ์ƒ์„ฑ์ž ์ฃผ์ž…๋งŒ์„ ์‚ฌ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ƒ์„ฑ์ž ์ฃผ์ž… + ํ•„๋“œ ์ฃผ์ž…(ํ˜น์€ ์ƒ์„ฑ์ž ์ฃผ์ž… + ์„ธํ„ฐ ์ฃผ์ž…) ์„ž์–ด์„œ ์‚ฌ์šฉํ•˜๋ฉด ์ˆœํ™˜ ์ฐธ์กฐ๋ฅผ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. (์ข‹์€ ์„ค๊ณ„๋Š” ์•„๋‹˜)

singletonObjects์—๋Š” ์ƒ์„ฑ์ด ์™„์ „ํžˆ ์™„๋ฃŒ๋œ ๋นˆ, earlySingletonObjects์€ ์ƒ์„ฑ์€ ๋์ง€๋งŒ ์ดˆ๊ธฐํ™”๋Š” ๋˜์ง€ ์•Š์€ ๋นˆ, singletonFactories์—๋Š” ๋นˆ ํŒฉํ† ๋ฆฌ๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.

createBean

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {

	RootBeanDefinition mbdToUse = mbd;
	
	// bean defintion ํ™•์ •๊ณผ ๊ด€๋ จ๋œ ์ฝ”๋“œ ์ƒ๋žต
	}
	try {
		// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
			return bean;
		}
	} // ์ƒ๋žต

	try {
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		return beanInstance;
	} // ์ƒ๋žต, ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ log ๊ด€๋ จ๋œ ๋ถ€๋ถ„์„ ์ผ๋ถ€ ์ƒ๋žตํ–ˆ๋‹ค.
}
  1. Bean definition ํ™•์ •์„ ํ™•์‹คํžˆ ํ•œ๋‹ค. (์ƒ๋žต๋จ)
  2. resolveBeforeInstantiation()๋ฅผ ํ†ตํ•ด bean์ด ๋ฐ˜ํ™˜๋˜๋ฉด ๋” ์ด์ƒ ์ถ”๊ฐ€ ์ž‘์—…์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์‹ค์ œ ๋นˆ ๋Œ€์‹  ํ”„๋ก์‹œ ๋“ฑ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ถ€๋ถ„์ด๋‹ค.
  3. doCreateBean() gogo

doCreateBean

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {

	// Instantiate the bean.
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	Object bean = instanceWrapper.getWrappedInstance();
	Class<?> beanType = instanceWrapper.getWrappedClass();
	if (beanType != NullBean.class) {
		mbd.resolvedTargetType = beanType;
	}
	// Allow post-processors to modify the merged bean definition.
	synchronized (mbd.postProcessingLock) {
		if (!mbd.postProcessed) {
			try {
				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
			}
			catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Post-processing of merged bean definition failed", ex);
			}
			mbd.markAsPostProcessed();
		}
	}

	// Eagerly cache singletons to be able to resolve circular references
	// even when triggered by lifecycle interfaces like BeanFactoryAware.
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
		isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}

	// Initialize the bean instance.
	Object exposedObject = bean;
	try {
		populateBean(beanName, mbd, instanceWrapper);
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	} // ์ƒ๋žต

	if (earlySingletonExposure) {
		Object earlySingletonReference = getSingleton(beanName, false);
		if (earlySingletonReference != null) {
			if (exposedObject == bean) {
				exposedObject = earlySingletonReference;
			}
			else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
				String[] dependentBeans = getDependentBeans(beanName);
				Set<String> actualDependentBeans = CollectionUtils.newLinkedHashSet(dependentBeans.length);
				for (String dependentBean : dependentBeans) {
					if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
						actualDependentBeans.add(dependentBean);
					}
				}
				if (!actualDependentBeans.isEmpty()) {
					throw new BeanCurrentlyInCreationException("์ƒ๋žต");
				}
			}
		}
	}

	// Register bean as disposable.
	try {
		registerDisposableBeanIfNecessary(beanName, bean, mbd);
	} // ์ƒ๋žต, ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ log ๊ด€๋ จ๋œ ๋ถ€๋ถ„์„ ์ผ๋ถ€ ์ƒ๋žตํ–ˆ๋‹ค.
	return exposedObject;
}
  1. createBeanInstance()์œผ๋กœ bean instance๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. (mbd๊ฐ€ ์‹ฑ๊ธ€ํ†ค์ธ ๊ฒฝ์šฐ, factoryBeanInstanceCache์—์„œ ํ•ด๋‹น ๋นˆ ์ธ์Šคํ„ด์Šค๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ์žฌ์‚ฌ์šฉ)
  2. postProcessingLock์„ ๊ฑธ๊ณ  applyMergedBeanDefinitionPostProcessors()๋กœ post processor๋ฅผ ์ ์šฉํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  markAsPostProcessed()๋กœ post processed ๋˜์—ˆ์Œ์„ ๋งˆํ‚นํ•œ๋‹ค.
  3. ์ˆœํ™˜ ์˜์กด์„ฑ(circular reference)์„ ๋Œ€๋น„ํ•˜์—ฌ SingletonFactory์— ๋นˆ์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ๋žŒ๋‹ค์ธ factory๋ฅผ ์ €์žฅํ•ด๋‘”๋‹ค.
  4. populateBean()๋กœ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•œ๋‹ค. ์•„๋ž˜์—์„œ ์ถ”๊ฐ€๋กœ ์„ค๋ช…ํ•œ๋‹ค.
  5. initializeBean()์œผ๋กœ ๋นˆ์˜ ์ดˆ๊ธฐํ™” ๊ด€๋ จ ๋ฉ”์„œ๋“œ๋“ค์„ ์‹คํ–‰ํ•œ๋‹ค. @PostConstruct ์–ด๋…ธํ…Œ์ด์…˜์ด ์—ฌ๊ธฐ์„œ ์‹คํ–‰๋œ๋‹ค! applyBeanPostProcessorsAfterInitialization()๋ฅผ ํ†ตํ•ด AOP Proxy๋„ ์—ฌ๊ธฐ์„œ ์ ์šฉ๋œ๋‹ค. (๊ผญ ์—ฌ๊ธฐ์„œ ๋ชจ๋“  AOP Proxy๊ฐ€ ์ ์šฉ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๊ณ , getEarlyReference()์—์„œ๋„ ์ƒ์„ฑ๋˜๋Š” ๊ฒฝ์šฐ๋„ ์กด์žฌํ•œ๋‹ค. ์ˆœํ™˜ ์˜์กด์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๊ฑด๋ฐ, ๋งŒ์•ฝ early..์—์„œ ๋จผ์ € ์ƒ์„ฑ๋๋‹ค๋ฉด ์—ฌ๊ธฐ์„  ์žฌ์‚ฌ์šฉํ•œ๋‹ค.)
  6. earlySingletonExposure์ธ ๊ฒฝ์šฐ, ์ˆœํ™˜ ์˜์กด์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด earlySingletonReference๊ณผ ํ˜„์žฌ bean์„ ๋น„๊ตํ•œ๋‹ค. earlySingletonReference๋Š” getSingleton(beanName, false);์„ ํ†ตํ•ด ๊ฐ€์ ธ์˜ค๋Š”๋ฐ, ์ด๋Ÿฌ๋ฉด singletonFactories๋Š” ์ œ์™ธํ•œ singletonObject์™€ earlySingletonObjects๋งŒ ํ™•์ธํ•˜๊ฒŒ ๋œ๋‹ค. (๋งŒ์•ฝ ๋‹ค๋ฅธ ๋นˆ์ด ์˜์กด์„ ์œ„ํ•ด factory์—์„œ ๋นˆ์„ ๋นผ๋ƒˆ์œผ๋ฉด singletonObject๋‚˜ earlySingletonObjects์— ๋“ฑ๋ก๋˜๋‹ˆ๊นŒ)
    ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ๊ฑด ํ˜„์žฌ ๋นˆ๊ณผ getSingleton()์„ ํ†ตํ•ด ๊ฐ€์ ธ์˜จ ๋นˆ์ด ๋‹ค๋ฅผ ๋•Œ์ด๋‹ค. (exposedObject != bean, !allowRawInjectionDespiteWrapping(ํ”„๋ก์‹œ ๋ง๊ณ  ์›๋ณธ ๋นˆ ์‚ฌ์šฉ ๋ถˆ๊ฐ€) ๊ฒฝ์šฐ) ํ˜„์žฌ๋Š” initializeBean()๋ฅผ ํ†ตํ•ด AOP๊ฐ€ ์ ์šฉ๋œ ์ƒํƒœ์ธ๋ฐ, ๋‹ค๋ฅธ ๋นˆ์€ ๋‹ค๋ฅธ ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฑฐ๋‹ค.
    ๋งŒ์•ฝ removeSingletonIfCreatedForTypeCheckOnly, ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ํƒ€์ž… ์ฒดํฌ๋งŒ ํ•˜๋ ค๊ณ  ๋นˆ์„ ๊ฐ€์ ธ๊ฐ”๋‹ค๋ฉด ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๋Š”๋‹ค. ํ•˜์ง€๋งŒ ์ด ๋ชจ๋“  ๊ฒƒ์ด ์ถฉ์กฑ๋˜์–ด ์ˆœํ™˜ ์˜์กด์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๋ฉด, ์˜ˆ์™ธ๋ฅผ ํ„ฐ๋œจ๋ฆฐ๋‹ค.

populateBean()

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	if (bw == null) {
		if (mbd.hasPropertyValues()) {
			throw new );
		}
		else {
			// Skip property population phase for null instance.
			return;
		}
	}

	if (bw.getWrappedClass().isRecord()) {
		if (mbd.hasPropertyValues()) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Cannot apply property values to a record");
		}
			else {
		// Skip property population phase for records since they are immutable.
			return;
		}
	}
	// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
	// state of the bean before properties are set. This can be used, for example,
	// to support styles of field injection.
	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
			if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
				return;
			}
		}
	}

	PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

	int resolvedAutowireMode = mbd.getResolvedAutowireMode();
	if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
		MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
		// Add property values based on autowire by name if applicable.
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
			autowireByName(beanName, mbd, bw, newPvs);
		}
		// Add property values based on autowire by type if applicable.
		if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			autowireByType(beanName, mbd, bw, newPvs);
		}
		pvs = newPvs;
	}
	if (hasInstantiationAwareBeanPostProcessors()) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
		for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
			PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
			if (pvsToUse == null) {
				return;
			}
			pvs = pvsToUse;
		}
	}

	boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
	if (needsDepCheck) {
		PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
		checkDependencies(beanName, mbd, filteredPds, pvs);
	}
	if (pvs != null) {
		applyPropertyValues(beanName, mbd, bw, pvs);
	}
}
  1. ์‚ฌ์ „ ๊ฒ€์ฆ ๋‹จ๊ณ„๋ฅผ ํ†ตํ•ด bean wrapper๊ฐ€ null์ธ์ง€, record ํƒ€์ž…(record ํƒ€์ž…์€ ๋ถˆ๋ณ€์ด๋ผ property ์ฃผ์ž…์ด ํ•„์š” ์—†๋‹ค)์ธ์ง€ ๋“ฑ์„ ๊ฒ€์ฆํ•œ๋‹ค.
  2. postProcessAfterInstantiation()๋กœ ์˜์กด์„ฑ ์ฃผ์ž…์„ ๊ฑด๋„ˆ๋›ฐ์–ด์•ผ ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
  3. ๋นˆ์— ์„ค์ •ํ•  property values๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
  4. AUTOWIRE_BY_NAME ํ˜น์€ AUTOWIRE_BY_TYPE ๋“ฑ ์„ค์ •๋œ ๊ฐ’์— ๋งž์ถฐ ์ด๋ฆ„์ด๋‚˜ ํƒ€์ž…์„ ๊ธฐ์ค€์œผ๋กœ ํ•„์š”ํ•œ ๋นˆ์„ ๊ฐ€์ ธ์˜ค๊ณ , property values์— ์ถ”๊ฐ€ํ•œ๋‹ค. (XML)
  5. InstantiationAwareBeanPostProcessor๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ, ์—ฌ๊ธฐ์„œ AutowiredAnnotationBeanPostProcessor๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. Autowired ๊ทธ Autowired ๋งž๋‹ค. ์—ฌ๊ธฐ์„œ @Autowired, @Value, @Inject๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค. (Annotation)
    ๋งŒ์•ฝ Annotation ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด 4๋ฒˆ์€ ์Šคํ‚ต๋˜๊ณ  5๋ฒˆ๋งŒ ์‹คํ–‰๋œ๋‹ค.
  6. DependencyCheck์œผ๋กœ ํ•„์š”ํ•œ ์˜์กด์„ฑ์ด ๋‹ค ๊ฐ–์ถ”์–ด์กŒ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
  7. ๋งˆ์ง€๋ง‰์œผ๋กœ applyPropertyValues()๋ฅผ ํ†ตํ•ด property value๋ฅผ ์ ์šฉํ•œ๋‹ค. ๊ตฌ์ฒด์ ์œผ๋กœ๋Š” ๋ฆฌํ”Œ๋ ‰์…˜์„ ํ†ตํ•ด ์ ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

4. ๋งˆ๋ฌด๋ฆฌ

finishRefresh()

protected void finishRefresh() {
	// Reset common introspection caches in Spring's core infrastructure.
	resetCommonCaches();

	// Clear context-level resource caches (such as ASM metadata from scanning).
	clearResourceCaches();

	// Initialize lifecycle processor for this context.
	initLifecycleProcessor();

	// Propagate refresh to lifecycle processor first.
	getLifecycleProcessor().onRefresh();

	// Publish the final event.
	publishEvent(new ContextRefreshedEvent(this));
}

finishRefresh()์—์„œ๋Š” ์ด์ œ ํ•„์š” ์—†๊ฒŒ ๋œ ์บ์‹œ๋“ค์„ ์ œ๊ฑฐํ•˜๊ณ , LifecycleProcessor๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.

Lifecycle processor๋Š” Lifecycle ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ๋นˆ๋“ค์„ ๊ด€๋ฆฌํ•œ๋‹ค. Lifecycle์„ ๊ตฌํ˜„ํ•œ ๋นˆ๋“ค์€ start(), stop()์„ ๊ตฌํ˜„ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ ์ด ๋ฉ”์„œ๋“œ๋“ค์„ ํ†ตํ•ด์„œ Lifecycle processor๊ฐ€ ๋นˆ์„ ์‹œ์ž‘ํ•˜๊ณ  ์ข…๋ฃŒํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋งˆ์ง€๋ง‰์œผ๋กœ publishEvent()๋ฅผ ํ†ตํ•ด ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ดˆ๊ธฐํ™”๋˜์—ˆ์Œ์„ ์™ธ๋ถ€์— ์•Œ๋ฆฌ๊ฒŒ ๋œ๋‹ค. (์•„๋งˆ ์ด๋ฒคํŠธ ๋ฉ€ํ‹ฐ์บ์Šคํ„ฐ๋กœ ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›์•„๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค.)


์•„์ฃผ ๊ธธ๊ณ  ๊ธด ์—ฌ์ •์ด์—ˆ๋‹ค.. refresh()๊ฐ€ ๋๋‚˜๋ฉด ์ปจํ…Œ์ด๋„ˆ์™€ ๋นˆ์˜ ์ค€๋น„๊ฐ€ ์™„๋ฃŒ๋œ ๊ฒƒ์ด๊ณ , ์ด์ œ ๋‹ค์‹œ ์ฒ˜์Œ์˜ run() ๋ฉ”์„œ๋“œ๋กœ ๋Œ์•„๊ฐ€์ž...

refresh๊ฐ€ ๋๋‚˜๋ฉด ๋‚จ์€ ์ž‘์—…์€ ๋ช‡ ๊ฐœ ๋˜์ง€ ์•Š๋Š”๋‹ค.

afterRefresh()

์Šคํ”„๋ง ๋ถ€ํŠธ ํ™˜๊ฒฝ์˜ ์ตœ์ข…_์ตœ์ข…_์ตœ์ข…_์ตœ์ข… ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•œ๋‹ค. ์ดˆ๊ธฐํ™” ์ž‘์—…์„ ๋งˆ๋ฌด๋ฆฌํ•˜๊ณ  ์ƒํƒœ๋ฅผ ์ •๋ฆฌ, ์›น ์„œ๋ฒ„๋ฅผ ๊ตฌ๋™ํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ํ•œ๋‹ค.

listeners.started(context, startup.timeTakenToStarted());

์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹œ์ž‘๋˜์—ˆ์Œ์„ ์ด๋ฒคํŠธ๋กœ ์•Œ๋ฆฐ๋‹ค.

callRunners(context, applicationArguments);

์ตœ์ข…์ ์œผ๋กœ CommandLineRunner๋‚˜ ApplicationRunner ๋นˆ์„ ํ˜ธ์ถœํ•ด ์‚ฌ์šฉ์ž ์ •์˜ ์ดˆ๊ธฐํ™” ๋กœ์ง์„ ์‹คํ–‰ํ•œ๋‹ค.


์š”์•ฝ

  1. Spring์€ IoC ์ปจํ…Œ์ด๋„ˆ์˜ ์—ญํ• ์„ ํ•˜๊ธฐ ์œ„ํ•ด Bean๊ณผ DI๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  2. Spring์˜ ์‹คํ–‰ ๊ณผ์ •์„ ์—„์ฒญ๋‚˜๊ฒŒ ๊ฐ„๋žตํ•˜๊ฒŒ ์š”์•ฝํ•˜์ž๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
    2-1. Application Context ์ƒ์„ฑ
    2-2. Bean Definition ์ •์˜
    2-3. DI ์‹คํ–‰ ๋ฐ Bean ์ƒ์„ฑ

ํšŒ๊ณ 

์‚ฌ์‹ค ์›๋ž˜ ์Šคํ”„๋ง ๋ถ€ํŠธ ์ž์ฒด ๋‚ด๋ถ€ ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ๋œฏ์–ด๋ณด๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ๊ณตํฌ์‹ฌ์ด ์‚ด์ง ์žˆ์—ˆ๋‹ค... ๋‚ด๊ฐ€ ์ž‘์„ฑํ•˜์ง€ ์•Š์€ ์ฝ”๋“œ๋ฅผ ์ž˜ ์ฝ์„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฑธ ์•Œ๊ณ  ์žˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์ดํ•ด๊ฐ€ ์ž˜ ์•ˆ ๋˜์ง€ ์•Š์„๊นŒ ํ•˜๋Š” ์ƒ๊ฐ์ด ์žˆ์—ˆ๋‚˜๋ณด๋‹ค.

ํ•˜์ง€๋งŒ ์ฝ์–ด๋ณด๋ฉฐ ์ฐจ๊ทผ์ฐจ๊ทผ ๋œฏ์–ด๋ณด๋‹ˆ ๊ทธ๋ฆฌ ์–ด๋ ค์šด ์ผ๋„ ์•„๋‹ˆ์—ˆ๋‹ค! ๋‹จ์ˆœํžˆ ๊ณต์‹ ๋ฌธ์„œ, ๊ธ€ ๊ฐ™์€ ๊ฑธ ์ฝ๋‹ค ๋ณด๋ฉด ๊ทธ๋ž˜์„œ ๋Œ€์ฒด ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•œ ๊ฑฐ์ง€? ๋ผ๋Š” ์˜๋ฌธ์ด ๊ฐ€๋” ๋“ค ๋•Œ๊ฐ€ ์žˆ์—ˆ๋Š”๋ฐ, ์ด์   ๊ณง๋ฐ”๋กœ ์ง์ ‘ ์ฝ”๋“œ๋ฅผ ๋œฏ์–ด๋ด์•ผ๊ฒ ๋‹ค ใ…Žใ…Ž

๊ทธ๋ฆฌ๊ณ  ์ฃผ์„, ๋ฉ”์„œ๋“œ๋ช…, ๋ณ€์ˆ˜๋ช…์ด ์–ผ๋งˆ๋‚˜ ์ค‘์š”ํ•œ์ง€ ๋ฐฐ์šด ๊ฒƒ ๊ฐ™๋‹ค. ๊ตฌ์ฒด์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ๊ถ๊ธˆํ•ด์„œ ๋“ค์–ด๊ฐ€ ๋ณธ ๊ฒƒ์„ ์ œ์™ธํ•˜๋ฉด, ์—ฅ๊ฐ„ํ•˜๋ฉด ์—„์ฒญ๋‚˜๊ฒŒ ์นœ์ ˆํ•œ ์ฃผ์„๊ณผ ๋ฉ”์„œ๋“œ๋ช…, ๋ณ€์ˆ˜๋ช…์„ ํ†ตํ•ด ๋Œ€๋žต ์–ด๋–ค ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ๊ฑด์ง€ ์‰ฝ๊ฒŒ ์ง์ž‘ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ ํ•  ๋•Œ ์ฃผ์„, ๋ฉ”์„œ๋“œ๋ช…, ๋ณ€์ˆ˜๋ช…์„ ๋” ์‹ ์ค‘ํžˆ ์ž‘์„ฑํ•ด์•ผ๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค!

ํ‹€๋ฆฐ ์  ์ง€์ /์งˆ๋ฌธ ๋Œ“๊ธ€ ์–ธ์ œ๋“  ํ™˜์˜์ž…๋‹ˆ๋‹ค_ใธ(โ–ญ-โ–ญ)โœจ ๋.

0๊ฐœ์˜ ๋Œ“๊ธ€