Spring Core
์ํ๋์ ์คํ๋ง ํต์ฌ ์๋ฆฌ - ๊ธฐ๋ณธํธ ๊ฐ์๋ฅผ ์์ฝํ ๋ด์ฉ์ ๋๋ค.
Spring
Required
Spring Framework
Spring Boot
Optional
Spring Data
Spring Session
Spring Security
Spring Rest Docs
Spring Batch
Spring Cloud
์ข์ ๊ฐ์ฒด์งํฅ์ 5๊ฐ์ง ์์น (SOLID)
SRP: ๋จ์ผ ์ฑ ์ ์์น(single responsibility principle)
ํ๋์ ํด๋์ค๋ ํ๋์ ์ฑ ์๋ง
๊ฐ์ ธ์ผ ํ๋ค.๊ด์ฌ์ฌ๋ฅผ ๋ถ๋ฆฌ์์ผ ๋ณ๊ฒฝ์ด ์์ ๋ ํ๊ธ ํจ๊ณผ๋ฅผ ์ค์ผ ์ ์๋ค.
ํด๋ผ์ด์ธํธ ๊ฐ์ฒด๋ ์คํํ๋ ์ฑ ์๋ง ๋ด๋น
DIP: ์์กด๊ด๊ณ ์ญ์ ์์น (Dependency inversion principle)
ํ๋ก๊ทธ๋๋จธ๋
โ์ถ์ํ์ ์์กดํด์ผ์ง, ๊ตฌ์ฒดํ์ ์์กดํ๋ฉด ์๋๋ค.โ
๊ตฌํ ํด๋์ค์ ์์กดํ์ง ๋ง๊ณ ,
์ธํฐํ์ด์ค์ ์์กด
ํ๋ผ.์ญํ (Interface)์ ์์กด
ํด์ผ๊ตฌํ์ ๋ณ๊ฒฝ์ ์ ์ฐ
ํด์ง ์ ์๋ค.์์กด์ฑ ์ฃผ์ (DI)์ DIP ์์น์ ๋ฐ๋ฆ
OCP: ๊ฐ๋ฐฉ-ํ์ ์์น (Open/closed principle)
์ํํธ์จ์ด ์์๋
ํ์ฅ์์๋ ์ด๋ ค ์์ผ๋ ๋ณ๊ฒฝ์๋ ๋ซํ ์์ด์ผ ํ๋ค
์ ํ๋ฆฌ์ผ์ด์ ์
์ฌ์ฉ ์์ญ
๊ณผ๊ตฌ์ฑ ์์ญ
์ผ๋ก ๋๋์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ์๋ก์ด ํด๋์ค์ ์๋ก์ด ๊ธฐ๋ฅ์ ๊ตฌํํ๋ฉด ์ฌ์ฉ ์ญ์์ ๋ณ๊ฒฝ์ ๋ซ์ ์ ์๋ค.
LSP: ๋ฆฌ์ค์ฝํ ์นํ ์์น (Liskov substitution principle)
ํ๋ก๊ทธ๋จ์
๊ฐ์ฒด๋ ํ๋ก๊ทธ๋จ์ ์ ํ์ฑ์ ๊นจ๋จ๋ฆฌ์ง ์์ผ๋ฉด์ ํ์ ํ์ ์ ์ธ์คํด์ค๋ก ๋ฐ๊ฟ ์ ์์ด์ผ ํ๋ค.
๋คํ์ฑ์์ ํ์ ํด๋์ค๋ ์ธํฐํ์ด์ค ๊ท์ฝ์ ๋ค ์ง์ผ์ผ ํ๋ค.
ISP: ์ธํฐํ์ด์ค ๋ถ๋ฆฌ ์์น (Interface segregation principle)
ํน์ ํด๋ผ์ด์ธํธ๋ฅผ ์ํ ์ธํฐํ์ด์ค ์ฌ๋ฌ ๊ฐ๊ฐ ๋ฒ์ฉ ์ธํฐํ์ด์ค ํ๋๋ณด๋ค ๋ซ๋ค.
์ธํฐํ์ด์ค์ ๋ถ๋ฆฌ๋ก ์ธํฐํ์ด์ค๊ฐ ๋ช ํํด์ง๊ณ , ๋์ฒด ๊ฐ๋ฅ์ฑ์ด ๋์์ง๋ค.
์คํ๋ง๊ณผ ๊ฐ์ฒด์งํฅ
IoC(Inversion of Control, ์ ์ด์ ์ญ์ )
ํ๋ก๊ทธ๋จ์ ์ ์ด ํ๋ฆ์
์ง์ ์ ์ดํ๋ ๊ฒ์ด ์๋๋ผ์ธ๋ถ์์ ๊ด๋ฆฌ
ํ๋ ๊ฒ
DI(Dependency Injection, ์์กด๊ด๊ณ ์ฃผ์ )
์์กด๊ด๊ณ๋ ์ ์ ์ธ ํด๋์ค ์์กด ๊ด๊ณ์,
์คํ ์์ ์ ๊ฒฐ์ ๋๋ ๋์ ์ธ ๊ฐ์ฒด(์ธ์คํด์ค)
์์กด ๊ด๊ณ ๋์ ๋ถ๋ฆฌํด์ ์๊ฐ์คํ๋ง์ด ๋คํ์ฑ + OCP(๊ฐ๋ฐฉ-ํ์ ์์น), DIP(์์กด๊ด๊ณ ์ญ์ ์์น) ๊ฐ๋ฅํ๋๋ก ์ง์
์ ์ ์ธ ํด๋์ค ์์กด๊ด๊ณ
ํด๋์ค๊ฐ ์ฌ์ฉํ๋ import ์ฝ๋๋ง ๋ณด๊ณ ์์กด๊ด๊ณ๋ฅผ ์ฝ๊ฒ ํ๋จ
๋์ ์ธ ๊ฐ์ฒด ์ธ์คํด์ค ์์กด ๊ด๊ณ
์ ํ๋ฆฌ์ผ์ด์ ์คํ ์์ ์ ์ค์ ์์ฑ๋ ๊ฐ์ฒด ์ธ์คํด์ค์ ์ฐธ์กฐ๊ฐ ์ฐ๊ฒฐ๋ ์์กด ๊ด๊ณ
ํด๋ผ์ด์ธํธ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ , ํด๋ผ์ด์ธํธ๊ฐ ํธ์ถํ๋ ๋์์ ํ์ ์ธ์คํด์ค ์์กด๊ด๊ณ ๋ณ๊ฒฝ ๊ฐ๋ฅ
DI Container(IoC Container)
๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ด๋ฆฌํ๋ฉด์ ์์กด๊ด๊ณ๋ฅผ ์ฐ๊ฒฐํด ์ฃผ๋ ๊ฒ์ ์๋ฏธ
์์กด๊ด๊ณ ์ฃผ์ ์ ์ด์ ์ ๋ง์ถ๋ฉด DI ์ปจํ ์ด๋๋ผ๊ณ ๋ถ๋ฆฌ๋๊ฒ ์ ํฉ
์คํ๋ง์ DI, DI Container๋ก
๋คํ์ฑ + OCP, DIP
์ ์ ์ฉ์์ผ ํด๋ผ์ด์ธํธ์ ์ฝ๋ ๋ณ๊ฒฝ ์์ด ๊ธฐ๋ฅ ํ์ฅ์ด ๊ฐ๋ฅํ๋๋ก ์ง์
๋๋ฉ์ธ ์ค๊ณ
๋๋ฉ์ธ
ํ๋ ฅ, ์ญํ , ์ฑ ์
๊ด๊ณ (๊ธฐํ์ ์์ )์ญํ ๊ณผ ๊ตฌํ์ ๋ถ๋ฆฌ
ํ์ฌ ์์ ๋กญ๊ฒ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ์กฐ๋ฆฝํ ์ ์๋๋ก ์ค๊ณ
ํด๋์ค ๋ค์ด์ด๊ทธ๋จ (๊ฐ๋ฐ์ ์์ )
๊ฐ์ฒด ๋ค์ด์ด๊ทธ๋จ (์ธ์คํด์ค๋ผ๋ฆฌ์ ์ฐธ์กฐ)
Spring Container
/**
* AnnotationConfigApplicationContext : ApplicationContext ์ธํฐํ์ด์ค์ ๊ตฌํ์ฒด
* ConfigObject : ๊ตฌ์ฑ ์ ๋ณด
*/
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(ConfigObject.class);
ApplicationContext = ์คํ๋ง ์ปจํ ์ด๋
์คํ๋ง ์ปจํ ์ด๋๋ XML ๊ธฐ๋ฐ ๋๋ ์ ๋ ธํ ์ด์ ๊ธฐ๋ฐ์ ์๋ฐ ์ค์ ํด๋์ค๋ก ๋ง๋ค ์ ์์
์คํ๋ง ์ปจํ ์ด๋ ์์ฑ ๊ณผ์
์คํ๋ง ์ปจํ ์ด๋ ์์ฑ
@Configuration
์ ์ธ ๊ฐ์ฒด๋ฅผ์ค์ ์ ๋ณด
๋ก ์ฌ์ฉ๋๋
new AnnotationConfigApplicationContext(ConfigObject.class)
์คํ๋ง ๋น ๋ฑ๋ก
Config ๊ฐ์ฒด์์
@Bean
์ ์ธ๋ ๋ฉ์๋๋ฅผ ๋ชจ๋ ํธ์ถํด์ ๋ฐํ๋ ๊ฐ์ฒด๋ฅผ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋ก
์คํ๋ง ๋น(์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋ก๋ ๊ฐ์ฒด)์ @Bean ์ ์ธ๋ ๋ฉ์๋๋ช ์ ์คํ๋ง ๋น์ ์ด๋ฆ์ผ๋ก ์ฌ์ฉํ๊ฑฐ๋
@Bean(name="beanName")
์ฒ๋ผ ์ง์ ๋ถ์ฌ๋ ๊ฐ๋ฅ๋น ์ด๋ฆ์ ํญ์ ๋ค๋ฅธ ์ด๋ฆ์ ์ฌ์ฉํ์.
๊ฐ์ ์ด๋ฆ์ ์ฌ์ฉํ๋ฉด, ๋ค๋ฅธ ๋น์ด ๋ฌด์๋๊ฑฐ๋, ๋ฎ์ด์ฐ์ด๊ฑฐ๋ ์ค์ ์ ๋ฐ๋ผ ์ค๋ฅ๊ฐ ๋ฐ์
์คํ๋ง ๋น ์์กด๊ด๊ณ ์ค์
์ค์ ์ ๋ณด๋ฅผ ์ฐธ๊ณ ํด์ ์์กด๊ด๊ณ ์ฃผ์ (DI)
Bean ์กฐํ
AnnotationConfigApplicationContext ac =
new AnnotationConfigApplicationContext(AppConfig.class);
@Test
void findAllBean() {
// ์คํ๋ง์ ๋ฑ๋ก๋ ๋ชจ๋ ๋น ์ ๋ณด ์กฐํ
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
// ๋น ์ด๋ฆ์ผ๋ก ๋น ๊ฐ์ฒด(์ธ์คํด์ค) ์กฐํ
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name=" + beanDefinitionName + " object=" +
bean);
}
}
@Test
void findApplicationBean() {
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
// ROLE_APPLICATION: ์ง์ ๋ฑ๋กํ ์ ํ๋ฆฌ์ผ์ด์
๋น
// ROLE_INFRASTRUCTURE: ์คํ๋ง์ด ๋ด๋ถ์์ ์ฌ์ฉํ๋ ๋น
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name=" + beanDefinitionName + " object=" +
bean);
}
}
}
๋น ์กฐํ ๋ฐฉ๋ฒ
๋น ์ด๋ฆ๊ณผ ํ์ ์ผ๋ก ์กฐํ:
ac.getBean(๋น์ด๋ฆ, ํ์ )
ํด๋น ํ์ ์ ๋ชจ๋ ๋น ์กฐํ:
ac.getBeansOfType()
์กฐํ ๋์ ์คํ๋ง ๋น์ด ์์ผ๋ฉด ์์ธ ๋ฐ์
NoSuchBeanDefinitionException: No bean named 'xxxxx' available
BeanFactory
์คํ๋ง ์ปจํ ์ด๋์ ์ต์์ ์ธํฐํ์ด์ค
์คํ๋ง ๋น์ ๊ด๋ฆฌํ๊ณ ์กฐํํ๋ ์ญํ ๋ด๋น(getBean() ์ ๊ณต)
BeanFactory <- ApplicationContext <- AnnotationConfig, ApplicationContext
ApplicationContext
BeanFactory ๊ธฐ๋ฅ์ ๋ชจ๋ ์์๋ฐ์์ ์ ๊ณต
๋น์ ๊ด๋ฆฌํ๊ณ ๊ฒ์ํ๋ ๊ธฐ๋ฅ๋ฟ๋ง ์๋๋ผ, ์ ๋ง์ ํธ๋ฆฌ ๋ถ๊ฐ ๊ธฐ๋ฅ ์ ๊ณต
MessageSource
๋ฉ์์ง์์ค๋ฅผ ํ์ฉํ ๊ตญ์ ํ ๊ธฐ
ํ๊ตญ์์ ๋ค์ด์ค๋ฉด ํ๊ตญ์ด, ์์ด๊ถ์์ ๋ค์ด์ค๋ฉด ์์ด ์ถ๋ ฅ
EnvironmentCapable
ํ๊ฒฝ๋ณ์
๋ก์ปฌ, ๊ฐ๋ฐ, ์ด์๋ฑ์ ๊ตฌ๋ถํด์ ์ฒ๋ฆฌ
ApplicationEventPublisher
์ ํ๋ฆฌ์ผ์ด์ ์ด๋ฒคํธ
์ด๋ฒคํธ๋ฅผ ๋ฐํํ๊ณ ๊ตฌ๋ ํ๋ ๋ชจ๋ธ์ ํธ๋ฆฌํ๊ฒ ์ง์
ResourceLoader
ํธ๋ฆฌํ ๋ฆฌ์์ค ์กฐํ
ํ์ผ, ํด๋์คํจ์ค, ์ธ๋ถ ๋ฑ์์ ๋ฆฌ์์ค๋ฅผ ํธ๋ฆฌํ๊ฒ ์กฐํ
BeanDefinition
์คํ๋ง ๋น ์ค์ ๋ฉํ ์ ๋ณด
@Bean
,<bean>
๊ฐ ํ๋์ฉ ๋ฉํ ์ ๋ณด ์์ฑ
์ถ์ํ๋ BeanDefinition ๋๋ถ์ ์คํ๋ง์ด (์๋ฐ ์ฝ๋, XML, Groovy ๋ฑ)๋ค์ํ ์ค์ ํ์์ ์ง์
์คํ๋ง ์ปจํ ์ด๋๋ ์ด ๋ฉํ์ ๋ณด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์คํ๋ง ๋น ์์ฑ

Singleton Container
Singleton Pattern
ํด๋์ค์ ์ธ์คํด์ค๊ฐ ๋ฑ ํ๊ฐ๋ง ์์ฑ๋๋ ๊ฒ์ ๋ณด์ฅํ๋ ๋์์ธ ํจํด
๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ๋ ๊ฐ ์ด์ ์์ฑํ์ง ๋ชปํ๋๋ก private ์์ฑ์ ์ฌ์ฉ
์ด๋ฏธ ๋ง๋ค์ด์ง ๊ฐ์ฒด๋ฅผ ๊ณต์ ํด์ ํจ์จ์ ์ผ๋ก ์ฌ์ฉ ๊ฐ๋ฅํ์ง๋ง ์ ๋ง์ ๋ฌธ์ ์ ๋ณด์
์ฑ๊ธํค ํจํด์ ๊ตฌํํ๊ธฐ ์ํด ์ฝ๋๊ฐ ๊ธธ์ด์ง ์ ์์.
์์กด๊ด๊ณ์ ํด๋ผ์ด์ธํธ๊ฐ ๊ตฌ์ฒด ํด๋์ค์ ์์กด(DIP๋ฅผ ์๋ฐ).
ํด๋ผ์ด์ธํธ๊ฐ ๊ตฌ์ฒด ํด๋์ค์ ์์กดํด์ OCP ์์น์ ์๋ฐํ ๊ฐ๋ฅ์ฑ์ด ๋์.
ํ ์คํธ์ ์ด๋ ค์.
๋ด๋ถ ์์ฑ์ ๋ณ๊ฒฝํ๊ฑฐ๋ ์ด๊ธฐํ ํ๊ธฐ ์ด๋ ค์.
private ์์ฑ์๋ฅผ ์ฌ์ฉํ๋ค๋ณด๋ ์์ ํด๋์ค๋ฅผ ๋ง๋ค๊ธฐ ์ด๋ ค์
๊ฒฐ๋ก ์ ์ผ๋ก ์ ์ฐ์ฑ์ด ๋จ์ด์ง๊ณ , ์ํฐํจํด์ผ๋ก ๋ถ๋ฆฌ์.
Singleton Container
์คํ๋ง ์ปจํ ์ด๋: ์ฑ๊ธํค ์ปจํ ์ด๋ ์ญํ
์ฑ๊ธํค ๋ ์ง์คํธ: ์ฑ๊ธํค ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ด๋ฆฌํ๋ ๊ธฐ๋ฅ
์ฑ๊ธํค ํจํด์ ๋ฌธ์ ์ ์ ํด๊ฒฐํ๋ฉด์, ๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ์ฑ๊ธํค์ผ๋ก ๊ด๋ฆฌ
DIP, OCP, ํ ์คํธ, private ์์ฑ์๋ก ๋ถํฐ ์์ ๋ก์
์ฑ๊ธํค ๊ฐ์ฒด(์คํ๋ง ๋น)๋ ์ํ๋ฅผ
๋ฌด์ํ(stateless)
๋ก ์ค๊ณํด์ผ ํ๋ค.ํน์ ํด๋ผ์ด์ธํธ์
์์กด์ ์ธ ํ๋
๊ฐ ์์ผ๋ฉด ์๋๋ค.ํน์ ํด๋ผ์ด์ธํธ๊ฐ
๊ฐ์ ๋ณ๊ฒฝํ ์ ์๋ ํ๋
๊ฐ ์์ผ๋ฉด ์๋๋ค.๊ฐ๊ธ์ ์ผ๋ก
์ฝ๊ธฐ๋ง ๊ฐ๋ฅ
ํด์ผ ํ๋ค.ํ๋ ๋์ ์ ์๋ฐ์์
๊ณต์ ๋์ง ์๋
์ง์ญ๋ณ์, ํ๋ผ๋ฏธํฐ, ThreadLocal ๋ฑ์ ์ฌ์ฉํด์ผ ํ๋ค.
์คํ๋ง ์ค์ ์ ๋ณด๋ ํญ์
@Configuration
์ ์ฌ์ฉํ์ฌ ์ฑ๊ธํค์ ๋ณด์ฅํ์.@Configuration ์ ์ธ ์ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์กฐ์ํ๋ CGLIB ๊ธฐ์ ์ด ์ ์ฉ๋์ด ์ฑ๊ธํค ๋ณด์ฅ
์ค์ ์ ๋ณด ํด๋์ค๋ฅผ ์์๋ฐ์ xxx@CGLIB ํด๋์ค๊ฐ ์ฑ๊ธํค์ ๋ณด์ฅ
Component Scan
์ค์ ์ ๋ณด ํด๋์ค์
@ComponentScan
์ ๋ช ์ํด ์ฃผ๋ฉด, ์๋์ผ๋ก class path๋ฅผ ํ์ํด์@Component
๊ฐ ๋ช ์๋ class๋ค์ ์ค์บํด์ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก๋น ์ด๋ฆ ๊ธฐ๋ณธ ์ ๋ต: ์๊ธ์๋ง ์๋ฌธ์๋ก ๋ณ๊ฒฝ๋ ํด๋์ค๋ช ์ ์ฌ์ฉ
๋น ์ด๋ฆ ์ง์ ์ง์ : @Component("beanName")
์์กด๊ด๊ณ ์ฃผ์ ์
@Autowired
๊ฐ ํด๊ฒฐ๊ธฐ๋ณธ ์กฐํ ์ ๋ต: ํ์ ์ด ๊ฐ์ ๋น์ ์ฐพ์์ ์ฃผ์
@ComponentScan(
/**
* basePackages
* ํ์ํ ํจํค์ง์ ์์ ์์น(ํ์ ํจํค์ง ๋ชจ๋ ํ์)
* ์ง์ ํ์ง ์์ผ๋ฉด @ComponentScan ์ ์ธ๋ ์ค์ ์ ๋ณด ํด๋์ค์ ํจํค์ง๊ฐ ์์ ์์น
* ์ค์ ์ ๋ณด ํด๋์ค์ ์์น๋ฅผ ํ๋ก์ ํธ ์ต์ ๋จ์ ๋๋ ๊ฒ์ ์ถ์ฒ
*
* ์คํ๋ง ๋ถํธ๋ ๊ธฐ๋ณธ ๋ฐฉ๋ฒ์ผ๋ก @SpringBootApplication ์ @ComponentScan ํฌํจ
*/
basePackages = {"hello.core", "hello.service"},
}
Component Scan ๊ธฐ๋ณธ ๋์
@Component
: ์ปดํฌ๋ํธ ์ค์บ ํ์ ๋์@Controller
: ์คํ๋ง MVC ์ปจํธ๋กค๋ฌ@Service
: ๋น์ฆ๋์ค ๋ก์ง ๊ณ์ธต@Repository
: ์คํ๋ง ๋ฐ์ดํฐ ์ ๊ทผ ๊ณ์ธต(๋ฐ์ดํฐ ๊ณ์ธต์ ์์ธ๋ฅผ ์คํ๋ง ์์ธ๋ก ๋ณํ)@Configuration
: ์คํ๋ง ์ค์ ์ ๋ณด(์คํ๋ง ๋น์ด ์ฑ๊ธํค์ ์ ์งํ๋๋ก ์ฒ๋ฆฌ)
Filters
includeFilters : ์ปดํฌ๋ํธ ์ค์บ ๋์ ์ถ๊ฐ ์ง์
excludeFilters : ์ปดํฌ๋ํธ ์ค์บ์์ ์ ์ธํ ๋์ ์ง์
@ComponentScan(
includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class),
excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class)
)
์์กด๊ด๊ณ ์๋ ์ฃผ์
์์ฑ์ ์ฃผ์
โญ๏ธ์์ฑ์๋ฅผ ํตํด ์์กด ๊ด๊ณ๋ฅผ ์ฃผ์ ๋ฐ๋ ๋ฐฉ๋ฒ
๋ฑ 1๋ฒ ํธ์ถ ๋ณด์ฅ. ๋ถ๋ณ-ํ์ ์์กด๊ด๊ณ
๋ถ๋ณํ๊ฒ ์ค๊ณ ๊ฐ๋ฅํ๊ณ , ์์กด๊ด๊ณ ๋๋ฝ ๋ฐฉ์ง(final)
ํญ์ ์์ฑ์ ์ฃผ์ ์ ์ ํํ์.
lombok ์ฌ์ฉ ์
@RequiredArgsConstructor
@Component public class OrderServiceImpl implements OrderService { private final MemberRepository memberRepository; private final DiscountPolicy discountPolicy; @Autowired public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) { this.memberRepository = memberRepository; this.discountPolicy = discountPolicy; } }
์์ ์ ์ฃผ์ (Setter)
์์ ์ ๋ฉ์๋๋ฅผ ํตํด์ ์์กด๊ด๊ณ๋ฅผ ์ฃผ์
์ ํ, ๋ณ๊ฒฝ ๊ฐ๋ฅ์ฑ์ด ์๋ ์์กด ๊ด๊ณ
์ ํ์ ์ผ๋ก ์ฌ์ฉํ ๊ฒฝ์ฐ(์ฃผ์ ํ ๋์์ด ์์ด๋ ๋์ํ๋๋ก ํ ๊ฒฝ์ฐ)
@Autowired(required = false)
๋จ, ์ค๊ฐ์ ์์กด๊ด๊ณ๋ฅผ ๋ณ๊ฒฝํ ์ผ์ ๊ฑฐ์ ์์
@Component public class OrderServiceImpl implements OrderService { private MemberRepository memberRepository; private DiscountPolicy discountPolicy; @Autowired public void setMemberRepository(MemberRepository memberRepository) { this.memberRepository = memberRepository; } @Autowired public void setDiscountPolicy(DiscountPolicy discountPolicy) { this.discountPolicy = discountPolicy; } }
ํ๋ ์ฃผ์
์ธ๋ถ์์ ๋ณ๊ฒฝ์ด ๋ถ๊ฐ๋ฅํ์ฌ ํ ์คํธํ๊ธฐ ํ๋ค๋ค๋ ์น๋ช ์
๊ฐ๊ธ์ ํ ์คํธ ์ฝ๋์์๋ง ์ฌ์ฉ
@Component public class OrderServiceImpl implements OrderService { @Autowired private MemberRepository memberRepository; @Autowired private DiscountPolicy discountPolicy; }
์ผ๋ฐ ๋ฉ์๋ ์ฃผ์
์ผ๋ฐ ๋ฉ์๋๋ฅผ ํตํด ์ฃผ์
ํ๋ฒ์ ์ฌ๋ฌ ํ๋๋ฅผ ์ฃผ์ ๋ฐ์ ์ ์๋ ํน์ง์ด ์์ง๋ง ์ ์ฌ์ฉํ์ง ์์
@Component public class OrderServiceImpl implements OrderService { private MemberRepository memberRepository; private DiscountPolicy discountPolicy; @Autowired public void init(MemberRepository memberRepository, DiscountPolicy discountPolicy) { this.memberRepository = memberRepository; this.discountPolicy = discountPolicy; } }
์ต์
@Autowired(required=false)
์๋ ์ฃผ์ ํ ๋์์ด ์์ผ๋ฉด ์์ ์ ๋ฉ์๋ ์์ฒด๋ฅผ ํธ์ถํ์ง ์์
@Autowired(required = false) public void setNoBean1(Member member) { System.out.println("setNoBean1 = " + member); }
org.springframework.lang.@Nullable
์๋ ์ฃผ์ ํ ๋์์ด ์์ผ๋ฉด null
@Autowired public void setNoBean2(@Nullable Member member) { System.out.println("setNoBean2 = " + member); }
Optional<>
์๋ ์ฃผ์ ํ ๋์์ด ์์ผ๋ฉด Optional.empty
@Autowired(required = false) public void setNoBean3(Optional<Member> member) { System.out.println("setNoBean3 = " + member); }
์กฐํ ๋์ ๋น์ด 2๊ฐ ์ด์์ผ ๊ฒฝ์ฐ
@Autowired
ํ์ ๋งค์นญ์ ์๋
์ฌ๋ฌ ๋น์ด ์กฐํ๋๋ฉด ํ๋ ์ด๋ฆ, ํ๋ผ๋ฏธํฐ ์ด๋ฆ์ผ๋ก ๋น ์ด๋ฆ์ ์ถ๊ฐ ๋งค์นญ
@Autowired
private DiscountPolicy rateDiscountPolicy
@Qualifier
๋น ๋ฑ๋ก ์ @Qualifier ๋ก ์ถ๊ฐ ๊ตฌ๋ถ์ ์ค์
@Qualifier ๋งค์นญ โ ๋น ์ด๋ฆ ๋งค์นญ โ NoSuchBeanDefinitionException ์์ธ
@Component
@Qualifier("mainDiscountPolicy") // ๋น ๋ฑ๋ก ์ ์ด๋ฆ ์ค์
public class RateDiscountPolicy implements DiscountPolicy {}
/** 1. ์์ฑ์ ์๋ ์ฃผ์
์ ๊ฒฝ์ฐ **/
@Autowired
public OrderServiceImpl(
MemberRepository memberRepository,
@Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
/** 2. ์์ ์ ์๋ ์ฃผ์
์ ๊ฒฝ์ฐ **/
@Autowired
public DiscountPolicy setDiscountPolicy(@Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
return discountPolicy;
}
@Primary
@Autowired ์์ ์ฌ๋ฌ ๋น์ด ๋งค์นญ๋๋ฉด @Primary๊ฐ ์ฐ์ ๊ถ
Database Connection์ ๊ฐ์ ธ์ฌ ๊ฒฝ์ฐ ๋ฑ ์๊ทผ ์ฌ์ฉ
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}
์ฐธ๊ณ . ๋น ์ ๋ ธํ ์ด์ ๋ง๋ค๊ธฐ
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,
ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier("mainDiscountPolicy")
public @interface MainDiscountPolicy {
}
//
@Component
@MainDiscountPolicy
public class RateDiscountPolicy implements DiscountPolicy {}
//
@Autowired
public OrderServiceImpl(
MemberRepository memberRepository,
@MainDiscountPolicy DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
์กฐํํ ๋น์ด ๋ชจ๋ ํ์ํ ๊ฒฝ์ฐ
๋์ ์ผ๋ก Bean์ ์ ํํด์ผํ ๋, ๋คํ์ฑ ์ฝ๋๋ฅผ ์ ์งํ๋ฉด์ Bean์ ์ฌ์ฉํ ์ ์์
public class AllBeanTest {
@Test
void findAllBean() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);
DiscountService discountService = ac.getBean(DiscountService.class);
Member member = new Member(1L, "userA", Grade.VIP);
int discountPrice = discountService.discount(member, 10000, "fixDiscountPolicy");
assertThat(discountService).isInstanceOf(DiscountService.class);
assertThat(discountPrice).isEqualTo(1000);
int rateDiscountPrice = discountService.discount(member, 20000, "rateDiscountPolicy");
assertThat(rateDiscountPrice).isEqualTo(2000);
}
static class DiscountService {
/**
* Map(Key=์คํ๋ง ๋น ์ด๋ฆ, value=DiscountPolicy ํ์
์ผ๋ก ์กฐํํ ๋ชจ๋ ์คํ๋ง ๋น)
*
* policyMap
* {key = "fixDiscountPolicy", value = {FixDiscountPolicy@5731}}
* {key = "rateDiscountPolicy", value = {RateDiscountPolicy@5732}}
*/
private final Map<String, DiscountPolicy> policyMap;
/**
* DiscountPolicy ํ์
์ผ๋ก ์กฐํํ ๋ชจ๋ ์คํ๋ง ๋น์
*
* policies
* 0 = {FixDiscountPolicy@5736} discountFixAmount = 1000
* 1 = {RateDiscountPolicy@5737} discountPercent = 10
*/
private final List<DiscountPolicy> policies;
public DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) {
this.policyMap = policyMap;
this.policies = policies;
}
// ์ํ๋ ํ ์ธ ๋ฐฉ๋ฒ์ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ ํ, Map์์ ๊บผ๋ด์ ์ฌ์ฉ
public int discount(Member member, int price, String discountCode) {
DiscountPolicy discountPolicy = policyMap.get(discountCode);
return discountPolicy.discount(member, price);
}
}
}
ํธ๋ฆฌํ ์๋ ๋น ๋ฑ๋ก ๊ธฐ๋ฅ์ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉํ์.
์๋ ๋น ๋ฑ๋ก์ ๊ธฐ์ ์ง์ ๊ฐ์ฒด, ๋คํ์ฑ์ ํ์ฉํ๋(Bean Map, List) ๋น์ฆ๋์ค ๋ก์ง์ ์ ์ฉํด๋ณด์.
์ง์ ๋ฑ๋กํ๋ ๋น์ ์ค์ ์ ๋ณด์ ๋ฐ๋ก ๋ํ๋๊ฒ ํ๋ ๊ฒ์ด ์ ์ง๋ณด์ํ๊ธฐ ์ข๋ค.
๋น ์์ฑ์ฃผ๊ธฐ ์ฝ๋ฐฑ
์คํ๋ง ๋น์ ์ด๋ฒคํธ ๋ผ์ดํ์ฌ์ดํด
์คํ๋ง ์ปจํ ์ด๋ ์์ฑ
โ์คํ๋ง ๋น ์์ฑ
โ์์กด๊ด๊ณ ์ฃผ์
โ์ด๊ธฐํ ์ฝ๋ฐฑ
โ์ฌ์ฉ
โ์๋ฉธ์ ์ฝ๋ฐฑ
โ์คํ๋ง ์ข ๋ฃ
.
๊ฐ์ฒด์ ์์ฑ๊ณผ ์ด๊ธฐํ๋ฅผ ๋ถ๋ฆฌํ์.
์์ฑ์๋
๊ฐ์ฒด ์์ฑ์ ์ฑ ์
์, ์ด๊ธฐํ๋ ์์ฑ๋ ๊ฐ๋ค์ ํ์ฉํด์ ์ปค๋ฅ์ ์ด๊ฒฐ๊ณผ ๊ฐ์๋ฌด๊ฑฐ์ด ๋์์ ์ํ
๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๋ถ๋ถ๊ณผ ์ด๊ธฐํ ํ๋ ๋ถ๋ถ์ ๋ช ํํ๊ฒ ๋๋๋ ๊ฒ์ด ์ ์ง๋ณด์ ๊ด์ ์์ ์ข์
.
์คํ๋ง์ ๋น ์๋ช ์ฃผ๊ธฐ ์ฝ๋ฐฑ ์ง์ ๋ฐฉ๋ฒ
@PostConstruct
, @PreDestory
์ง์
์คํ๋ง์์ ๊ถ์ฅํ๋ ๋ฐฉ๋ฒ
๋ฉ์๋์ ์ ๋ํ ์ด์ ๋ง ์ ์ธํ๋ฉด ๋๋ ํธ๋ฆฌํ ๋ฐฉ๋ฒ
์คํ๋ง์ ์ข ์์กฑ์ด์ง ์์ ๊ธฐ์
์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ ์ฉ ๋ถ๊ฐ(@Bean ์ค์ ์ ๋ณด ๊ธฐ๋ฅ ํ์ฉ)
์ค์ ์ ๋ณด
์ ์ด๊ธฐํ/์ข
๋ฃ ๋ฉ์๋ ์ง์
@Bean(initMethod = "init", destroyMethod = "close")
destroyMethod ๊ธฐ๋ณธ๊ฐ์ด inferred(์ถ๋ก )์ผ๋ก ๋ฑ๋ก
close, shutdown(๋๋ถ๋ถ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๊ฐ์ง๋ ์ข ๋ฃ ๋ฉ์๋ ์ด๋ฆ) ๋ฉ์๋๋ฅผ ์๋์ผ๋ก ํธ์ถ
๋ฉ์๋ ์ด๋ฆ์ ์์ ๋ก์
์คํ๋ง ๋น์ด ์คํ๋ง ์ฝ๋์ ์์กดํ์ง ์์
์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์๋ ์ ์ฉ ๊ฐ๋ฅ(์ฝ๋๊ฐ ์๋ ์ค์ ์ ๋ณด๋ฅผ ์ฌ์ฉ)
InitializingBean
, DisposableBean
์ธํฐํ์ด์ค
InitializingBean.afterPropertiesSet()
DisposableBean.destroy()
์ง๊ธ์ ๊ฑฐ์ ์ฌ์ฉํ์ง ์๋ ๋ฐฉ๋ฒ
์คํ๋ง ์ ์ฉ ์ธํฐํ์ด์ค์ ์์กด
์ด๊ธฐํ, ์๋ฉธ ๋ฉ์๋ ์ด๋ฆ ๋ณ๊ฒฝ ๋ถ๊ฐ
์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ ์ฉ ๋ถ๊ฐ
๋น ์ค์ฝํ
๋น์ด ์กด์ฌํ ์ ์๋ ๋ฒ์
์คํ๋ง์ ์ฑ๊ธํค, ํ๋กํ ํ์ , ์น ๊ด๋ จ ์ค์ฝํ(request, session, application)๋ฅผ ์ง์
๋น ์ค์ฝํ ์ง์ ๋ฐฉ๋ฒ
// ์ปดํฌ๋ํธ ์ค์บ ์๋ ๋ฑ๋ก
@Scope("prototype")
@Component
public class HelloBean {}
...
// ์๋ ๋ฑ๋ก
@Scope("prototype")
@Bean
PrototypeBean HelloBean() {
return new HelloBean();
}
.
์ฑ๊ธํค
๊ธฐ๋ณธ ์ค์ฝํ
์คํ๋ง ์ปจํ ์ด๋์ ์์~์ข ๋ฃ๊น์ง ์ ์ง๋๋ ๊ฐ์ฅ ๋์ ๋ฒ์์ ์ค์ฝํ
์คํ๋ง ์ปจํ ์ด๋๋ ํญ์ ๊ฐ์ ์ธ์คํด์ค์ ์คํ๋ง ๋น์ ๋ฐํ
.
ํ๋กํ ํ์
์คํ๋ง ์ปจํ ์ด๋๋ ํ๋กํ ํ์ ๋น์ ์์ฑ๊ณผ ์์กด๊ด๊ณ ์ฃผ์ , ์ด๊ธฐํ๊น์ง๋ง ๊ด์ฌํ๋ ๋งค์ฐ ์งง์ ๋ฒ์์ ์ค์ฝํ(์ข ๋ฃ ๋ฉ์๋ ํธ์ถ X)
์คํ๋ง ์ปจํ ์ด๋์ ์กฐํํ ๋๋ง๋ค ์๋ก์ด ์ธ์คํด์ค๋ฅผ ์์ฑํด์ ๋ฐํ
์์กด์ฑ ์ฃผ์ ์ ๋ฐ๋ ์์ ์ ๊ฐ๊ฐ ์๋ก์ด ํ๋กํ ํ์ ๋น์ด ์์ฑ
ํ๋กํ ํ์ ๋น์ ์กฐํํ ํด๋ผ์ด์ธํธ๊ฐ ๊ด๋ฆฌ. ์ข ๋ฃ ๋ฉ์๋ ํธ์ถ๋ ํด๋ผ์ด์ธํธ๊ฐ ์ํ
์ง์ ์ ์ผ๋ก ์ฌ์ฉํ๋ ์ผ์ ๋งค์ฐ ๋๋ฌพ
์ฐธ๊ณ . ์ฑ๊ธํค ๋น๊ณผ ํจ๊ป ์ฌ์ฉ์ ๋ฌธ์ ์
์คํ๋ง์ ์ผ๋ฐ์ ์ผ๋ก ์ฑ๊ธํค ๋น์ ์ฌ์ฉํ์ฌ ์ฑ๊ธํค ๋น์ด ํ๋กํ ํ์ ๋น์ ์ฌ์ฉ
์ฑ๊ธํค ๋น์ ์์ฑ ์์ ์๋ง ์์กด์ฑ ์ฃผ์ ์ ๋ฐ์ผ๋ฏ๋ก, ํ๋กํ ํ์ ๋น์ ์ฌ์ฉํ ๋๋ง๋ค ์๋ก ์์ฑํด์ ์ฌ์ฉํ๊ณ ์ํ๋ ์๋์ ๋ค๋ฅด๊ฒ ํ๋กํ ํ์ ๋น ์ค์ฝํ๊ฐ ์ฑ๊ธํค ๋น๊ณผ ํจ๊ป ๊ณ์ ์ ์ง
ObjectProvider ์ ํ์ฉํ ๋ฌธ์ ํด๊ฒฐ
์ง์ ํ ๋น์ ์ปจํ ์ด๋์์ ๋์ ์ฐพ์์ฃผ๋ DL(Dependency Lookup) ์๋น์ค ์ ๊ณต
@Autowired
private ObjectProvider<PrototypeBean> prototypeBeanProvider;
public int logic() {
PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
.
์น ์ค์ฝํ
์น ํ๊ฒฝ์์๋ง ๋์
ํ๋กํ ํ์ ๋น๊ณผ ๋ค๋ฅด๊ฒ ์คํ๋ง์ด ํด๋น ์ค์ฝํ์ ์ข ๋ฃ์์ ๊น์ง ๊ด๋ฆฌ
์ ์ง๋ณด์๋ฅผ ์ํด ํ์ํ ๊ณณ์๋ง ์ต์ํํด์ ์ฌ์ฉ ๊ถ์ฅ
request:
HTTP ์์ฒญ ํ๋๊ฐ ๋ค์ด์ค๊ณ ๋๊ฐ ๋๊น์ง ์ ์ง๋๋ ์ค์ฝํ
๊ฐ๊ฐ์ HTTP ์์ฒญ๋ง๋ค ๋ณ๋์ ๋น ์ธ์คํด์ค ์์ฑ/๊ด๋ฆฌ
/**
* @Scope
* - ์ค์ ๊ณ ๊ฐ ์์ฒญ์ด ๋ค์ด์์ผ request ์ค์ฝํ ๊ฐ์ฒด์ ๋น์ด ์์ฑ๋๋ฏ๋ก ๋น ์์ฑ ์ง์ฐ์ด ํ์.
* - ์ ์ฉ ๋์์ ๋ฐ๋ผ ScopedProxyMode.TARGET_CLASS, ScopedProxyMode.INTERFACES ์ ํ
*
* - HTTP request์ ๊ด๊ณ ์์ด ์ฑ๊ธํค์ฒ๋ผ ๋์ํ๋ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ค๋ฅธ ๋น์ ๋ฏธ๋ฆฌ ์์กด์ฑ ์ฃผ์
* - ์์ฒญ์ด ์ค๋ฉด ํ๋ก์ ๊ฐ์ฒด ๋ด๋ถ์์ ์๋ณธ ๊ฐ์ฒด์ ์์ฒญํ๋ ์์ ๋ก์ง
*/
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {...}
session:
HTTP Session๊ณผ ๋์ผํ ์๋ช ์ฃผ๊ธฐ(์์ฑ~์ข ๋ฃ)๋ฅผ ๊ฐ์ง๋ ์ค์ฝํ
application:
์๋ธ๋ฆฟ ์ปจํ ์คํธ(ServletContext)์ ๋์ผํ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ฐ์ง๋ ์ค์ฝํ
websocket:
์น ์์ผ๊ณผ ๋์ผํ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ฐ์ง๋ ์ค์ฝํ
Last updated