SlideShare a Scribd company logo
1 of 79
Download to read offline
Spring Framework
Inversion of Control Container
2015년 11월 17일
윤경구
1
차례
• Framework과 Spring
• 사전 지식
• IoC 기본 개념
• Spring IoC 핵심 기능
• JSR 330 javax.inject 표준
• IoC 컨테이너 관련 이슈 및 Spring 비판
2
Framework과 Spring
3
Framework이란?
• 프레임웍은 사용자가 작성한 코드와 합쳐져서 선택적으로 변경 가능한, 고유한
기능을 제공하는 소프트웨어
• 프레임웍의 특징
• 제어의 역전 (Inversion of Control) : 프로그램 제어 흐름을 호출자가 결정하
는 것이 아니라 프레임웍이 결정한다
• 기본 동작 : 확장 없이도 동작하는 기본 동작들이 제공되어야 한다.
• 사용자 코드를 통한 기능 확장 : 특정 기능만 선택적으로 확장할 수 있다.
• 프레임웍 코드는 변경되지 않는다 : 사용자 기능을 확장할 수 있지만, 프레임
웍 코드 자체는 변경될 필요가 없어야 한다.
4
좋은 Framework에 대한 생각
• 역할의 분리 : 시스템과 비즈니스 로직의 분리 (개발자, 아키텍트, 시스템 담당)
• 아키텍처 효율성
• 결과물이 시스템에 부담을 적게 줘야
• 결과물의 수준이 개발자에 의존하지 않고 큰 차이가 없어야
• 생산성
• 간결하고 빠른 개발 / 적은 인적 비용 / 재사용성
• short learning curve : 특히 비즈니스 로직 구현이 직관적이고, 기술적으로 진입 장벽
이 낮아야 함
• Tooling이 용이
• 기술 확산이 쉬워야 (Viral) : 표준의 힘, 새로운 기술에 개발자들이 유인될 수 있음
5
Spring의 EJB 모델 비판
• 복잡한 시스템을 비즈니스 개발자에게 노출
• EJB는 컨테이너 환경에 대한 의존이 심해 테스트하기 어렵다.
• 클래스로더 구조가 복잡하여 WAS 구조를 모르면 이해하기 어렵다.
• 설정(deployment descriptor)이 너무 복잡하여 이해하기 어렵다.
• Business 객체를 EJB remote interface(티어 구조)로 설계하면 불필요하게 복잡해질뿐만 아
니라 객체 지향 원칙을 해친다.
• EJB는 간단한 것을 힘들게 구현한다. (Over-Engineering)
• EJB는 환경과 요건에 따른 implementation 방식 중 하나여야 하는 것을 일반적인
Business 객체 모두에 강요한다. (특정한 경우에만 적합하다)
• EJB는 분산 환경에서 복잡한 트랜잭션 관리가 필요한 경우 (declarative transaction
management 장점) 외에는 써야 할 이유가 딱히 없다.
6
Spring History
• 1.0 릴리스 (2004년 3월) : EJB를 비판하며 Apache 라이센스로 출시
• IoC container (핵심 코어 기능 모두 구현)
• Web MVC, Hibernate 연동, 트랜잭션 관리 등
• 2.0 릴리스 (2006년)
• AOP 기능 추가
• 2.5 ~ 3.0 릴리스 (2007년 ~ 2009년)
• XML 외에 Java 5의 annotation을 활용한 JavaConfig 설정 기능 (Guice 비판 대응)
• 4.0 릴리스 (2013년) : Java 6 이후 버전만 지원
• Java 8, Groovy, Java EE 7, WebSocket
7
Spring Framework
• Spring Core Container : IoC
• AOP
• Data Access
• Transaction Management
• Web MVC
• Remote Access
• Testing
• Convention over Configuration
RAD : Spring Boot & Spring Roo
• Spring Batch
• Spring Integration : EAI
8
Prerequisites 사전 지식
9
• Class, Constructor, Field, Method, Package에 붙을 수 있음
• @interface를 통해 일종의 클래스로 선언함 (컴파일하면 실제로 interface가 됨)
• Target : annotation이 붙을 수 있는 위치를 지정
• Retention : annotation의 유효 범위 (SOURCE, CLASS, RUNTIME)
Java annotation
10
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TxMarker {
TxValue value();
}
• Class, Constructor, Field, Method, Package에 붙을 수 있음
• @interface를 통해 일종의 클래스로 선언함 (컴파일하면 실제로 interface가 됨)
• Target : annotation이 붙을 수 있는 위치를 지정
• Retention : annotation의 유효 범위 (SOURCE, CLASS, RUNTIME)
public interface TxService {
@TxMarker(TxValue.REQUIRED)
void service();
}
Java annotation
11
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TxMarker {
TxValue value();
}
meta-annotation
• meta-annotation : simply an annotation that can be applied to another
annotation (an annotation that is declared on another annotation)
• 아래 예제 annotation에서 정의된 @Service는 @Component로도 취급됨
• 여기에서 @Component가 meta-annotation
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // Spring은 이 선언에 따라 @Service를 @Component처럼 취급
public @interface Service {
// ....
}
12
composed annotation
• composed annotation : 여러 개의 meta-annotation을 하나의 커스텀
annotation으로 결합해주는 annotation
• 아래 예에서 @TransactionalService는 meta-annoation인 @Transactional과
@Service를 결합한 composed annotation
@Transactional
@Service
@Target(TYPE)
@Retention(RUNTIME)
@Documented
public @interface TransactionalService {
// ....
}
13
BCI : Byte Code Instrumentation
• source 코드가 아닌 컴파일된 bytecode를 직접 수정하여 bytecode를 변경하는
방식
• 두 가지 시점에서 변경이 가능
• ClassLoader의 loadClass에서 defineClass를 호출하기 전에
• JVM agent로 등록하여 클래스가 로드될 때 JVM이 실행시켜주는 callback 메
소드 안에서
14
Dynamic Proxy
15
public interface TxService {
void service();
}
Class class = Proxy.getProxyClass(classloader,
TxService.class);
Dynamic Proxy
16
public interface TxService {
void service();
}
Class class = Proxy.getProxyClass(classloader,
TxService.class);
// 만들어지는 Proxy bytecode를 Java code로 표현한다면 …
public class $Proxy0 implements TxService {
private InvocationHandler h;
private static Method m3; // static initializer에서
reflection으로 초기화
public $Proxy0(InvocationHandler h) {
this.h = h;
}
public void service() {
// interface에 선언된 모든 메소드들을 다음 내용으로 채워 구현
h.invoke(this, m3, null);
}
...
}
CGLIB (1/2)
• cglib : Byte Code Generation Library
• Dynamic Proxy와 비슷하게 bytecode를 만들
거나 변경하여 Proxy를 제공하는 라이브러리.
• JDK Dynamic Proxy와 달리 interface 뿐만아
니라 이미 존재하는 class를 서브클래싱하여
method interception을 할 수 있다.
• JDK Dynamic Proxy처럼 reflection으로 호출
하는 방식이지만 같은 이름의 Method가 많을
경우 조금 더 빨리 찾기 때문에 성능적으로 조
금 유리하다.
17
Java Bytecode
ASM
CGLIB
CGLIB (2/2)
18
public class HelloClass {// interface 아닌 class도 proxy 방식 확장
public String hello(String input) {
return "Hello, " + input + "!!!";
}
}
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HelloClass.class);
enhancer.setCallback(new Interceptor());
HelloClass helloObj = (HelloClass) enhancer.create();
System.out.println(helloObj.hello("Tmax"));
CGLIB (2/2)
19
public class HelloClass {// interface 아닌 class도 proxy 방식 확장
public String hello(String input) {
return "Hello, " + input + "!!!";
}
}
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HelloClass.class);
enhancer.setCallback(new Interceptor());
HelloClass helloObj = (HelloClass) enhancer.create();
System.out.println(helloObj.hello("Tmax"));
class Interceptor implements MethodInterceptor {
public Object intercept(Object o, Method m, Object[] args,
MethodProxy mproxy) throws Throwable {
return mproxy.invokeSuper(o, args) + " BY CGLIB";
}
}
IoC Container 개념
20
Inversion of Control
• Inversion of Control : 제어의 역전
• 프로그램 중 일반 라이브러리가 사용자가 작성한 코드 부분의 흐름을 제어하는
방식의 설계를 뜻한다.
• IoC에서는 라이브러리 코드가 업무에 특정한 코드를 호출한다.
• IoC 개념은 Dependency Injection 방식이나 Service Locator 패턴, Factory 패
턴, Template Method 패턴, Callback, Event Loop 등의 방식으로 구현 가능.
21
Dependency Injection
• Dependency Injection : 의존체 주입. (객체 세계에서 객체의 멤버 필드들이 해당 객체가 의
존하는 의존체이다)
• 컴포넌트들의 의존체를 주입할 수 있고 외부에서 설정할 수 있으면 해당 컴포넌트들을 재사용
할 수 있다.
• 의존체로 추상체(인터페이스나 추상 클래스)를 사용하면 의존체 객체를 생성하는 것은 분리된
곳에서 제어할 수 있으므로, 객체의 구현을 많은 코드 수정없이 변경할 수 있다.
• 의존체는 컴포넌트로 주입할 수 있으므로 의존체를 mock 구현체로 주입하면 테스트를 보다
쉽게 할 수 있다.
• Dependency Injection과 Service Locator의 가장 큰 차이점은 dependency를 찾기 위해 코
드가 시스템을 알 필요가 있느냐의 여부
• Spring은 도메인 로직 코드가 프레임웍 자체에 아무런 의존을 갖지 않도록 설계되었다.
22
Injector
Dependency Injection Roles
• Client Object : 다른 객체(서비스)를 사용하는 객체
• Service Object : 사용될 가능성이 있는 모든 객체
• Interfaces : 클라이언트가 서비스를 사용하기 위해 인지하는 인터페이스
• Injector : 서비스를 생성하고 이를 클라이언트에 주입하는 역할을 하는 모듈. 종
종 클라이언트를 만드는 역할도 함.
23
Client ServiceRef1
Injector
Dependency Injection Roles
• Client Object : 다른 객체(서비스)를 사용하는 객체
• Service Object : 사용될 가능성이 있는 모든 객체
• Interfaces : 클라이언트가 서비스를 사용하기 위해 인지하는 인터페이스
• Injector : 서비스를 생성하고 이를 클라이언트에 주입하는 역할을 하는 모듈. 종
종 클라이언트를 만드는 역할도 함.
24
Client ServiceRef1 ServiceImpl1 ServiceRef2 ServiceImpl2
Client와 Dependency
25
@Component
public class SomeComponentImpl implements SomeComponent {
private Someone someone;
private Something something;
public void saySomething() {
System.out.println("Someone " + someone.getName() + "
uses " + something.getMaterial());
}
}
Client 클래스
Dependencies
Dependency Injection Types
• 클라이언트 객체가 서비스 객체 구현체를 받는 방법
• Constructor injection : 클래스의 생성자의 인자 dependency 주입
• Field injection : 클래스 멤버 필드 dependency 주입
• Setter injection : setter 메소드의 인자 dependency 주입
• Method injection : 메소드를 주입
26
Constructor Injection
27
@Component
public class HelloComponentImpl implements HelloComponent {
private Someone someone;
@Autowired // Constructor Injection
public HelloComponentImpl(Someone someone) {
this.someone = someone;
}
public void hello() {
System.out.println("Hello, " + someone.getName());
}
}
ApplicationContext ctx = new
AnnotationConfigApplicationContext(HelloComponentImpl.class,
Youknowwho.class);
HelloComponent h = ctx.getBean(HelloComponent.class);
h.hello();
Spring
Setter Injection
28
@Component
public class SetterComponentImpl implements SetterComponent {
private Someone someone;
@Autowired // Setter Injection
public void setSomeone(Someone someone) {
this.someone = someone;
}
public void hello() {
System.out.println("Hello, " + someone.getName());
}
}
ApplicationContext ctx = new
AnnotationConfigApplicationContext(SetterComponentImpl.class,
Youknowwho.class);
SetterComponent c = ctx.getBean(SetterComponent.class);
c.hello();
Spring
Field Injection
29
@Component
public class FieldComponentImpl implements FieldComponent {
@Autowired // Field Injection
private Someone someone;
public void hello() {
System.out.println("Hello, " + someone.getName());
}
}
ApplicationContext ctx = new
AnnotationConfigApplicationContext(FieldComponentImpl.class,
Youknowwho.class);
FieldComponent c = ctx.getBean(FieldComponent.class);
c.hello();
Spring
Method Injection
• 객체 참조나 값을 inject하는 대신에 method를 inject하는 개념
• getter injection이라고도 함 (불필요한 setter method를 없애겠다는 생각)
• 코드에서 IoC 컨테이너에 대한 dependency를 줄이기 위해 사용될 수 있음
30
public abstract class MethodComponentImpl implements
MethodComponent {
public void hello() {
System.out.println("Hello, use " +
getSomething().getMaterial());
}
public abstract Something getSomething(); // 추상 메소드의 구현
체를 injection하게 됨
}
<bean id="methodComponent"
class="com.example.MethodComponentImpl"> <!-- method injection
-->
<lookup-method name="getSomething" bean="something2"/>
</bean>
Spring
Spring Key Features
31
Spring IoC Container
• BeanFactory interface 구현체가 Spring IoC Container
• ApplicationContext는 BeanFactory의 자식 인터페이스이며 BeanFactory에
AOP 기능, 메시지 리소스 처리 (국제화 관련), 이벤트 처리 등을 추가로 처리하
도록 고안.
• 특별한 이유가 없으면 ApplicationContext를 사용.
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[]
{"services.xml", “daos.xml"}); // XML 방식 configuration
ApplicationContext context =
new AnnotationConfigApplicationContext(MyConfiguration.class); //
java annotation 방식 configuration
32
Configuration
• configuration 정보 : Spring Container가 객체들을 생성하고, 설정하고, 결합하
는 방식을 알려주는 메타 정보
• xml 방식과 java 방식
• Spring 3.0부터 JavaConfig (annotation 방식)를 지원 : Google Guice의 비판
에 대한 수용
• 구현에 따라 약간의 차이는 있지만 대부분 호환
• XML은 field injection을 지원하지 않고, JavaConfig는 method injection을
지원 안함
• Spring에서는 XML에서 annotation 설정도 찾도록 element를 지정할 수 있어
혼용도 가능
33
Configuration Metadata
34
XML과 JavaConfig
35
XML JavaConfig 비고
<beans> root element @Configuration
XML : configuration XML 파일의 root element
Java : configuration 자바 클래스
<bean> element @Bean
XML : bean 정의 XML element
Java : bean 정의 메소드 (리턴 값이 bean임을 나타냄)
<import> element @Import
XML : 다른 configuration XML 파일을 import
Java : @Configuration 자바 클래스 간에 import
XML Config 예제
36
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
… >
<bean id="helloComponent"
class="com.example.HelloComponentImpl">
<constructor-arg ref="someone"/>
<constructor-arg ref="something"/>
</bean>
<bean id="someone" class="com.example.Youknowwho" />
<bean id="something" class="com.example.Metal" />
</beans>
Java Config 예제
37
@Configuration
public class DemoConfiguration {
@Bean
public HelloComponent helloComponent() {
return new HelloComponentImpl(someone(), something());
}
@Bean
public Someone someone() { return new Youknowwho(); }
@Bean
public Something something() { return new Metal(); }
}
Java IoC Configuration은 JavaConfig와 각 빈에 정의된 annotation 두 가지 파트로 구성
XML과 JavaConfig 장단점
• 자바 annotation 방식
• 장점 : annotation 위치만으로도 클래스나 해당 요소 등 많은 정보를 갖고 있
으므로 설정이 훨씬 짧고 간결
• 단점 : configuration 정보는 POJO가 아니고, 설정이 코드 안에 들어가서 제어
하기 어렵다. 해당 bean에 들어가는 annotation에 대해서도 호불호가 갈린다.
• XML 방식
• 장점 : 소스 코드에 변경이 없고 설정이 변경되어도 다시 컴파일할 필요가 없
다. 툴화하기 쉽다.
• 단점 : 설정이 복잡함
38
Injection 방식과 Spring 구현
•Constructor Injection
•Setter Injection
•Field Injection
•Method Injection
39
Spring은 ApplicationContext를 생성할 때 각 bean들을 eagerly initialize 하면서
해당 bean들의 dependency를 resolve하여 미리 Object Graph를 생성하는 구조
Constructor Injection (1/2)
40
@Component // Spring이 관리하는 bean임을 선언
public class HelloComponentImpl implements HelloComponent {
private Someone someone;
@Autowired // Constructor Injection
public HelloComponentImpl(Someone someone) {
this.someone = someone;
}
}
@Component // Spring이 관리하는 bean임을 선언
public class Youknowwho implements Someone {
public String getName() {
return getClass().getName();
}
}
Constructor Injection (2/2)
41
new ApplicationContext(HelloComponentImpl.class)
주어진 bean 등록 요청 (HelloComponentImpl.class)
내부적으로 BeanFactory 생성
beanFactory에서 singleton들을 모두 초기화 (각각 getBean)
ConcurrentHashMap에서 bean 이름으로 검색
singleton bean이 없으면 BeanFactory로 bean 생성
Constructor Injection이므로 생성자 인자에 대해서 getBean
인자 bean들이 만들어진 후 생성자 호출
Reflection 사용
Constructor
Injection
BeanContext
초기화
Constructor Injection (2/2)
42
new ApplicationContext(HelloComponentImpl.class)
주어진 bean 등록 요청 (HelloComponentImpl.class)
내부적으로 BeanFactory 생성
beanFactory에서 singleton들을 모두 초기화 (각각 getBean)
ConcurrentHashMap에서 bean 이름으로 검색
singleton bean이 없으면 BeanFactory로 bean 생성
Constructor Injection이므로 생성자 인자에 대해서 getBean
인자 bean들이 만들어진 후 생성자 호출
Reflection 사용
Constructor
Injection
BeanContext
초기화
// Constructor Injection의 실질적인 실행 순서
// 1. 생성자 인자 bean를 먼저 찾거나 만듬
Someone someone = new Youknowwho();
// 2. 찾은 인자 bean으로 inject하려는 bean의 생성자 호출
HelloComponent bean = new HelloComponentImpl(someone);
Setter Injection (1/2)
43
@Component // Spring이 관리하는 bean임을 선언
public class SetterComponentImpl implements SetterComponent {
private Someone someone;
@Autowired // Setter Injection
public void setSomeone(Someone someone) {
this.someone = someone;
}
}
@Component // Spring이 관리하는 bean임을 선언
public class Youknowwho implements Someone {
public String getName() {
return getClass().getName();
}
}
Setter Injection (2/2)
44
ConcurrentHashMap에서 bean 이름으로 검색
singleton bean이 없으면 BeanFactory로 bean 생성
bean 객체에 대해 각 인자 bean으로 setter 호출
Setter Injection이므로 bean 생성자 먼저 호출 객체 생성
Reflection 사용
Setter Injection
BeanContext
초기화 등BeanContext 내에서 해당 컴포넌트 getBean() 호출
생성 후 dependency 검사. 각각에 대해 getBean() 호출
Setter Injection (2/2)
45
ConcurrentHashMap에서 bean 이름으로 검색
singleton bean이 없으면 BeanFactory로 bean 생성
bean 객체에 대해 각 인자 bean으로 setter 호출
Setter Injection이므로 bean 생성자 먼저 호출 객체 생성
Reflection 사용
Setter Injection
BeanContext
초기화 등BeanContext 내에서 해당 컴포넌트 getBean() 호출
생성 후 dependency 검사. 각각에 대해 getBean() 호출
// Setter Injection의 실질적인 실행 순서
// 1. inject 하려는 bean의 생성자 호출
SetterComponent bean = new SetterComponentImpl();
// 2. 생성자 인자 bean를 먼저 찾거나 만듬
Someone someone = new Youknowwho();
// 3. bean 객체에 setter를 호출
bean.setSomeone(someone);
Field Injection
• Spring에서 Field Injection은 Java annotation 방식만 지원
• XML로 표현하기에 setter와 구분하기 쉽지 않고 별로 큰 차이가 없어서인듯.
• Field Injection 실행 순서는 Setter Injection과 동일하게 먼저 bean을 생성한
후에 dependency를 resolve하는 과정에서 annotate된 Field에 해당하는 bean
을 찾아서 inject.
• 즉, 먼저 bean 생성 후에 field resolve해서 inject
46
@Component
public class FieldComponentImpl implements FieldComponent {
@Autowired // Field Injection
private Someone someone;
}
Method Injection (1/2)
• Spring에서 Method Injection은 XML Configuration 방식만 지원
• ApplicationContext 즉, IoC Container 관련 코드 없이 bean lookup 등을 수행
하고자 할 때 주로 사용. 다른 대부분의 경우는 굳이 사용할 이유가 없음.
47
public abstract class MethodComponentImpl implements
MethodComponent {
public abstract Something getSomething();
}
<bean id="methodComp" class="com.example.MethodComponentImpl">
<!-- method injection -->
<lookup-method name="getSomething" bean="something2"/>
</bean>
Method Injection (2/2)
48
ConcurrentHashMap에서 bean 이름으로 검색
singleton bean이 없으면 BeanFactory로 bean 생성
Method Injection이므로 CGLIB 사용하여 자식 클래스 정의
Reflection 및 CGLIB
Proxy 사용
Method Injection
BeanContext
초기화 등BeanContext 내에서 해당 컴포넌트 getBean() 호출
CGLIB Proxy로 정의된 자식 클래스로 bean 객체 생성
Method Injection (2/2)
49
ConcurrentHashMap에서 bean 이름으로 검색
singleton bean이 없으면 BeanFactory로 bean 생성
Method Injection이므로 CGLIB 사용하여 자식 클래스 정의
Reflection 및 CGLIB
Proxy 사용
Method Injection
BeanContext
초기화 등BeanContext 내에서 해당 컴포넌트 getBean() 호출
CGLIB Proxy로 정의된 자식 클래스로 bean 객체 생성
// Method Injection의 실질적인 실행 순서
// 1. inject 하려는 abstract bean class의 CGLIB 자식 클래스 생성
Enhancer enhancer = new Enhancer();
enhancer.setSuperClass(MethodComponentImpl.class);
…
Class<MethodComponentImpl> clazz = enhancer.createClass();
// 2. bean의 생성자를 호출하여 객체 생성
MethodComponent bean = clazz.newInstance();
Constructor or Setter
• Spring에서는 Constructor Injection과 Setter Injection을 섞어 사용하는 것을
허용
• Constructor Injection은 Mandatory Injection에, Setter Injection은 Optional
Injection에 사용하는 것을 권장
• null이 되어서는 안되는 dependency는 Constructor Injection으로
• dependency resolution이 required가 아닌 경우에는 Setter Injection으로
50
Scope
• Scope은 IoC 컨테이너가 관리하는 빈 객체의 생애주기(lifecycle)을 정의
• Spring은 기본으로 Singleton과 Prototype 두 가지 Scope을 정의
• Spring에서 빈의 기본 Scope은 Singleton
51
Scope 설명
Singleton IoC 컨테이너 단위로 빈이 하나만 생성
Prototype IoC 컨테이너로 빈 요청이 올 때마다 생성
Request (Spring Web) HTTP request 마다 하나씩 빈 객체 매핑
Session (Spring Web) HTTP Session별로 하나씩 빈 객체 매핑
Global-session (Spring Web) 세션과 비슷하지만 Portlet에서 사용
Application (Spring Web) ServletContext의 lifecycle에 해당하는 Scope
기본 Scope
• Singleton scope
• BeanFactory를 통해 getBean() 요청이 오거나 inject 요청이 오면
ConcurrentHashMap으로 singleton bean 객체들을 관리하여 return
• 결과적으로 하나의 객체가 여러 bean들에게 공유됨
• Prototype scope
• BeanFactory를 통해 getBean() 요청이 오거나 inject 요청이 오면 매번
reflection을 사용하여 새로운 bean 객체를 만들어 return
52
Singleton 빈에서 Prototype 빈 참조 (1/3)
• Singleton bean에 Prototype bean을 inject하면 prototype bean은 마치 singleton
scope을 가진 것처럼 동작
• Inject되는 시점에서만 prototype으로 동작하기 때문
• 매번 access할 때마다 prototype처럼 동작하도록 하려면?
• IoC Container 즉, ApplicationContext에서 직접 getBean()을 호출하여
dependency를 resolve는 것이 한 방법
• 이렇게 할 경우 컨테이너에 대한 코드가 비즈니스 로직에 포함되므로 method
injection을 사용하여 회피할 수 있다.
• Spring은 proxyMode를 제공해서 bean이 아닌 scoped proxy bean을 inject할 수
있다.
53
Singleton 빈에서 Prototype 빈 참조 (2/3)
54
@Component // 이 bean은 기본값 Scope인 Singleton
public class SomeComponentImpl implements SomeComponent {
@Autowired // Field Injection
private Something something; // Leather 객체가 inject될 것임
}
@Component // Spring이 관리하는 bean임을 선언
@Scope("prototype") // 이 bean은 prototype Scope
public class Leather implements Something {
public String getMaterial() {
return getClass().getName();
}
}
Singleton 빈에서 Prototype 빈 참조 (3/3)
55
@Component // 이 bean은 기본값 Scope인 Singleton
public class SomeComponentImpl implements SomeComponent {
@Autowired // Field Injection
private Something something; // prototype scoped proxy 객체
가 inject될 것
}
@Component // Spring이 관리하는 bean임을 선언
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value =
"prototype")
public class Leather implements Something {
public String getMaterial() {
return getClass().getName();
}
}
proxyMode는 기본값인 NO, CGLIB 기반의 TARGET_CLASS,
Dynamic Proxy 기반의 INTERFACES 중 하나를 지정
Custom Scope 구현
• singleton이나 prototype이 아닌 scope의 bean을 다른 bean에 inject하려고
하면 bean을 inject하는 게 아니라 AOP scoped proxy 를 inject
• AOP scoped proxy 는 CGLIB 기반의 proxy
• 해당 bean을 access할 때마다 CGLIB proxy 객체가 등록된 커스텀 Scope 객
체에 대해 get을 호출
• 커스텀 Scope 클래스 구현에 따라 get에 의해 객체 return
• 이런 구조적 문제로 http request scope bean을 singleton bean에서 참조하려
고 하면 성능 문제가 발생할 수 있음
56
Web Request/Session Scope 구현
• org.springframework.web.context.request.RequestScope/SessionScope 클
래스
• ThreadLocal에 requestAttributes라는 변수를 두고 같은 request인지 scope을
체크
57
Autowire
• 관련된 bean 클래스들을 자동으로 찾아 inject 해주는 기능
• 설정이 매우 간소해지며, Java annotation을 사용할 경우 configuration이 거의 필
요가 없어짐
• 적합한 bean 후보가 여럿일 경우, 임의로 선택하거나(기본값), 부가적인
@Qualifier 혹은 @Qualifier 기반의 meta annotation 등의 정보를 고려하여 선택
• wiring 방식
• byName : bean 이름으로 찾기
• byType : bean 클래스명으로 찾기
• constructor : bean의 생성자 파라미터의 클래스명으로 찾기
58
Autowire
59
@Component
public class SomeComponentImpl implements SomeComponent {
@Autowired @Qualifier("leather")// Field Injection
private Something something; // Leather 객체를 injection
}
@Component @Qualifier("leather")
public class Leather implements Something {
…
}
@Component @Qualifier("metal")
public class Metal implements Something {
…
}
Lazy Instantiation
• Spring은 기본적으로 컨테이너 즉, ApplicationContext가 생성될 때 모든 bean
들을 eagerly initialize (생성)
• 문맥에 따라 필요한 bean들은 처음 사용될 때 initialize할 수 있도록 lazy-init 옵
션을 제공
60
Bean Lifecycle Callbacks
• Spring이 bean을 생성하거나 해지하는 lifecycle 특정 시점에서 호출해주는 callback
• initialize callbacks 호출 순서
• @PostConstruct 로 표시된 메소드
• InitializingBean I/F를 implement한 경우 afterPropertiesSet() 메소드
• init() : default init method 혹은 지정한 init method
• destroy callbacks 호출 순서
• @PreDestroy 로 표시된 메소드
• DisposableBean I/F를 implement한 경우 destroy() 메소드
• destroy() : default destroy method 혹은 지정한 destroy method
61
JSR 330 DI 자바 표준
62
JSR 330 (javax.inject)
• JSR 330 (javax.inject) : Dependency Injection for Java, Java EE 6
• JSR 299 (CDI) : Contexts and Dependency Injection for the Java EE, Java EE 6
• CDI(JSR 299)는 Java EE에서 Spring을 대체하는 Java EE 표준으로 추진
• JSR 330을 확장하고 있으며, Autowire 기반의 container로 Java EE 기능들의 결합
방법도 표준으로 정의
• Java DI(JSR 330)은 몇 가지 표준적인 annotation만 정의하고 wiring이나 container에
대해서는 언급하지 않음
• Google Guice 개발자와 RedHat JBoss 등에서 주도적으로 진행
• Spring, Guice 등 대부분의 Java 기반 IoC 컨테이너들이 JSR 330은 지원
• 추후 Java SE에도 포함 예상
63
JSR 330 (javax.inject) 내용
• 다섯 개의 annotation과 한 개의 interface로 구성
• @Inject : dependency를 지정. 생성자, 메소드, 필드에 가능
• @Named : 문자열 기반의 qualifier
• @Qualifier : 클래스 type 기반의 qualifier
• @Scope : Scope을 정의할 수 있는 meta annotation
• @Singleton : @Scope 중 유일하게 스펙에서 정의한 annotation. 공유 scope.
• Provider<T> interface
• T get() 메소드 하나를 정의. 일종의 factory 메소드
64
Spring annotations vs. JSR 330 annotations
Spring javax.inject.* javax.inject restrictions / comments
@Autowired @Inject Spring에서는 둘 다 사용 가능
표준인 @Inject는 'required' 속성이 없음
@Component @Named Spring에서 관리하는 bean을 뜻하는 @Component는 표준인
@Named와 거의 동일하게 사용 가능
@Scope("singleton") @Singleton JSR-330은 특별하게 명시되지 않으면 Spring의 prototype
scope이 기본값.
Spring은 singleton이 기본값.
javax.inject 도 사용자 정의 Scope을 위해 @Scope
annotation을 정의
@Qualifier @Named Spring은 @Qualifier나 Generic type을 사용하여 auto wiring
시 엄밀한 제어를 할 수 있음. javax.inject도 @Named에 value
값을 지정하면 유사한 의미
65
66
Spring javax.inject.* javax.inject restrictions / comments
@Value - Spring에서는 Bean이 아닌 primitive나 collection 등의 Value
Injection이 가능함.
@Required - Spring에만 있음.
컨테이너 초기 시에 반드시 initialize되어야 하는 dependency에 대
한 지정.
@Lazy - Spring에만 있음.
IoC 컨테이너 생성 시점이 아니라 처음 액세스될 때 initialize하는 빈
에 대한 표기
다른 IoC 컨테이너
67
Guice
• Google Guice는 Spring이 XML 기반의 설정으로 구성된 점을 비판하며 Java 5
의 annotation과 Generics 기능을 최대한 활용하여 설정하도록 설계
• Spring과 달리 interface 기반이 아니어서 bean들은 임의의 class가 가능
• Spring이 IoC 컨테이너도 3.0 이후 Guice의 비판에 대응하여 JavaConfig를 설
계하여 포함
• Spring은 Java EE integration 측면에서 타 IoC 컨테이너에 비해 방대한 API, SPI
를 구축해놓았지만 Guice는 Java EE 지원이 없어 상대적으로 라이브러리가 가
벼움.
68
Dagger 2
• Spring이나 Google Guice가 runtime에 object graph를 만드는 부분을 비판하며
컴파일 time(annotation processing time)에 코드 생성을 통해 validation과
object graph 생성까지 하는 아이디어
• Runtime Proxy를 사용하지 않으므로 성능이나 메모리 footprint 측면에서 유리하
여 Android와 같은 모바일 환경에서 많이 채택하는 추세
• 상대적으로 기능 구현이 어렵고 런타임 유연성은 약함
• Dagger 1은 Square라는 Financial Startup에서 만들었으며, Dagger 2는 구글에서
개발 중
• Dagger 1은 compile time validation까지 진행, Dagger 2는 object graph까지
compile time에 구성하는 게 목적
69
Issues on IoC containers
(Spring에 대한 비판들)
70
Configuration 복잡도
• Configuration 방법 : XML, Java Configuration Code, Java Annotation,
Autowiring
• Spring 비판
• 설정과 코드를 오가면서 코드를 이해하는 게 어렵다. (주로 XML 설정에 대한
비판)
• xml 방식과 java 방식
• Spring 3.0부터 둘 다 지원
• 기존 코드에 영향을 안 준다는 측면에서 configuration은 XML이 합리적
• bean의 특성은 코드의 일부라고 판단할 수 있으므로 annotation이 합리적
71
과도한 decoupling
• Program to an interface, not an implementation (Design Pattern, GoF)
• decoupling interface from implementation
• 구현체는 대부분 하나인 경우에도 모두 interface를 별도로 선언해야 함
• Too many interfaces
• Cohesive small system과 decoupling을 위한 decoupling
• Spring framework은 후자를 만들게 한다. (fine granularity의 interface 유도)
• Abstract class와 interface (Erich Gamma 인터뷰에서)
• 자바의 interface는 메소드 추가 같은 변경이 어려워 incremental 변경에는 적
합치 않음. Abstract class에서는 구현 자식 class들 변경 없이 메소드 추가 가능.
72
성능 오버헤드
• Reflection + dynamic proxy, CGLIB enhancer 등 reflection을 injection 시에
과도하게 사용
• Map-like API
• bean에 대해 접근할 때 ApplicationContext로부터 getBean(name) 하는 형
태로 성능에 불이익이 있음.
• Bean이 많을수록 Boot-time 성능이 떨어지고, 클래스가 많아짐(interface,
implementation, proxy 등)으로 인해 memory footprint 증가
• 서로 다른 scope을 가진 bean들 간의 injection 시 런타임 성능 이슈
73
Compile-time validation 부족
• object dependency graph 검증이 컴파일 시에 충분히 되지 않으므로, 대부분
의 validation은 코드 실행 후 ApplicationContext 생성 시점에서 이루어짐
74
org.springframework.beans.factory.BeanCreationException: Error creating bean with name
‘helloController'

: Injection of autowired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException

: Could not autowire field: private hello.ConstructorBasedInjection hello.HelloController.cbInj

; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException

: No qualifying bean of type [hello.ConstructorBasedInjection] found for dependency

: expected at least 1 bean which qualifies as autowire candidate for this dependency.
IoC 컨테이너 설계 시 추가 고려 사항들
• 표준 준수 여부
• JSR 330 (javax.inject), CDI (Java EE standard), Spring (de facto)
• Spring API 호환 구현 가능성
• 논리적으로는 컴파일 시점에 dependency를 injection하더라도 대부분 가능
•
75
Discussions
76
Spring Web Request Scope
구현 방식
77
Custom Scope 구현
• singleton이나 prototype이 아닌 scope의 bean을 다른 bean에 inject하려고
하면 bean을 inject하는 게 아니라 AOP scoped proxy 를 inject
• AOP scoped proxy 는 CGLIB 기반의 proxy
• 해당 bean을 access할 때마다 CGLIB proxy 객체가 등록된 커스텀 Scope 객
체에 대해 get을 호출
• 커스텀 Scope 클래스 구현에 따라 get에 의해 객체 return
• 이런 구조적 문제로 http request scope bean을 singleton bean에서 참조하려
고 하면 성능 문제가 발생할 수 있음
78
Request Scope에서 Request와 연결
• Request 발생 시
• WAS Web Container의 request event를 listen하면서 event 발생 시 thread local에
해당 event와 HttpServletRequest 객체를 사용하여 커스텀 Scope 객체를 생성 저장
• 실제 Request Scope의 Bean이 사용될 때 (Dynamic Proxy 메소드 호출)
• proxy 코드에서 getBean을 호출하면 thread local의 커스텀 Scope 객체를 찾아보고
없으면 에러.
• Scope 객체가 있으면 이 Scope 객체 안에서 (ConcurrentHashMap처럼 동작) bean
name으로 bean을 찾고, 없으면 생성해서 저장.
• 이 코드는 Request, Session, Global_Session(Portlet) 모두 공통
• Session인 경우 실제 getBean을 할 때 lock을 사용한다는 차이만 있음 (multi-thread)
79

More Related Content

What's hot

Angular 2 rc5 조사
Angular 2 rc5 조사Angular 2 rc5 조사
Angular 2 rc5 조사Rjs Ryu
 
객체지향프로그래밍 특강
객체지향프로그래밍 특강객체지향프로그래밍 특강
객체지향프로그래밍 특강uEngine Solutions
 
유지보수 가능한 개발 원칙
유지보수 가능한 개발 원칙유지보수 가능한 개발 원칙
유지보수 가능한 개발 원칙Hyosang Hong
 
세미나 Spring mybatis
세미나 Spring mybatis세미나 Spring mybatis
세미나 Spring mybatisSomang Jeong
 
메이븐 기본 이해
메이븐 기본 이해메이븐 기본 이해
메이븐 기본 이해중선 곽
 
Angular2를 위한 타입스크립트
Angular2를 위한 타입스크립트Angular2를 위한 타입스크립트
Angular2를 위한 타입스크립트Jin wook
 
Spring 3의 jsr 303 지원
Spring 3의 jsr 303 지원Spring 3의 jsr 303 지원
Spring 3의 jsr 303 지원Sewon Ann
 
Angular2를 위한 컴포넌트 분석과 개발
Angular2를 위한 컴포넌트 분석과 개발Angular2를 위한 컴포넌트 분석과 개발
Angular2를 위한 컴포넌트 분석과 개발Jin wook
 
AngularJS 2, version 1 and ReactJS
AngularJS 2, version 1 and ReactJSAngularJS 2, version 1 and ReactJS
AngularJS 2, version 1 and ReactJSKenneth Ceyer
 
개발 방식을 바꾸는 15가지 기술
개발 방식을 바꾸는 15가지 기술개발 방식을 바꾸는 15가지 기술
개발 방식을 바꾸는 15가지 기술중선 곽
 
자바9 특징 (Java9 Features)
자바9 특징 (Java9 Features)자바9 특징 (Java9 Features)
자바9 특징 (Java9 Features)Chang-Hwan Han
 
Front end dev 2016 & beyond
Front end dev 2016 & beyondFront end dev 2016 & beyond
Front end dev 2016 & beyondJae Sung Park
 
스프링프레임워크 & 마이바티스 무.료 강의자료 제공 (Spring IoC & DI)_ 구로자바학원/구로오라클학원/구로IT학원
스프링프레임워크 & 마이바티스 무.료 강의자료 제공 (Spring IoC & DI)_ 구로자바학원/구로오라클학원/구로IT학원스프링프레임워크 & 마이바티스 무.료 강의자료 제공 (Spring IoC & DI)_ 구로자바학원/구로오라클학원/구로IT학원
스프링프레임워크 & 마이바티스 무.료 강의자료 제공 (Spring IoC & DI)_ 구로자바학원/구로오라클학원/구로IT학원탑크리에듀(구로디지털단지역3번출구 2분거리)
 
GDG DevFest 2017 Seoul 프론트엔드 모던 프레임워크 낱낱히 파헤치기
 GDG DevFest 2017 Seoul 프론트엔드 모던 프레임워크 낱낱히 파헤치기 GDG DevFest 2017 Seoul 프론트엔드 모던 프레임워크 낱낱히 파헤치기
GDG DevFest 2017 Seoul 프론트엔드 모던 프레임워크 낱낱히 파헤치기Kenneth Ceyer
 
05.실행환경 교육교재(업무처리,연계통합)
05.실행환경 교육교재(업무처리,연계통합)05.실행환경 교육교재(업무처리,연계통합)
05.실행환경 교육교재(업무처리,연계통합)Hankyo
 
JavaEE6 - 설계 차원의 단순성
JavaEE6 - 설계 차원의 단순성JavaEE6 - 설계 차원의 단순성
JavaEE6 - 설계 차원의 단순성Jay Lee
 

What's hot (19)

Angular 2 rc5 조사
Angular 2 rc5 조사Angular 2 rc5 조사
Angular 2 rc5 조사
 
객체지향프로그래밍 특강
객체지향프로그래밍 특강객체지향프로그래밍 특강
객체지향프로그래밍 특강
 
3.Spring IoC&DI(spring ioc실습, XML기반)
3.Spring IoC&DI(spring ioc실습, XML기반)3.Spring IoC&DI(spring ioc실습, XML기반)
3.Spring IoC&DI(spring ioc실습, XML기반)
 
유지보수 가능한 개발 원칙
유지보수 가능한 개발 원칙유지보수 가능한 개발 원칙
유지보수 가능한 개발 원칙
 
세미나 Spring mybatis
세미나 Spring mybatis세미나 Spring mybatis
세미나 Spring mybatis
 
메이븐 기본 이해
메이븐 기본 이해메이븐 기본 이해
메이븐 기본 이해
 
5.Spring IoC&DI(DI와 관련된 어노테이션)
5.Spring IoC&DI(DI와 관련된 어노테이션)5.Spring IoC&DI(DI와 관련된 어노테이션)
5.Spring IoC&DI(DI와 관련된 어노테이션)
 
Angular2를 위한 타입스크립트
Angular2를 위한 타입스크립트Angular2를 위한 타입스크립트
Angular2를 위한 타입스크립트
 
Spring 3의 jsr 303 지원
Spring 3의 jsr 303 지원Spring 3의 jsr 303 지원
Spring 3의 jsr 303 지원
 
Angular2를 위한 컴포넌트 분석과 개발
Angular2를 위한 컴포넌트 분석과 개발Angular2를 위한 컴포넌트 분석과 개발
Angular2를 위한 컴포넌트 분석과 개발
 
AngularJS 2, version 1 and ReactJS
AngularJS 2, version 1 and ReactJSAngularJS 2, version 1 and ReactJS
AngularJS 2, version 1 and ReactJS
 
개발 방식을 바꾸는 15가지 기술
개발 방식을 바꾸는 15가지 기술개발 방식을 바꾸는 15가지 기술
개발 방식을 바꾸는 15가지 기술
 
자바9 특징 (Java9 Features)
자바9 특징 (Java9 Features)자바9 특징 (Java9 Features)
자바9 특징 (Java9 Features)
 
Front end dev 2016 & beyond
Front end dev 2016 & beyondFront end dev 2016 & beyond
Front end dev 2016 & beyond
 
스프링프레임워크 & 마이바티스 무.료 강의자료 제공 (Spring IoC & DI)_ 구로자바학원/구로오라클학원/구로IT학원
스프링프레임워크 & 마이바티스 무.료 강의자료 제공 (Spring IoC & DI)_ 구로자바학원/구로오라클학원/구로IT학원스프링프레임워크 & 마이바티스 무.료 강의자료 제공 (Spring IoC & DI)_ 구로자바학원/구로오라클학원/구로IT학원
스프링프레임워크 & 마이바티스 무.료 강의자료 제공 (Spring IoC & DI)_ 구로자바학원/구로오라클학원/구로IT학원
 
2.Spring IoC & DI (ioc container)
2.Spring IoC & DI (ioc container)2.Spring IoC & DI (ioc container)
2.Spring IoC & DI (ioc container)
 
GDG DevFest 2017 Seoul 프론트엔드 모던 프레임워크 낱낱히 파헤치기
 GDG DevFest 2017 Seoul 프론트엔드 모던 프레임워크 낱낱히 파헤치기 GDG DevFest 2017 Seoul 프론트엔드 모던 프레임워크 낱낱히 파헤치기
GDG DevFest 2017 Seoul 프론트엔드 모던 프레임워크 낱낱히 파헤치기
 
05.실행환경 교육교재(업무처리,연계통합)
05.실행환경 교육교재(업무처리,연계통합)05.실행환경 교육교재(업무처리,연계통합)
05.실행환경 교육교재(업무처리,연계통합)
 
JavaEE6 - 설계 차원의 단순성
JavaEE6 - 설계 차원의 단순성JavaEE6 - 설계 차원의 단순성
JavaEE6 - 설계 차원의 단순성
 

Similar to Spring Framework - Inversion of Control Container

HOONS닷넷 오픈소스 프로젝트 Part1.
HOONS닷넷 오픈소스 프로젝트 Part1.HOONS닷넷 오픈소스 프로젝트 Part1.
HOONS닷넷 오픈소스 프로젝트 Part1.Hojin Jun
 
Spring vs. spring boot
Spring vs. spring bootSpring vs. spring boot
Spring vs. spring bootChloeChoi23
 
반복적인 작업이 싫은 안드로이드 개발자에게
반복적인 작업이 싫은 안드로이드 개발자에게반복적인 작업이 싫은 안드로이드 개발자에게
반복적인 작업이 싫은 안드로이드 개발자에게Sungju Jin
 
Metaworks3 Framework workbook 2015
Metaworks3 Framework workbook 2015Metaworks3 Framework workbook 2015
Metaworks3 Framework workbook 2015uEngine Solutions
 
[Td 2015]각이 다른 mvc6! 그 여섯 번째 이야기!(최지훈)
[Td 2015]각이 다른 mvc6! 그 여섯 번째 이야기!(최지훈)[Td 2015]각이 다른 mvc6! 그 여섯 번째 이야기!(최지훈)
[Td 2015]각이 다른 mvc6! 그 여섯 번째 이야기!(최지훈)Sang Don Kim
 
자바 웹 개발 시작하기 (5주차 : 스프링 프래임워크)
자바 웹 개발 시작하기 (5주차 : 스프링 프래임워크)자바 웹 개발 시작하기 (5주차 : 스프링 프래임워크)
자바 웹 개발 시작하기 (5주차 : 스프링 프래임워크)DK Lee
 
Spring boot 공작소(1-4장)
Spring boot 공작소(1-4장)Spring boot 공작소(1-4장)
Spring boot 공작소(1-4장)Choonghyun Yang
 
Spring3 발표자료 - 김연수
Spring3 발표자료 - 김연수Spring3 발표자료 - 김연수
Spring3 발표자료 - 김연수Yeon Soo Kim
 
Dagger 2.0 을 활용한 의존성 주입
Dagger 2.0 을 활용한 의존성 주입Dagger 2.0 을 활용한 의존성 주입
Dagger 2.0 을 활용한 의존성 주입승용 윤
 
NCS기반 Spring Framework & MyBatis_ 스프링프레임워크 & 마이바티스 ☆무료강의자료 제공/ 구로오라클학원, 탑크리에...
NCS기반 Spring Framework & MyBatis_ 스프링프레임워크 & 마이바티스  ☆무료강의자료 제공/ 구로오라클학원, 탑크리에...NCS기반 Spring Framework & MyBatis_ 스프링프레임워크 & 마이바티스  ☆무료강의자료 제공/ 구로오라클학원, 탑크리에...
NCS기반 Spring Framework & MyBatis_ 스프링프레임워크 & 마이바티스 ☆무료강의자료 제공/ 구로오라클학원, 탑크리에...탑크리에듀(구로디지털단지역3번출구 2분거리)
 
처음 시작하는 라라벨
처음 시작하는 라라벨처음 시작하는 라라벨
처음 시작하는 라라벨KwangSeob Jeong
 
XECon2015 :: [2-1] 정광섭 - 처음 시작하는 laravel
XECon2015 :: [2-1] 정광섭 - 처음 시작하는 laravelXECon2015 :: [2-1] 정광섭 - 처음 시작하는 laravel
XECon2015 :: [2-1] 정광섭 - 처음 시작하는 laravelXpressEngine
 
04.실행환경 교육교재(화면처리)
04.실행환경 교육교재(화면처리)04.실행환경 교육교재(화면처리)
04.실행환경 교육교재(화면처리)Hankyo
 
Angular는 사실 어렵지 않습니다.
Angular는 사실 어렵지 않습니다.Angular는 사실 어렵지 않습니다.
Angular는 사실 어렵지 않습니다.장현 한
 
[H3 2012] Bridge over troubled water : make plug-in for Appspresso
[H3 2012] Bridge over troubled water : make plug-in for Appspresso[H3 2012] Bridge over troubled water : make plug-in for Appspresso
[H3 2012] Bridge over troubled water : make plug-in for AppspressoKTH, 케이티하이텔
 
01.개발환경 교육교재
01.개발환경 교육교재01.개발환경 교육교재
01.개발환경 교육교재Hankyo
 
[D2 COMMUNITY] Open Container Seoul Meetup - 마이크로 서비스 아키텍쳐와 Docker kubernetes
[D2 COMMUNITY] Open Container Seoul Meetup -  마이크로 서비스 아키텍쳐와 Docker kubernetes[D2 COMMUNITY] Open Container Seoul Meetup -  마이크로 서비스 아키텍쳐와 Docker kubernetes
[D2 COMMUNITY] Open Container Seoul Meetup - 마이크로 서비스 아키텍쳐와 Docker kubernetesNAVER D2
 

Similar to Spring Framework - Inversion of Control Container (20)

Springmvc
SpringmvcSpringmvc
Springmvc
 
HOONS닷넷 오픈소스 프로젝트 Part1.
HOONS닷넷 오픈소스 프로젝트 Part1.HOONS닷넷 오픈소스 프로젝트 Part1.
HOONS닷넷 오픈소스 프로젝트 Part1.
 
Spring vs. spring boot
Spring vs. spring bootSpring vs. spring boot
Spring vs. spring boot
 
반복적인 작업이 싫은 안드로이드 개발자에게
반복적인 작업이 싫은 안드로이드 개발자에게반복적인 작업이 싫은 안드로이드 개발자에게
반복적인 작업이 싫은 안드로이드 개발자에게
 
Metaworks3 Framework workbook 2015
Metaworks3 Framework workbook 2015Metaworks3 Framework workbook 2015
Metaworks3 Framework workbook 2015
 
[Td 2015]각이 다른 mvc6! 그 여섯 번째 이야기!(최지훈)
[Td 2015]각이 다른 mvc6! 그 여섯 번째 이야기!(최지훈)[Td 2015]각이 다른 mvc6! 그 여섯 번째 이야기!(최지훈)
[Td 2015]각이 다른 mvc6! 그 여섯 번째 이야기!(최지훈)
 
자바 웹 개발 시작하기 (5주차 : 스프링 프래임워크)
자바 웹 개발 시작하기 (5주차 : 스프링 프래임워크)자바 웹 개발 시작하기 (5주차 : 스프링 프래임워크)
자바 웹 개발 시작하기 (5주차 : 스프링 프래임워크)
 
Spring boot 공작소(1-4장)
Spring boot 공작소(1-4장)Spring boot 공작소(1-4장)
Spring boot 공작소(1-4장)
 
Spring3 발표자료 - 김연수
Spring3 발표자료 - 김연수Spring3 발표자료 - 김연수
Spring3 발표자료 - 김연수
 
Dagger 2.0 을 활용한 의존성 주입
Dagger 2.0 을 활용한 의존성 주입Dagger 2.0 을 활용한 의존성 주입
Dagger 2.0 을 활용한 의존성 주입
 
RHAMT 소개
RHAMT 소개RHAMT 소개
RHAMT 소개
 
NCS기반 Spring Framework & MyBatis_ 스프링프레임워크 & 마이바티스 ☆무료강의자료 제공/ 구로오라클학원, 탑크리에...
NCS기반 Spring Framework & MyBatis_ 스프링프레임워크 & 마이바티스  ☆무료강의자료 제공/ 구로오라클학원, 탑크리에...NCS기반 Spring Framework & MyBatis_ 스프링프레임워크 & 마이바티스  ☆무료강의자료 제공/ 구로오라클학원, 탑크리에...
NCS기반 Spring Framework & MyBatis_ 스프링프레임워크 & 마이바티스 ☆무료강의자료 제공/ 구로오라클학원, 탑크리에...
 
처음 시작하는 라라벨
처음 시작하는 라라벨처음 시작하는 라라벨
처음 시작하는 라라벨
 
XECon2015 :: [2-1] 정광섭 - 처음 시작하는 laravel
XECon2015 :: [2-1] 정광섭 - 처음 시작하는 laravelXECon2015 :: [2-1] 정광섭 - 처음 시작하는 laravel
XECon2015 :: [2-1] 정광섭 - 처음 시작하는 laravel
 
04.실행환경 교육교재(화면처리)
04.실행환경 교육교재(화면처리)04.실행환경 교육교재(화면처리)
04.실행환경 교육교재(화면처리)
 
Angular는 사실 어렵지 않습니다.
Angular는 사실 어렵지 않습니다.Angular는 사실 어렵지 않습니다.
Angular는 사실 어렵지 않습니다.
 
[H3 2012] Bridge over troubled water : make plug-in for Appspresso
[H3 2012] Bridge over troubled water : make plug-in for Appspresso[H3 2012] Bridge over troubled water : make plug-in for Appspresso
[H3 2012] Bridge over troubled water : make plug-in for Appspresso
 
01.개발환경 교육교재
01.개발환경 교육교재01.개발환경 교육교재
01.개발환경 교육교재
 
ecdevday4
ecdevday4ecdevday4
ecdevday4
 
[D2 COMMUNITY] Open Container Seoul Meetup - 마이크로 서비스 아키텍쳐와 Docker kubernetes
[D2 COMMUNITY] Open Container Seoul Meetup -  마이크로 서비스 아키텍쳐와 Docker kubernetes[D2 COMMUNITY] Open Container Seoul Meetup -  마이크로 서비스 아키텍쳐와 Docker kubernetes
[D2 COMMUNITY] Open Container Seoul Meetup - 마이크로 서비스 아키텍쳐와 Docker kubernetes
 

More from Kyung Koo Yoon

Smart software engineer
Smart software engineerSmart software engineer
Smart software engineerKyung Koo Yoon
 
Lecture on Java Concurrency Day 3 on Feb 11, 2009.
Lecture on Java Concurrency Day 3 on Feb 11, 2009.Lecture on Java Concurrency Day 3 on Feb 11, 2009.
Lecture on Java Concurrency Day 3 on Feb 11, 2009.Kyung Koo Yoon
 
Lecture on Java Concurrency Day 2 on Feb 4, 2009.
Lecture on Java Concurrency Day 2 on Feb 4, 2009.Lecture on Java Concurrency Day 2 on Feb 4, 2009.
Lecture on Java Concurrency Day 2 on Feb 4, 2009.Kyung Koo Yoon
 
Lecture on Java Concurrency Day 4 on Feb 18, 2009.
Lecture on Java Concurrency Day 4 on Feb 18, 2009.Lecture on Java Concurrency Day 4 on Feb 18, 2009.
Lecture on Java Concurrency Day 4 on Feb 18, 2009.Kyung Koo Yoon
 
Lecture on Java Concurrency Day 1 on Jan 21, 2009.
Lecture on Java Concurrency Day 1 on Jan 21, 2009.Lecture on Java Concurrency Day 1 on Jan 21, 2009.
Lecture on Java Concurrency Day 1 on Jan 21, 2009.Kyung Koo Yoon
 
창의와 열정, 소프트웨어 엔지니어
창의와 열정, 소프트웨어 엔지니어창의와 열정, 소프트웨어 엔지니어
창의와 열정, 소프트웨어 엔지니어Kyung Koo Yoon
 

More from Kyung Koo Yoon (13)

Kubernetes
Kubernetes Kubernetes
Kubernetes
 
Java 8 고급 (6/6)
Java 8 고급 (6/6)Java 8 고급 (6/6)
Java 8 고급 (6/6)
 
Java 8 고급 (5/6)
Java 8 고급 (5/6)Java 8 고급 (5/6)
Java 8 고급 (5/6)
 
Java 8 고급 (4/6)
Java 8 고급 (4/6)Java 8 고급 (4/6)
Java 8 고급 (4/6)
 
Java 8 고급 (3/6)
Java 8 고급 (3/6)Java 8 고급 (3/6)
Java 8 고급 (3/6)
 
Java 8 고급 (2/6)
Java 8 고급 (2/6)Java 8 고급 (2/6)
Java 8 고급 (2/6)
 
Java 8 고급 (1/6)
Java 8 고급 (1/6)Java 8 고급 (1/6)
Java 8 고급 (1/6)
 
Smart software engineer
Smart software engineerSmart software engineer
Smart software engineer
 
Lecture on Java Concurrency Day 3 on Feb 11, 2009.
Lecture on Java Concurrency Day 3 on Feb 11, 2009.Lecture on Java Concurrency Day 3 on Feb 11, 2009.
Lecture on Java Concurrency Day 3 on Feb 11, 2009.
 
Lecture on Java Concurrency Day 2 on Feb 4, 2009.
Lecture on Java Concurrency Day 2 on Feb 4, 2009.Lecture on Java Concurrency Day 2 on Feb 4, 2009.
Lecture on Java Concurrency Day 2 on Feb 4, 2009.
 
Lecture on Java Concurrency Day 4 on Feb 18, 2009.
Lecture on Java Concurrency Day 4 on Feb 18, 2009.Lecture on Java Concurrency Day 4 on Feb 18, 2009.
Lecture on Java Concurrency Day 4 on Feb 18, 2009.
 
Lecture on Java Concurrency Day 1 on Jan 21, 2009.
Lecture on Java Concurrency Day 1 on Jan 21, 2009.Lecture on Java Concurrency Day 1 on Jan 21, 2009.
Lecture on Java Concurrency Day 1 on Jan 21, 2009.
 
창의와 열정, 소프트웨어 엔지니어
창의와 열정, 소프트웨어 엔지니어창의와 열정, 소프트웨어 엔지니어
창의와 열정, 소프트웨어 엔지니어
 

Spring Framework - Inversion of Control Container

  • 1. Spring Framework Inversion of Control Container 2015년 11월 17일 윤경구 1
  • 2. 차례 • Framework과 Spring • 사전 지식 • IoC 기본 개념 • Spring IoC 핵심 기능 • JSR 330 javax.inject 표준 • IoC 컨테이너 관련 이슈 및 Spring 비판 2
  • 4. Framework이란? • 프레임웍은 사용자가 작성한 코드와 합쳐져서 선택적으로 변경 가능한, 고유한 기능을 제공하는 소프트웨어 • 프레임웍의 특징 • 제어의 역전 (Inversion of Control) : 프로그램 제어 흐름을 호출자가 결정하 는 것이 아니라 프레임웍이 결정한다 • 기본 동작 : 확장 없이도 동작하는 기본 동작들이 제공되어야 한다. • 사용자 코드를 통한 기능 확장 : 특정 기능만 선택적으로 확장할 수 있다. • 프레임웍 코드는 변경되지 않는다 : 사용자 기능을 확장할 수 있지만, 프레임 웍 코드 자체는 변경될 필요가 없어야 한다. 4
  • 5. 좋은 Framework에 대한 생각 • 역할의 분리 : 시스템과 비즈니스 로직의 분리 (개발자, 아키텍트, 시스템 담당) • 아키텍처 효율성 • 결과물이 시스템에 부담을 적게 줘야 • 결과물의 수준이 개발자에 의존하지 않고 큰 차이가 없어야 • 생산성 • 간결하고 빠른 개발 / 적은 인적 비용 / 재사용성 • short learning curve : 특히 비즈니스 로직 구현이 직관적이고, 기술적으로 진입 장벽 이 낮아야 함 • Tooling이 용이 • 기술 확산이 쉬워야 (Viral) : 표준의 힘, 새로운 기술에 개발자들이 유인될 수 있음 5
  • 6. Spring의 EJB 모델 비판 • 복잡한 시스템을 비즈니스 개발자에게 노출 • EJB는 컨테이너 환경에 대한 의존이 심해 테스트하기 어렵다. • 클래스로더 구조가 복잡하여 WAS 구조를 모르면 이해하기 어렵다. • 설정(deployment descriptor)이 너무 복잡하여 이해하기 어렵다. • Business 객체를 EJB remote interface(티어 구조)로 설계하면 불필요하게 복잡해질뿐만 아 니라 객체 지향 원칙을 해친다. • EJB는 간단한 것을 힘들게 구현한다. (Over-Engineering) • EJB는 환경과 요건에 따른 implementation 방식 중 하나여야 하는 것을 일반적인 Business 객체 모두에 강요한다. (특정한 경우에만 적합하다) • EJB는 분산 환경에서 복잡한 트랜잭션 관리가 필요한 경우 (declarative transaction management 장점) 외에는 써야 할 이유가 딱히 없다. 6
  • 7. Spring History • 1.0 릴리스 (2004년 3월) : EJB를 비판하며 Apache 라이센스로 출시 • IoC container (핵심 코어 기능 모두 구현) • Web MVC, Hibernate 연동, 트랜잭션 관리 등 • 2.0 릴리스 (2006년) • AOP 기능 추가 • 2.5 ~ 3.0 릴리스 (2007년 ~ 2009년) • XML 외에 Java 5의 annotation을 활용한 JavaConfig 설정 기능 (Guice 비판 대응) • 4.0 릴리스 (2013년) : Java 6 이후 버전만 지원 • Java 8, Groovy, Java EE 7, WebSocket 7
  • 8. Spring Framework • Spring Core Container : IoC • AOP • Data Access • Transaction Management • Web MVC • Remote Access • Testing • Convention over Configuration RAD : Spring Boot & Spring Roo • Spring Batch • Spring Integration : EAI 8
  • 10. • Class, Constructor, Field, Method, Package에 붙을 수 있음 • @interface를 통해 일종의 클래스로 선언함 (컴파일하면 실제로 interface가 됨) • Target : annotation이 붙을 수 있는 위치를 지정 • Retention : annotation의 유효 범위 (SOURCE, CLASS, RUNTIME) Java annotation 10 import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface TxMarker { TxValue value(); }
  • 11. • Class, Constructor, Field, Method, Package에 붙을 수 있음 • @interface를 통해 일종의 클래스로 선언함 (컴파일하면 실제로 interface가 됨) • Target : annotation이 붙을 수 있는 위치를 지정 • Retention : annotation의 유효 범위 (SOURCE, CLASS, RUNTIME) public interface TxService { @TxMarker(TxValue.REQUIRED) void service(); } Java annotation 11 import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface TxMarker { TxValue value(); }
  • 12. meta-annotation • meta-annotation : simply an annotation that can be applied to another annotation (an annotation that is declared on another annotation) • 아래 예제 annotation에서 정의된 @Service는 @Component로도 취급됨 • 여기에서 @Component가 meta-annotation @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component // Spring은 이 선언에 따라 @Service를 @Component처럼 취급 public @interface Service { // .... } 12
  • 13. composed annotation • composed annotation : 여러 개의 meta-annotation을 하나의 커스텀 annotation으로 결합해주는 annotation • 아래 예에서 @TransactionalService는 meta-annoation인 @Transactional과 @Service를 결합한 composed annotation @Transactional @Service @Target(TYPE) @Retention(RUNTIME) @Documented public @interface TransactionalService { // .... } 13
  • 14. BCI : Byte Code Instrumentation • source 코드가 아닌 컴파일된 bytecode를 직접 수정하여 bytecode를 변경하는 방식 • 두 가지 시점에서 변경이 가능 • ClassLoader의 loadClass에서 defineClass를 호출하기 전에 • JVM agent로 등록하여 클래스가 로드될 때 JVM이 실행시켜주는 callback 메 소드 안에서 14
  • 15. Dynamic Proxy 15 public interface TxService { void service(); } Class class = Proxy.getProxyClass(classloader, TxService.class);
  • 16. Dynamic Proxy 16 public interface TxService { void service(); } Class class = Proxy.getProxyClass(classloader, TxService.class); // 만들어지는 Proxy bytecode를 Java code로 표현한다면 … public class $Proxy0 implements TxService { private InvocationHandler h; private static Method m3; // static initializer에서 reflection으로 초기화 public $Proxy0(InvocationHandler h) { this.h = h; } public void service() { // interface에 선언된 모든 메소드들을 다음 내용으로 채워 구현 h.invoke(this, m3, null); } ... }
  • 17. CGLIB (1/2) • cglib : Byte Code Generation Library • Dynamic Proxy와 비슷하게 bytecode를 만들 거나 변경하여 Proxy를 제공하는 라이브러리. • JDK Dynamic Proxy와 달리 interface 뿐만아 니라 이미 존재하는 class를 서브클래싱하여 method interception을 할 수 있다. • JDK Dynamic Proxy처럼 reflection으로 호출 하는 방식이지만 같은 이름의 Method가 많을 경우 조금 더 빨리 찾기 때문에 성능적으로 조 금 유리하다. 17 Java Bytecode ASM CGLIB
  • 18. CGLIB (2/2) 18 public class HelloClass {// interface 아닌 class도 proxy 방식 확장 public String hello(String input) { return "Hello, " + input + "!!!"; } } Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HelloClass.class); enhancer.setCallback(new Interceptor()); HelloClass helloObj = (HelloClass) enhancer.create(); System.out.println(helloObj.hello("Tmax"));
  • 19. CGLIB (2/2) 19 public class HelloClass {// interface 아닌 class도 proxy 방식 확장 public String hello(String input) { return "Hello, " + input + "!!!"; } } Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HelloClass.class); enhancer.setCallback(new Interceptor()); HelloClass helloObj = (HelloClass) enhancer.create(); System.out.println(helloObj.hello("Tmax")); class Interceptor implements MethodInterceptor { public Object intercept(Object o, Method m, Object[] args, MethodProxy mproxy) throws Throwable { return mproxy.invokeSuper(o, args) + " BY CGLIB"; } }
  • 21. Inversion of Control • Inversion of Control : 제어의 역전 • 프로그램 중 일반 라이브러리가 사용자가 작성한 코드 부분의 흐름을 제어하는 방식의 설계를 뜻한다. • IoC에서는 라이브러리 코드가 업무에 특정한 코드를 호출한다. • IoC 개념은 Dependency Injection 방식이나 Service Locator 패턴, Factory 패 턴, Template Method 패턴, Callback, Event Loop 등의 방식으로 구현 가능. 21
  • 22. Dependency Injection • Dependency Injection : 의존체 주입. (객체 세계에서 객체의 멤버 필드들이 해당 객체가 의 존하는 의존체이다) • 컴포넌트들의 의존체를 주입할 수 있고 외부에서 설정할 수 있으면 해당 컴포넌트들을 재사용 할 수 있다. • 의존체로 추상체(인터페이스나 추상 클래스)를 사용하면 의존체 객체를 생성하는 것은 분리된 곳에서 제어할 수 있으므로, 객체의 구현을 많은 코드 수정없이 변경할 수 있다. • 의존체는 컴포넌트로 주입할 수 있으므로 의존체를 mock 구현체로 주입하면 테스트를 보다 쉽게 할 수 있다. • Dependency Injection과 Service Locator의 가장 큰 차이점은 dependency를 찾기 위해 코 드가 시스템을 알 필요가 있느냐의 여부 • Spring은 도메인 로직 코드가 프레임웍 자체에 아무런 의존을 갖지 않도록 설계되었다. 22
  • 23. Injector Dependency Injection Roles • Client Object : 다른 객체(서비스)를 사용하는 객체 • Service Object : 사용될 가능성이 있는 모든 객체 • Interfaces : 클라이언트가 서비스를 사용하기 위해 인지하는 인터페이스 • Injector : 서비스를 생성하고 이를 클라이언트에 주입하는 역할을 하는 모듈. 종 종 클라이언트를 만드는 역할도 함. 23 Client ServiceRef1
  • 24. Injector Dependency Injection Roles • Client Object : 다른 객체(서비스)를 사용하는 객체 • Service Object : 사용될 가능성이 있는 모든 객체 • Interfaces : 클라이언트가 서비스를 사용하기 위해 인지하는 인터페이스 • Injector : 서비스를 생성하고 이를 클라이언트에 주입하는 역할을 하는 모듈. 종 종 클라이언트를 만드는 역할도 함. 24 Client ServiceRef1 ServiceImpl1 ServiceRef2 ServiceImpl2
  • 25. Client와 Dependency 25 @Component public class SomeComponentImpl implements SomeComponent { private Someone someone; private Something something; public void saySomething() { System.out.println("Someone " + someone.getName() + " uses " + something.getMaterial()); } } Client 클래스 Dependencies
  • 26. Dependency Injection Types • 클라이언트 객체가 서비스 객체 구현체를 받는 방법 • Constructor injection : 클래스의 생성자의 인자 dependency 주입 • Field injection : 클래스 멤버 필드 dependency 주입 • Setter injection : setter 메소드의 인자 dependency 주입 • Method injection : 메소드를 주입 26
  • 27. Constructor Injection 27 @Component public class HelloComponentImpl implements HelloComponent { private Someone someone; @Autowired // Constructor Injection public HelloComponentImpl(Someone someone) { this.someone = someone; } public void hello() { System.out.println("Hello, " + someone.getName()); } } ApplicationContext ctx = new AnnotationConfigApplicationContext(HelloComponentImpl.class, Youknowwho.class); HelloComponent h = ctx.getBean(HelloComponent.class); h.hello(); Spring
  • 28. Setter Injection 28 @Component public class SetterComponentImpl implements SetterComponent { private Someone someone; @Autowired // Setter Injection public void setSomeone(Someone someone) { this.someone = someone; } public void hello() { System.out.println("Hello, " + someone.getName()); } } ApplicationContext ctx = new AnnotationConfigApplicationContext(SetterComponentImpl.class, Youknowwho.class); SetterComponent c = ctx.getBean(SetterComponent.class); c.hello(); Spring
  • 29. Field Injection 29 @Component public class FieldComponentImpl implements FieldComponent { @Autowired // Field Injection private Someone someone; public void hello() { System.out.println("Hello, " + someone.getName()); } } ApplicationContext ctx = new AnnotationConfigApplicationContext(FieldComponentImpl.class, Youknowwho.class); FieldComponent c = ctx.getBean(FieldComponent.class); c.hello(); Spring
  • 30. Method Injection • 객체 참조나 값을 inject하는 대신에 method를 inject하는 개념 • getter injection이라고도 함 (불필요한 setter method를 없애겠다는 생각) • 코드에서 IoC 컨테이너에 대한 dependency를 줄이기 위해 사용될 수 있음 30 public abstract class MethodComponentImpl implements MethodComponent { public void hello() { System.out.println("Hello, use " + getSomething().getMaterial()); } public abstract Something getSomething(); // 추상 메소드의 구현 체를 injection하게 됨 } <bean id="methodComponent" class="com.example.MethodComponentImpl"> <!-- method injection --> <lookup-method name="getSomething" bean="something2"/> </bean> Spring
  • 32. Spring IoC Container • BeanFactory interface 구현체가 Spring IoC Container • ApplicationContext는 BeanFactory의 자식 인터페이스이며 BeanFactory에 AOP 기능, 메시지 리소스 처리 (국제화 관련), 이벤트 처리 등을 추가로 처리하 도록 고안. • 특별한 이유가 없으면 ApplicationContext를 사용. ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", “daos.xml"}); // XML 방식 configuration ApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class); // java annotation 방식 configuration 32
  • 33. Configuration • configuration 정보 : Spring Container가 객체들을 생성하고, 설정하고, 결합하 는 방식을 알려주는 메타 정보 • xml 방식과 java 방식 • Spring 3.0부터 JavaConfig (annotation 방식)를 지원 : Google Guice의 비판 에 대한 수용 • 구현에 따라 약간의 차이는 있지만 대부분 호환 • XML은 field injection을 지원하지 않고, JavaConfig는 method injection을 지원 안함 • Spring에서는 XML에서 annotation 설정도 찾도록 element를 지정할 수 있어 혼용도 가능 33
  • 35. XML과 JavaConfig 35 XML JavaConfig 비고 <beans> root element @Configuration XML : configuration XML 파일의 root element Java : configuration 자바 클래스 <bean> element @Bean XML : bean 정의 XML element Java : bean 정의 메소드 (리턴 값이 bean임을 나타냄) <import> element @Import XML : 다른 configuration XML 파일을 import Java : @Configuration 자바 클래스 간에 import
  • 36. XML Config 예제 36 <?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" … > <bean id="helloComponent" class="com.example.HelloComponentImpl"> <constructor-arg ref="someone"/> <constructor-arg ref="something"/> </bean> <bean id="someone" class="com.example.Youknowwho" /> <bean id="something" class="com.example.Metal" /> </beans>
  • 37. Java Config 예제 37 @Configuration public class DemoConfiguration { @Bean public HelloComponent helloComponent() { return new HelloComponentImpl(someone(), something()); } @Bean public Someone someone() { return new Youknowwho(); } @Bean public Something something() { return new Metal(); } } Java IoC Configuration은 JavaConfig와 각 빈에 정의된 annotation 두 가지 파트로 구성
  • 38. XML과 JavaConfig 장단점 • 자바 annotation 방식 • 장점 : annotation 위치만으로도 클래스나 해당 요소 등 많은 정보를 갖고 있 으므로 설정이 훨씬 짧고 간결 • 단점 : configuration 정보는 POJO가 아니고, 설정이 코드 안에 들어가서 제어 하기 어렵다. 해당 bean에 들어가는 annotation에 대해서도 호불호가 갈린다. • XML 방식 • 장점 : 소스 코드에 변경이 없고 설정이 변경되어도 다시 컴파일할 필요가 없 다. 툴화하기 쉽다. • 단점 : 설정이 복잡함 38
  • 39. Injection 방식과 Spring 구현 •Constructor Injection •Setter Injection •Field Injection •Method Injection 39 Spring은 ApplicationContext를 생성할 때 각 bean들을 eagerly initialize 하면서 해당 bean들의 dependency를 resolve하여 미리 Object Graph를 생성하는 구조
  • 40. Constructor Injection (1/2) 40 @Component // Spring이 관리하는 bean임을 선언 public class HelloComponentImpl implements HelloComponent { private Someone someone; @Autowired // Constructor Injection public HelloComponentImpl(Someone someone) { this.someone = someone; } } @Component // Spring이 관리하는 bean임을 선언 public class Youknowwho implements Someone { public String getName() { return getClass().getName(); } }
  • 41. Constructor Injection (2/2) 41 new ApplicationContext(HelloComponentImpl.class) 주어진 bean 등록 요청 (HelloComponentImpl.class) 내부적으로 BeanFactory 생성 beanFactory에서 singleton들을 모두 초기화 (각각 getBean) ConcurrentHashMap에서 bean 이름으로 검색 singleton bean이 없으면 BeanFactory로 bean 생성 Constructor Injection이므로 생성자 인자에 대해서 getBean 인자 bean들이 만들어진 후 생성자 호출 Reflection 사용 Constructor Injection BeanContext 초기화
  • 42. Constructor Injection (2/2) 42 new ApplicationContext(HelloComponentImpl.class) 주어진 bean 등록 요청 (HelloComponentImpl.class) 내부적으로 BeanFactory 생성 beanFactory에서 singleton들을 모두 초기화 (각각 getBean) ConcurrentHashMap에서 bean 이름으로 검색 singleton bean이 없으면 BeanFactory로 bean 생성 Constructor Injection이므로 생성자 인자에 대해서 getBean 인자 bean들이 만들어진 후 생성자 호출 Reflection 사용 Constructor Injection BeanContext 초기화 // Constructor Injection의 실질적인 실행 순서 // 1. 생성자 인자 bean를 먼저 찾거나 만듬 Someone someone = new Youknowwho(); // 2. 찾은 인자 bean으로 inject하려는 bean의 생성자 호출 HelloComponent bean = new HelloComponentImpl(someone);
  • 43. Setter Injection (1/2) 43 @Component // Spring이 관리하는 bean임을 선언 public class SetterComponentImpl implements SetterComponent { private Someone someone; @Autowired // Setter Injection public void setSomeone(Someone someone) { this.someone = someone; } } @Component // Spring이 관리하는 bean임을 선언 public class Youknowwho implements Someone { public String getName() { return getClass().getName(); } }
  • 44. Setter Injection (2/2) 44 ConcurrentHashMap에서 bean 이름으로 검색 singleton bean이 없으면 BeanFactory로 bean 생성 bean 객체에 대해 각 인자 bean으로 setter 호출 Setter Injection이므로 bean 생성자 먼저 호출 객체 생성 Reflection 사용 Setter Injection BeanContext 초기화 등BeanContext 내에서 해당 컴포넌트 getBean() 호출 생성 후 dependency 검사. 각각에 대해 getBean() 호출
  • 45. Setter Injection (2/2) 45 ConcurrentHashMap에서 bean 이름으로 검색 singleton bean이 없으면 BeanFactory로 bean 생성 bean 객체에 대해 각 인자 bean으로 setter 호출 Setter Injection이므로 bean 생성자 먼저 호출 객체 생성 Reflection 사용 Setter Injection BeanContext 초기화 등BeanContext 내에서 해당 컴포넌트 getBean() 호출 생성 후 dependency 검사. 각각에 대해 getBean() 호출 // Setter Injection의 실질적인 실행 순서 // 1. inject 하려는 bean의 생성자 호출 SetterComponent bean = new SetterComponentImpl(); // 2. 생성자 인자 bean를 먼저 찾거나 만듬 Someone someone = new Youknowwho(); // 3. bean 객체에 setter를 호출 bean.setSomeone(someone);
  • 46. Field Injection • Spring에서 Field Injection은 Java annotation 방식만 지원 • XML로 표현하기에 setter와 구분하기 쉽지 않고 별로 큰 차이가 없어서인듯. • Field Injection 실행 순서는 Setter Injection과 동일하게 먼저 bean을 생성한 후에 dependency를 resolve하는 과정에서 annotate된 Field에 해당하는 bean 을 찾아서 inject. • 즉, 먼저 bean 생성 후에 field resolve해서 inject 46 @Component public class FieldComponentImpl implements FieldComponent { @Autowired // Field Injection private Someone someone; }
  • 47. Method Injection (1/2) • Spring에서 Method Injection은 XML Configuration 방식만 지원 • ApplicationContext 즉, IoC Container 관련 코드 없이 bean lookup 등을 수행 하고자 할 때 주로 사용. 다른 대부분의 경우는 굳이 사용할 이유가 없음. 47 public abstract class MethodComponentImpl implements MethodComponent { public abstract Something getSomething(); } <bean id="methodComp" class="com.example.MethodComponentImpl"> <!-- method injection --> <lookup-method name="getSomething" bean="something2"/> </bean>
  • 48. Method Injection (2/2) 48 ConcurrentHashMap에서 bean 이름으로 검색 singleton bean이 없으면 BeanFactory로 bean 생성 Method Injection이므로 CGLIB 사용하여 자식 클래스 정의 Reflection 및 CGLIB Proxy 사용 Method Injection BeanContext 초기화 등BeanContext 내에서 해당 컴포넌트 getBean() 호출 CGLIB Proxy로 정의된 자식 클래스로 bean 객체 생성
  • 49. Method Injection (2/2) 49 ConcurrentHashMap에서 bean 이름으로 검색 singleton bean이 없으면 BeanFactory로 bean 생성 Method Injection이므로 CGLIB 사용하여 자식 클래스 정의 Reflection 및 CGLIB Proxy 사용 Method Injection BeanContext 초기화 등BeanContext 내에서 해당 컴포넌트 getBean() 호출 CGLIB Proxy로 정의된 자식 클래스로 bean 객체 생성 // Method Injection의 실질적인 실행 순서 // 1. inject 하려는 abstract bean class의 CGLIB 자식 클래스 생성 Enhancer enhancer = new Enhancer(); enhancer.setSuperClass(MethodComponentImpl.class); … Class<MethodComponentImpl> clazz = enhancer.createClass(); // 2. bean의 생성자를 호출하여 객체 생성 MethodComponent bean = clazz.newInstance();
  • 50. Constructor or Setter • Spring에서는 Constructor Injection과 Setter Injection을 섞어 사용하는 것을 허용 • Constructor Injection은 Mandatory Injection에, Setter Injection은 Optional Injection에 사용하는 것을 권장 • null이 되어서는 안되는 dependency는 Constructor Injection으로 • dependency resolution이 required가 아닌 경우에는 Setter Injection으로 50
  • 51. Scope • Scope은 IoC 컨테이너가 관리하는 빈 객체의 생애주기(lifecycle)을 정의 • Spring은 기본으로 Singleton과 Prototype 두 가지 Scope을 정의 • Spring에서 빈의 기본 Scope은 Singleton 51 Scope 설명 Singleton IoC 컨테이너 단위로 빈이 하나만 생성 Prototype IoC 컨테이너로 빈 요청이 올 때마다 생성 Request (Spring Web) HTTP request 마다 하나씩 빈 객체 매핑 Session (Spring Web) HTTP Session별로 하나씩 빈 객체 매핑 Global-session (Spring Web) 세션과 비슷하지만 Portlet에서 사용 Application (Spring Web) ServletContext의 lifecycle에 해당하는 Scope
  • 52. 기본 Scope • Singleton scope • BeanFactory를 통해 getBean() 요청이 오거나 inject 요청이 오면 ConcurrentHashMap으로 singleton bean 객체들을 관리하여 return • 결과적으로 하나의 객체가 여러 bean들에게 공유됨 • Prototype scope • BeanFactory를 통해 getBean() 요청이 오거나 inject 요청이 오면 매번 reflection을 사용하여 새로운 bean 객체를 만들어 return 52
  • 53. Singleton 빈에서 Prototype 빈 참조 (1/3) • Singleton bean에 Prototype bean을 inject하면 prototype bean은 마치 singleton scope을 가진 것처럼 동작 • Inject되는 시점에서만 prototype으로 동작하기 때문 • 매번 access할 때마다 prototype처럼 동작하도록 하려면? • IoC Container 즉, ApplicationContext에서 직접 getBean()을 호출하여 dependency를 resolve는 것이 한 방법 • 이렇게 할 경우 컨테이너에 대한 코드가 비즈니스 로직에 포함되므로 method injection을 사용하여 회피할 수 있다. • Spring은 proxyMode를 제공해서 bean이 아닌 scoped proxy bean을 inject할 수 있다. 53
  • 54. Singleton 빈에서 Prototype 빈 참조 (2/3) 54 @Component // 이 bean은 기본값 Scope인 Singleton public class SomeComponentImpl implements SomeComponent { @Autowired // Field Injection private Something something; // Leather 객체가 inject될 것임 } @Component // Spring이 관리하는 bean임을 선언 @Scope("prototype") // 이 bean은 prototype Scope public class Leather implements Something { public String getMaterial() { return getClass().getName(); } }
  • 55. Singleton 빈에서 Prototype 빈 참조 (3/3) 55 @Component // 이 bean은 기본값 Scope인 Singleton public class SomeComponentImpl implements SomeComponent { @Autowired // Field Injection private Something something; // prototype scoped proxy 객체 가 inject될 것 } @Component // Spring이 관리하는 bean임을 선언 @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value = "prototype") public class Leather implements Something { public String getMaterial() { return getClass().getName(); } } proxyMode는 기본값인 NO, CGLIB 기반의 TARGET_CLASS, Dynamic Proxy 기반의 INTERFACES 중 하나를 지정
  • 56. Custom Scope 구현 • singleton이나 prototype이 아닌 scope의 bean을 다른 bean에 inject하려고 하면 bean을 inject하는 게 아니라 AOP scoped proxy 를 inject • AOP scoped proxy 는 CGLIB 기반의 proxy • 해당 bean을 access할 때마다 CGLIB proxy 객체가 등록된 커스텀 Scope 객 체에 대해 get을 호출 • 커스텀 Scope 클래스 구현에 따라 get에 의해 객체 return • 이런 구조적 문제로 http request scope bean을 singleton bean에서 참조하려 고 하면 성능 문제가 발생할 수 있음 56
  • 57. Web Request/Session Scope 구현 • org.springframework.web.context.request.RequestScope/SessionScope 클 래스 • ThreadLocal에 requestAttributes라는 변수를 두고 같은 request인지 scope을 체크 57
  • 58. Autowire • 관련된 bean 클래스들을 자동으로 찾아 inject 해주는 기능 • 설정이 매우 간소해지며, Java annotation을 사용할 경우 configuration이 거의 필 요가 없어짐 • 적합한 bean 후보가 여럿일 경우, 임의로 선택하거나(기본값), 부가적인 @Qualifier 혹은 @Qualifier 기반의 meta annotation 등의 정보를 고려하여 선택 • wiring 방식 • byName : bean 이름으로 찾기 • byType : bean 클래스명으로 찾기 • constructor : bean의 생성자 파라미터의 클래스명으로 찾기 58
  • 59. Autowire 59 @Component public class SomeComponentImpl implements SomeComponent { @Autowired @Qualifier("leather")// Field Injection private Something something; // Leather 객체를 injection } @Component @Qualifier("leather") public class Leather implements Something { … } @Component @Qualifier("metal") public class Metal implements Something { … }
  • 60. Lazy Instantiation • Spring은 기본적으로 컨테이너 즉, ApplicationContext가 생성될 때 모든 bean 들을 eagerly initialize (생성) • 문맥에 따라 필요한 bean들은 처음 사용될 때 initialize할 수 있도록 lazy-init 옵 션을 제공 60
  • 61. Bean Lifecycle Callbacks • Spring이 bean을 생성하거나 해지하는 lifecycle 특정 시점에서 호출해주는 callback • initialize callbacks 호출 순서 • @PostConstruct 로 표시된 메소드 • InitializingBean I/F를 implement한 경우 afterPropertiesSet() 메소드 • init() : default init method 혹은 지정한 init method • destroy callbacks 호출 순서 • @PreDestroy 로 표시된 메소드 • DisposableBean I/F를 implement한 경우 destroy() 메소드 • destroy() : default destroy method 혹은 지정한 destroy method 61
  • 62. JSR 330 DI 자바 표준 62
  • 63. JSR 330 (javax.inject) • JSR 330 (javax.inject) : Dependency Injection for Java, Java EE 6 • JSR 299 (CDI) : Contexts and Dependency Injection for the Java EE, Java EE 6 • CDI(JSR 299)는 Java EE에서 Spring을 대체하는 Java EE 표준으로 추진 • JSR 330을 확장하고 있으며, Autowire 기반의 container로 Java EE 기능들의 결합 방법도 표준으로 정의 • Java DI(JSR 330)은 몇 가지 표준적인 annotation만 정의하고 wiring이나 container에 대해서는 언급하지 않음 • Google Guice 개발자와 RedHat JBoss 등에서 주도적으로 진행 • Spring, Guice 등 대부분의 Java 기반 IoC 컨테이너들이 JSR 330은 지원 • 추후 Java SE에도 포함 예상 63
  • 64. JSR 330 (javax.inject) 내용 • 다섯 개의 annotation과 한 개의 interface로 구성 • @Inject : dependency를 지정. 생성자, 메소드, 필드에 가능 • @Named : 문자열 기반의 qualifier • @Qualifier : 클래스 type 기반의 qualifier • @Scope : Scope을 정의할 수 있는 meta annotation • @Singleton : @Scope 중 유일하게 스펙에서 정의한 annotation. 공유 scope. • Provider<T> interface • T get() 메소드 하나를 정의. 일종의 factory 메소드 64
  • 65. Spring annotations vs. JSR 330 annotations Spring javax.inject.* javax.inject restrictions / comments @Autowired @Inject Spring에서는 둘 다 사용 가능 표준인 @Inject는 'required' 속성이 없음 @Component @Named Spring에서 관리하는 bean을 뜻하는 @Component는 표준인 @Named와 거의 동일하게 사용 가능 @Scope("singleton") @Singleton JSR-330은 특별하게 명시되지 않으면 Spring의 prototype scope이 기본값. Spring은 singleton이 기본값. javax.inject 도 사용자 정의 Scope을 위해 @Scope annotation을 정의 @Qualifier @Named Spring은 @Qualifier나 Generic type을 사용하여 auto wiring 시 엄밀한 제어를 할 수 있음. javax.inject도 @Named에 value 값을 지정하면 유사한 의미 65
  • 66. 66 Spring javax.inject.* javax.inject restrictions / comments @Value - Spring에서는 Bean이 아닌 primitive나 collection 등의 Value Injection이 가능함. @Required - Spring에만 있음. 컨테이너 초기 시에 반드시 initialize되어야 하는 dependency에 대 한 지정. @Lazy - Spring에만 있음. IoC 컨테이너 생성 시점이 아니라 처음 액세스될 때 initialize하는 빈 에 대한 표기
  • 68. Guice • Google Guice는 Spring이 XML 기반의 설정으로 구성된 점을 비판하며 Java 5 의 annotation과 Generics 기능을 최대한 활용하여 설정하도록 설계 • Spring과 달리 interface 기반이 아니어서 bean들은 임의의 class가 가능 • Spring이 IoC 컨테이너도 3.0 이후 Guice의 비판에 대응하여 JavaConfig를 설 계하여 포함 • Spring은 Java EE integration 측면에서 타 IoC 컨테이너에 비해 방대한 API, SPI 를 구축해놓았지만 Guice는 Java EE 지원이 없어 상대적으로 라이브러리가 가 벼움. 68
  • 69. Dagger 2 • Spring이나 Google Guice가 runtime에 object graph를 만드는 부분을 비판하며 컴파일 time(annotation processing time)에 코드 생성을 통해 validation과 object graph 생성까지 하는 아이디어 • Runtime Proxy를 사용하지 않으므로 성능이나 메모리 footprint 측면에서 유리하 여 Android와 같은 모바일 환경에서 많이 채택하는 추세 • 상대적으로 기능 구현이 어렵고 런타임 유연성은 약함 • Dagger 1은 Square라는 Financial Startup에서 만들었으며, Dagger 2는 구글에서 개발 중 • Dagger 1은 compile time validation까지 진행, Dagger 2는 object graph까지 compile time에 구성하는 게 목적 69
  • 70. Issues on IoC containers (Spring에 대한 비판들) 70
  • 71. Configuration 복잡도 • Configuration 방법 : XML, Java Configuration Code, Java Annotation, Autowiring • Spring 비판 • 설정과 코드를 오가면서 코드를 이해하는 게 어렵다. (주로 XML 설정에 대한 비판) • xml 방식과 java 방식 • Spring 3.0부터 둘 다 지원 • 기존 코드에 영향을 안 준다는 측면에서 configuration은 XML이 합리적 • bean의 특성은 코드의 일부라고 판단할 수 있으므로 annotation이 합리적 71
  • 72. 과도한 decoupling • Program to an interface, not an implementation (Design Pattern, GoF) • decoupling interface from implementation • 구현체는 대부분 하나인 경우에도 모두 interface를 별도로 선언해야 함 • Too many interfaces • Cohesive small system과 decoupling을 위한 decoupling • Spring framework은 후자를 만들게 한다. (fine granularity의 interface 유도) • Abstract class와 interface (Erich Gamma 인터뷰에서) • 자바의 interface는 메소드 추가 같은 변경이 어려워 incremental 변경에는 적 합치 않음. Abstract class에서는 구현 자식 class들 변경 없이 메소드 추가 가능. 72
  • 73. 성능 오버헤드 • Reflection + dynamic proxy, CGLIB enhancer 등 reflection을 injection 시에 과도하게 사용 • Map-like API • bean에 대해 접근할 때 ApplicationContext로부터 getBean(name) 하는 형 태로 성능에 불이익이 있음. • Bean이 많을수록 Boot-time 성능이 떨어지고, 클래스가 많아짐(interface, implementation, proxy 등)으로 인해 memory footprint 증가 • 서로 다른 scope을 가진 bean들 간의 injection 시 런타임 성능 이슈 73
  • 74. Compile-time validation 부족 • object dependency graph 검증이 컴파일 시에 충분히 되지 않으므로, 대부분 의 validation은 코드 실행 후 ApplicationContext 생성 시점에서 이루어짐 74 org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘helloController' : Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException : Could not autowire field: private hello.ConstructorBasedInjection hello.HelloController.cbInj ; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException : No qualifying bean of type [hello.ConstructorBasedInjection] found for dependency : expected at least 1 bean which qualifies as autowire candidate for this dependency.
  • 75. IoC 컨테이너 설계 시 추가 고려 사항들 • 표준 준수 여부 • JSR 330 (javax.inject), CDI (Java EE standard), Spring (de facto) • Spring API 호환 구현 가능성 • 논리적으로는 컴파일 시점에 dependency를 injection하더라도 대부분 가능 • 75
  • 77. Spring Web Request Scope 구현 방식 77
  • 78. Custom Scope 구현 • singleton이나 prototype이 아닌 scope의 bean을 다른 bean에 inject하려고 하면 bean을 inject하는 게 아니라 AOP scoped proxy 를 inject • AOP scoped proxy 는 CGLIB 기반의 proxy • 해당 bean을 access할 때마다 CGLIB proxy 객체가 등록된 커스텀 Scope 객 체에 대해 get을 호출 • 커스텀 Scope 클래스 구현에 따라 get에 의해 객체 return • 이런 구조적 문제로 http request scope bean을 singleton bean에서 참조하려 고 하면 성능 문제가 발생할 수 있음 78
  • 79. Request Scope에서 Request와 연결 • Request 발생 시 • WAS Web Container의 request event를 listen하면서 event 발생 시 thread local에 해당 event와 HttpServletRequest 객체를 사용하여 커스텀 Scope 객체를 생성 저장 • 실제 Request Scope의 Bean이 사용될 때 (Dynamic Proxy 메소드 호출) • proxy 코드에서 getBean을 호출하면 thread local의 커스텀 Scope 객체를 찾아보고 없으면 에러. • Scope 객체가 있으면 이 Scope 객체 안에서 (ConcurrentHashMap처럼 동작) bean name으로 bean을 찾고, 없으면 생성해서 저장. • 이 코드는 Request, Session, Global_Session(Portlet) 모두 공통 • Session인 경우 실제 getBean을 할 때 lock을 사용한다는 차이만 있음 (multi-thread) 79