๐Ÿƒ Spring Boot ์‹คํ–‰ ๊ณผ์ •์„ ํ•ด๋ถ€ํ•ด๋ณด์ž.. (1)

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

Tech

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

2025.10.02

์šฐ์„  ๊ฐ„๋‹จํ•˜๊ฒŒ Spring, IoC, DI, ๊ทธ๋ฆฌ๊ณ  Bean์— ๋Œ€ํ•ด ์งš๊ณ  ๋„˜์–ด๊ฐ€๋ณด์ž.

Spring

์Šคํ”„๋ง์€ ์ž๋ฐ” ํ”Œ๋žซํผ์„ ์œ„ํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ”„๋ ˆ์ž„์›Œํฌ์ด๋‹ค.
์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ”„๋ ˆ์ž„์›Œํฌ๋ผ ํ•จ์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๊ธฐ์ดˆ ๊ธฐ๋Šฅ๋“ค์„ ์ œ๊ณตํ•˜๋Š” ๊ณจ์กฐ ๊ฐ™์€ ์—ญํ• ์ด๋‹ค.

IoC ์ปจํ…Œ์ด๋„ˆ๋Š” ์Šคํ”„๋ง์˜ ํ•ต์‹ฌ ๋ชจ๋“ˆ ์ค‘ ํ•˜๋‚˜์ด๋‹ค. IoC ์ปจํ…Œ์ด๋„ˆ๋Š” ๋ญ˜๊นŒ. IoC ์ปจํ…Œ์ด๋„ˆ๋Š” ๊ฐ์ฒด๋“ค ๊ฐ„์˜ ์˜์กด์„ฑ๊ณผ ์ƒ๋ช…์ฃผ๊ธฐ(์ƒ์„ฑ, ์ œ๊ฑฐ)๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ๋ชจ๋“ˆ์ด๋‹ค.

IoC๋Š” ์ œ์–ด์˜ ์—ญ์ „(Inversion of Control)์ด๋ผ๋Š” ๋œป์ด๋‹ค. ๋ฌด์Šจ ์ œ์–ด๋ฅผ ์—ญ์ „ํ–ˆ๋ƒ๋ฉด, ๊ฐ์ฒด์˜ ์˜์กด์„ฑ์— ๋Œ€ํ•œ ์ œ์–ด์ด๋‹ค. ๊ฐ์ฒด์˜ ์˜์กด์„ฑ์„ ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ  ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋‹ด๋‹นํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์Šคํ”„๋ง์œผ๋กœ ๋ฐฑ์—”๋“œ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•ด๋ดค๋‹ค๋ฉด ์•Œ๊ฒ ์ง€๋งŒ ์ฝ”๋“œ๋ฅผ ์งค ๋•Œ, ์šฐ๋ฆฌ๋Š” Service์—์„œ ๋ถ€๋ฅด๋Š” Repository ์ฝ”๋“œ๋ฅผ new๋กœ ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค.

7969

์•„์ฃผ ํ”ํ•˜๊ฒŒ ๋ณผ ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ์ด๋‹ค. @RequiredArgsConstructor๋ฅผ ๋‹ฌ๊ณ , ๋ฐ‘์—๋Š” final๋กœ Service์— ๊ผญ ํ•„์š”ํ•œ ๋‹ค๋ฅธ ๊ฐ์ฒด๋“ค์„ ๋ณ€์ˆ˜๋กœ ์ง€์ •ํ•ด๋‘”๋‹ค. ๋‚˜๋Š” ์ƒ์„ฑ์ž๋ฅผ ์ž‘์„ฑํ•œ ์ ๋„, setter๋กœ ์ด ๋ณ€์ˆ˜๋“ค์„ new๋กœ ์ƒ์„ฑํ•˜์—ฌ ์ง‘์–ด๋„ฃ์–ด์ค€ ์ ๋„ ์—†๋‹ค. ๊ทธ๋Ÿฐ๋ฐ๋„ ์ฝ”๋“œ๋Š” ์ž˜ ์ž‘๋™ํ•œ๋‹ค.
๋‚ด๊ฐ€ ๋ชจ๋ฅด๋Š” ์‚ฌ์ด IoC ์ปจํ…Œ์ด๋„ˆ๊ฐ€ DI๋กœ ๋ฌผ๋ฐ‘์ž‘์—…์„ ํ•ด์ค€ ๊ฒƒ์ด๋‹ค.

DI๋Š” Dependency Injection, ์˜์กด์„ฑ ์ฃผ์ž…์ด๋‹ค. IoC์™€ ๋ญ๊ฐ€ ๋‹ค๋ฅธ ๊ฑธ๊นŒ ์‹ถ๊ฒ ์ง€๋งŒ, IoC๋Š” ์ข€ ๋” ์ถ”์ƒ์ ์ธ ๊ฐœ๋…์œผ๋กœ ์Šคํ”„๋ง์—์„œ ์ถ”๊ตฌํ•˜๋Š” ์ œ์–ด๋ฅผ ์—ญ์ „์‹œ์ผœ์•ผ ํ•œ๋‹ค๋Š” ์ฒ ํ•™์ด๋ผ๋ฉด DI๋Š” IoC๋ฅผ ์‹คํ˜„ํ•˜๋Š” ๊ตฌ์ฒด์ ์ธ ๋ฐฉ๋ฒ•์ด๋‹ค.

Bean

์œ„์—์„œ ์—ด์‹ฌํžˆ ๋งํ•œ ์ œ์–ด์˜ ์—ญ์ „, ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ์ฒด๋“ค์ด ์ „๋ถ€ Bean์ด๋‹ค. ์ฆ‰, Bean์€ ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ์ฒด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๊ฒ ๋‹ค.

๊ฐœ๋ฐœ์ž๊ฐ€ ์ปจํ…Œ์ด๋„ˆ์— ์ž‘์„ฑํ•ด์ค€ ๋นˆ ์„ค์ • ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ํ†ตํ•ด์„œ ์ƒ์„ฑ๋œ๋‹ค.

Spring Boot๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ณผ์ •์„ ํ•ด๋ถ€ํ•˜๊ธฐ ์ „ ๊ผญ ํ•„์š”ํ•œ ๊ฐœ๋…๋“ค์„ ๊ฐ„๋žตํžˆ ์ •๋ฆฌํ–ˆ๋‹ค. ์ด์ œ Spring Boot๊ฐ€ ์–ด๋–ค ๊ณผ์ •์„ ํ†ตํ•ด ์‹คํ–‰๋˜๋Š”์ง€ ํ•œ ๋ฒˆ ์•Œ์•„๋ณด์ž.


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

1. Spring Container ์ƒ์„ฑ

ApplicationContext๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

ํ˜น์€ BeanFactory๊ฐ€ ์ƒ์„ฑ๋˜์ง€๋งŒ, ๋ณดํ†ต์€ ApplicationContext๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. BeanFactory๊ฐ€ ํ•„์š”ํ•œ ๊ธฐ๋ณธ์ ์ธ ๊ธฐ๋Šฅ๋งŒ์„ ์ œ๊ณตํ•˜๋Š” IoC ์ปจํ…Œ์ด๋„ˆ๋ผ๋ฉด ApplicationContext๋Š” BeanFactory๋ฅผ ํ™•์žฅํ•˜์—ฌ ๊ตญ์ œํ™”, ์ด๋ฒคํŠธ ๋ฐœํ–‰ ๋“ฑ๋“ฑ ์ถ”๊ฐ€์ ์ธ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

@SpringBootApplication
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

์•„์ฃผ์•„์ฃผ ๋งŽ์ด ๋ณธ ์ฝ”๋“œ๋‹ค.
์Šคํ”„๋ง(๋ถ€ํŠธ) ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•  ๋•Œ ์ด run ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์‹คํ–‰๋œ๋‹ค. ์ด run ๋ฉ”์„œ๋“œ๋ฅผ ๋œฏ์–ด๋ณด์ž...

7971

์ฃผ์„์— ์•„์ฃผ ์นœ์ ˆํ•˜๊ฒŒ ์„ค๋ช…๋˜์–ด ์žˆ๋‹ค. ์‹คํ–‰ ์ค‘์ธ ApplicationContext๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š” ๋ฉ”์„œ๋“œ๋ผ๊ณ  ํ•œ๋‹ค. ์ œ์ผ ๊ด€๋ จ ์žˆ์–ด๋ณด์ด๋Š” ๊ฑด createApplicationContext()์ด๋‹ค.

createApplicationContext()

protected ConfigurableApplicationContext createApplicationContext() {
	return this.applicationContextFactory.create(this.properties.getWebApplicationType());

์•„์ง refresh ๋˜์ง€ ์•Š์€ Application Context๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๊ณ  ํ•œ๋‹ค. ๊ทธ๋Ÿผ refresh์—์„œ๋Š” ์–ด๋–ค ์ž‘์—…์„ ํ•˜๋Š” ๊ฑธ๊นŒ?

2. Bean Definition

refresh()์—์„œ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์ž‘์„ฑํ•ด์ค€ XML, ์–ด๋…ธํ…Œ์ด์…˜, config ํŒŒ์ผ ๋“ฑ์„ ์ฝ์–ด์™€์„œ Bean์„ ์ •์˜ํ•œ๋‹ค. (๊ทธ๋ฆฌ๊ณ  ๋‚˜์ค‘์— DI๋„ ํ•˜๊ณ  ์ƒ์„ฑ๋„ ํ•ด์ค€๋‹ค!) refresh ๋ฉ”์„œ๋“œ์˜ ์ฝ”๋“œ ์ „๋ฌธ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

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

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

๊ธธ๋‹ค.. ๊ทธ๋ฆฌ๊ณ  ์ฃผ์„์ด ์•„์ฃผ์•„์ฃผ ์นœ์ ˆํ•˜๊ฒŒ ๋‹ฌ๋ ค์žˆ๋‹ค. ์‹คํ–‰ํ•˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ๊ฐ์ž ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ์ •๋ฆฌํ•ด๋ณด๊ฒ ๋‹ค.

obtainFreshBeanFactory()

obtainFreshBeanFactory()์˜ ๋‚ด๋ถ€ ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	refreshBeanFactory();
	return getBeanFactory();
}

Bean factory๋ฅผ refreshํ•œ ๋‹ค์Œ ๊ฐ€์ ธ์˜ค๋Š” ๋“ฏํ•˜๋‹ค. refreshBeanFactory()์—์„œ๋Š” ๋ฌด์—‡์„ ํ• ๊นŒ?

@Override
protected final void refreshBeanFactory() throws BeansException {
	if (hasBeanFactory()) {
		destroyBeans();
		closeBeanFactory();
	}
	try {
		DefaultListableBeanFactory beanFactory = createBeanFactory();
		beanFactory.setSerializationId(getId());
		beanFactory.setApplicationStartup(getApplicationStartup());
		customizeBeanFactory(beanFactory);
		loadBeanDefinitions(beanFactory);
		this.beanFactory = beanFactory;
	}
	catch (IOException ex) {
		throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
	}
}

๋จผ์ € ๊ธฐ์กด์˜ bean factory๊ฐ€ ์กด์žฌํ•˜๋ฉด bean๋“ค์„ ์ „๋ถ€ ์ œ๊ฑฐํ•˜๊ณ  bean factory๋„ ๋‹ซ๋Š”๋‹ค.
์ดํ›„ bean factory๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ํ•ด๋‹น bean factory์— serialization id, bean definition override๋ฅผ ํ—ˆ์šฉํ•˜๋Š”์ง€, circular reference๋ฅผ ํ—ˆ์šฉํ•˜๋Š”์ง€ ์—ฌ๋ถ€ ๋“ฑ์„ ์„ค์ •ํ•œ๋‹ค.
์ดํ›„ loadBeanDefinitions()๋กœ ๋นˆ ์ •์˜๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
	// Create a new XmlBeanDefinitionReader for the given BeanFactory.
	XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

	// Configure the bean definition reader with this context's
	// resource loading environment.
	beanDefinitionReader.setEnvironment(getEnvironment());
	beanDefinitionReader.setResourceLoader(this);
	beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

	// Allow a subclass to provide custom initialization of the reader,
	// then proceed with actually loading the bean definitions.
	initBeanDefinitionReader(beanDefinitionReader);
	loadBeanDefinitions(beanDefinitionReader);
}

loadBeanDefinitions()๋ฅผ ๊ตฌํ˜„ํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ๋งŽ์•˜๋‹ค. ์œ„์ฒ˜๋Ÿผ XML์—์„œ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฉ”์„œ๋“œ, Annotation์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฉ”์„œ๋“œ, Groovy์—์„œ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฉ”์„œ๋“œ ๋“ฑ์ด ์žˆ์—ˆ๋‹ค. Spring Boot์—์„œ๋Š” Annotation์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•˜๋ฏ€๋กœ AnnotationConfigWebApplicationContext ํŒŒ์ผ์— ์ž‘์„ฑ๋œ loadBeanDefinitions()๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์„ค๋ช…ํ•˜๊ฒ ๋‹ค.

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
	AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
	ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);

	BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
	if (beanNameGenerator != null) {
		reader.setBeanNameGenerator(beanNameGenerator);
		scanner.setBeanNameGenerator(beanNameGenerator);
		beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
	}

	ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
	if (scopeMetadataResolver != null) {
		reader.setScopeMetadataResolver(scopeMetadataResolver);
		scanner.setScopeMetadataResolver(scopeMetadataResolver);
	}

	if (!this.componentClasses.isEmpty()) {
		if (logger.isDebugEnabled()) {
			logger.debug("Registering component classes: [" +
					StringUtils.collectionToCommaDelimitedString(this.componentClasses) + "]");
		}
		reader.register(ClassUtils.toClassArray(this.componentClasses));
	}

	if (!this.basePackages.isEmpty()) {
		if (logger.isDebugEnabled()) {
			logger.debug("Scanning base packages: [" +
						StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
		}
		scanner.scan(StringUtils.toStringArray(this.basePackages));
	}

	String[] configLocations = getConfigLocations();
	if (configLocations != null) {
		for (String configLocation : configLocations) {
			try {
				Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
				if (logger.isTraceEnabled()) {
					logger.trace("Registering [" + configLocation + "]");
				}
				reader.register(clazz);
			}
			catch (ClassNotFoundException ex) {
				if (logger.isTraceEnabled()) {
					logger.trace("Could not load class for config location [" + configLocation +
							"] - trying package scan. " + ex);
				}
				int count = scanner.scan(configLocation);
				if (count == 0 && logger.isDebugEnabled()) {
					logger.debug("No component classes found for specified class/package [" + configLocation + "]");
				}
			}
		}
	}
}

Annotation์ด ๋“ฑ๋ก๋œ ๋นˆ์˜ ์ •์˜๋ฅผ ์ฝ์–ด์˜ค๋Š” reader, class path์— ๋“ฑ๋ก๋œ bean definition๋ฅผ ์ฝ์–ด์˜ค๋Š” scanner๋ฅผ ์„ ์–ธํ•˜๊ณ  beanNameGenerator๋ฅผ ์„ค์ •ํ•œ๋‹ค. beanNameGenerator๋Š” bean definition์— ๋ถ€์—ฌํ•  ์ด๋ฆ„์— ๋Œ€ํ•œ ๊ทœ์น™์„ ์ •์˜ํ•œ๋‹ค. ์ดํ›„ bean definition์„ ์ฝ์–ด์˜ฌ ๋•Œ, @Scope ์–ด๋…ธํ…Œ์ด์…˜์„ ์ฝ์–ด bean์˜ scope๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” scopeMetadataResolver๋ฅผ ๋“ฑ๋กํ•œ๋‹ค.

์„ค์ • ๋„๊ตฌ(beanNameGenerator, scopeMetadataResolver)๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ๋‚˜๋ฉด ์‹ค์ œ๋กœ reader, scanner๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ bean factory์— bean definition์„ ๋“ฑ๋กํ•œ๋‹ค.

Component Class

this.componentClass์— ๋“ฑ๋ก๋˜์–ด ์žˆ๋Š” ํด๋ž˜์Šค ๋ชฉ๋ก์„ reader๋กœ bean definition์— ๋“ฑ๋กํ•œ๋‹ค.

๋ฉ”์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํด๋ž˜์Šค(@SpringBootApplication)์™€ @Configuration์ด ๋ถ™์€ ํด๋ž˜์Šค๊ฐ€ ์ด ์‹œ์ ์— ๋กœ๋”ฉ๋œ๋‹ค.

Base Package

this.basePackages๋ฅผ scanner๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์Šค์บ”ํ•˜๊ณ , ์Šค์บ” ๊ณผ์ •์—์„œ ๋ฐœ๊ฒฌ๋œ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ ํด๋ž˜์Šค๋ฅผ bean definition์— ๋“ฑ๋กํ•œ๋‹ค.

Base package ์•„๋ž˜์˜ ์„œ๋ธŒ ํŒจํ‚ค์ง€๋“ค์„ ํƒ์ƒ‰ํ•˜์—ฌ @Component, @Service ๋“ฑ๋“ฑ ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ํด๋ž˜์Šค๋ฅผ bean definition์œผ๋กœ ๋“ฑ๋กํ•œ๋‹ค. Base package๋Š” ์ž๋™์œผ๋กœ @SpringBootApplication์ด ์–ด๋…ธํ…Œ์ด์…˜์ด ์œ„์น˜ํ•œ ํŒจํ‚ค์ง€๋กœ ์„ค์ •๋œ๋‹ค.

Config Location

config location์ด class์ธ ๊ฒฝ์šฐ reader๋ฅผ ํ†ตํ•ด ๋“ฑ๋กํ•˜๊ณ  package์ธ ๊ฒฝ์šฐ scanner๋ฅผ ํ†ตํ•ด ๋“ฑ๋กํ•œ๋‹ค.

Context์— ๋“ฑ๋ก๋˜์–ด ์žˆ๋Š” bean definition์„ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋Š” ์ถ”๊ฐ€์ ์ธ ์†Œ์Šค์˜ ๊ฒฝ๋กœ, ์ด๋ฆ„์„ ๋งํ•œ๋‹ค.

์ด๋Ÿฌํ•œ ๊ณผ์ •์„ ๊ฑฐ์ณ bean definition์„ bean factory์— ๋“ฑ๋กํ•œ ๋’ค, ์ด bean factory๋ฅผ ๋“ค๊ณ  ๋Œ์•„์˜จ๋‹ค.

prepareBeanFactory()

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.ignoreDependencyInterface(ApplicationStartupAware.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 (!NativeDetector.inNativeImage() && 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());
	}
	if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
		beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
	}
}

Bean factory์— ์„ค์ •์„ ๋ถ€์—ฌํ•œ๋‹ค. classLoader bean์„ ๋“ฑ๋กํ•˜๊ธฐ๋„ ํ•˜๊ณ ... ๋„ˆ๋ฌด ๊ธธ์–ด์„œ ์ƒ๋žตํ•˜๊ฒ ๋‹ค.

postProcessBeanFactory()

Bean Post Processor๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ๋‹ค์–‘ํ•œ ์„ค์ •์„ ์ง„ํ–‰ํ•œ๋‹ค.

invokeBeanFactoryPostProcessors()

  1. ์ œ์ผ ๋จผ์ € BeanDefinitionRegistryPostProcessor๋“ค์„ ์‹คํ–‰ํ•œ๋‹ค.
    BeanDefinitionRegistryPostProcessor๋Š” ์ƒˆ๋กœ์šด ๋นˆ ์„ค๊ณ„๋„๋ฅผ ๋“ฑ๋ก, ์ˆ˜์ •ํ•˜๋Š” ์—ญํ• ์ด๋ผ ์ œ์ผ ๋จผ์ € ์‹คํ–‰๋˜์–ด์•ผ ํ•œ๋‹ค.
  2. ๋‚จ์•„์žˆ๋Š” BeanFactoryPostProcessor๋“ค์„ ์ „๋ถ€ ์‹คํ–‰ํ•œ๋‹ค.
    ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋œ BeanFactoryPostProcessor ๋นˆ๋“ค์„ ์กฐํšŒํ•ด์„œ ์ด๋ฆ„์„ ๊ฐ€์ ธ์˜ค๊ณ  ์ˆœ์„œ๋ฅผ ์ •๋ ฌํ•œ๋‹ค. ์ดํ›„ ์ •๋ ฌ๋œ ์ˆœ์„œ๋Œ€๋กœ postProcessBeanFactory()๋กœ ์†์„ฑ๊ฐ’ ์ˆ˜์ •์„ ์ง„ํ–‰ํ•œ๋‹ค. (์œ„์˜ postProcessBeanFactory๊ณผ๋Š” ๋‹ค๋ฅธ ๋ฉ”์„œ๋“œ๋‹ค.)
  3. ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์บ์‹œ๋ฅผ ์ •๋ฆฌํ•œ๋‹ค.

registerBeanPostProcessors()

Bean Post Processor๋“ค์„ ์šฐ์„  ์ˆœ์œ„์— ๋”ฐ๋ผ ๋ถ„๋ฅ˜ํ•ด bean factory์— ๋“ฑ๋กํ•œ๋‹ค.

BeanFactoryPostProcessor, BeanPostProcessor?

BeanFactoryPostProcessor์™€ BeanPostProcessor๊ฐ€ ์ด๋ฆ„์ด ์œ ์‚ฌํ•ด์„œ ํ—ท๊ฐˆ๋ฆด ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค...(์‚ฌ์‹ค ๋‚ด๊ฐ€ ๊ทธ๋žฌ๋‹ค.)

์ด๋ฆ„๊ณผ ์ฝ”๋“œ๋กœ ํŒŒ์•…ํ•ด๋ณด์ž๋ฉด...

์ „์ž๋Š” "Factory"์˜ post processor์ด๋ฉฐ, ์ด๋ฆ„๋งŒ ๋ณด๋ฉด Factory์—์„œ post process๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ๊ฑฐ๋‹ˆ bean์ด ์ƒ์„ฑ๋˜๊ธฐ ์ „์— ์‹คํ–‰๋  ๊ฒƒ ๊ฐ™๋‹ค. ๋‚ด๋ถ€์— ์กด์žฌํ•˜๋Š” ์œ ์ผํ•œ ๋ฉ”์„œ๋“œ postProcessBeanFactory()์˜ ์ฃผ์„์„ ์ฝ์–ด๋ณด๋‹ˆ Application Context์˜ internal bean factory์˜ ๊ธฐ๋ณธ์ ์ธ ์ดˆ๊ธฐํ™”๊ฐ€ ๋๋‚œ ๋’ค bean factory๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค๊ณ  ํ•œ๋‹ค. ๋‹จ, ๋นˆ ์„ค์ •์€ ๋ชจ๋‘ ๋กœ๋”ฉ๋˜์–ด ์žˆ์–ด์•ผ ํ•˜๋‚˜ ๋นˆ ์ธ์Šคํ„ด์Šคํ™”๋Š” ์•„์ง ์ง„ํ–‰๋˜๋ฉด ์•ˆ ๋˜๊ณ ... eager ์ดˆ๊ธฐํ™”๋˜๋Š” ๋นˆ๋“ค์˜ ์†์„ฑ์„ overrideํ•˜๊ฑฐ๋‚˜ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฑธ ํ—ˆ์šฉํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.

BeanPostProcessor ๋‚ด๋ถ€์—๋Š” postProcessBeforeInitialization(), postProcessAfterInitialization() ๋ฉ”์„œ๋“œ๊ฐ€ ์กด์žฌํ•œ๋‹ค. postProcessBefore~์€ ์ƒˆ๋กœ์šด ๋นˆ ์ธ์Šคํ„ด์Šค์— ์ดˆ๊ธฐํ™” ์ฝœ๋ฐฑ์ด ์ง„ํ–‰๋˜๊ธฐ ์ „์— ์ด ๋ฉ”์„œ๋“œ๋ฅผ ์ ์šฉํ•œ๋‹ค.(์ด๋ฏธ ํ”„๋กœํผํ‹ฐ ๊ฐ’์€ ์ฃผ์ž…๋จ) postProcessAfter~์€ ๋นˆ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ดˆ๊ธฐํ™” ๋œ ํ›„ ์ ์šฉ๋œ๋‹ค. ์•„๋งˆ ๋นˆ์ด ์ƒ์„ฑ๋œ ์ „/ํ›„๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

์Šคํƒ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•˜์ž๋ฉด
BeanFactoryPostProcessor๋Š”
- ๋นˆ ์ •์˜ ๋กœ๋“œ && ๋นˆ ์ƒ์„ฑ(์ธ์Šคํ„ด์Šคํ™”) ์ „์— ํ˜ธ์ถœ
- eager ์ดˆ๊ธฐํ™”๋˜๋Š” ๋นˆ์—๋„ ์†์„ฑ์„ ์žฌ์ •์˜, ์ถ”๊ฐ€ํ•˜๋Š” ์šฉ๋„
BeanPostProcessor๋Š”
- ๋นˆ์— ์ž‘๋™ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋นˆ ์ธ์Šคํ„ด์Šคํ™”๋ฅผ ํ•  ๋•Œ ์ž‘๋™

๊ทธ๋Ÿฌ๋ฉด Bean Definition โ†’ BeanFactoryPostProcessor โ†’ BeanPostProcessor.postProcessBeforeInitialization โ†’ Bean instantiate โ†’ BeanPostProcessor.postProcessAfterInitialization ๋Œ€๋žต ์ด๋Ÿฐ ์ˆœ์„œ๊ฐ€ ๋˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

BeanPostProcessor ๋‚ด๋ถ€ ๋ฉ”์„œ๋“œ๋“ค์˜ ํ–‰๋™ ๋ฐฉ์‹์ด ํ”„๋ก์‹œ์™€๋„ ์œ ์‚ฌํ•œ ๊ฒƒ ๊ฐ™์•„ ์ถ”๊ฐ€๋กœ ์ฐพ์•„๋ณด๋‹ˆ, ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋“ค์ด ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ์ฒด๊ฐ€ ๋นˆ์ผ ์ˆ˜๋„, ํ”„๋ก์‹œ๋กœ ๊ฐ์‹ผ ๋นˆ์ผ ์ˆ˜๋„ ์žˆ์–ด AOP ๊ธฐ๋Šฅ์ด ์—ฌ๊ธฐ์„œ ๊ตฌํ˜„๋œ๋‹ค๊ณ  ํ•œ๋‹ค. (์Šคํ”„๋ง ๋งํฌ ์ฐธ์กฐ)

initMessageSource()

๊ตญ์ œํ™”(i18n) ๊ธฐ๋Šฅ์„ ๋‹ด๋‹นํ•˜๋Š” ๋ฉ”์‹œ์ง€ ์†Œ์Šค ๋นˆ์„ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.

ApplicationContext๊ฐ€ BeanFactory์™€ ๋‹ค๋ฅธ ์  ์ค‘ ํ•˜๋‚˜๊ฐ€ ์ด ๊ตญ์ œํ™” ์ง€์›์ด๋‹ค!

initApplicationEventMulticaster()

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ด๋ฒคํŠธ(์ปจํ…์ŠคํŠธ ์ดˆ๊ธฐํ™”, ์‚ฌ์šฉ์ž ์ •์˜ ์ด๋ฒคํŠธ ๋“ฑ)๋ฅผ ๋ฉ€ํ‹ฐ์บ์ŠคํŠธํ•˜๋Š” ๋นˆ์„ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.

onRefresh()

๊ธฐํƒ€ ์ŠคํŽ˜์…œ ๋นˆ๋“ค์„ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.

registerListeners()

์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ํƒ€์ž…์˜ ๋นˆ๋“ค์„ ์ฐพ์•„์„œ ์ด๋ฒคํŠธ ๋ฉ€ํ‹ฐ์บ์Šคํ„ฐ์— ๋“ฑ๋กํ•œ๋‹ค.


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

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