핵심 3대 요소에 대해 알아보기 전에 먼저 POJO에 대해서 다뤄보겠습니다.
POJO(Plain Old Java Object 오래된 방식의 간단한 자바 오브젝트)는 특정 기술에 종속되지 않는 순수한 자바 객체를 의미합니다. 예를 들어, 특정 기술을 사용하기 위해 특정 프레임워크를 의존하게 되면 그것은 POJO라고 할 수 없습니다. 특정 기술에 종속되어 있기 때문입니다.
public class UserDTO {
private String userName;
private String userId;
private String userPassword;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
}
POJO는 DTO와 같이 기본적인 자바의 기능인 getter, setter 기능만 가지고 있습니다. 특정 기술에 종속되어 있지 않은 순수 자바 객체이기 때문에 위 객체는 POJO라고 할 수 있습니다.
public class Sample extends WindowAdapter {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
Window의 기능을 사용하기 위해 WindowAdapter 클래스를 상속받았기 때문에 POJO라고 할 수 없습니다. 이렇게 되면 다른 솔루션을 사용하고자 할 때 많은 양의 코드를 리팩토링해야 하는 문제가 있습니다.
이처럼 특정 기술과 환경에 종속되어 의존하게 되면, 코드 가독성 뿐만 아니라 유지보수, 확장성에도 어려움이 생깁니다. 이러한 객체지향의 장점을 잃어버린 자바를 되살리기 위해 POJO라는 개념이 등장한 것입니다.
진정한 POJO란 객체지향적인 원리에 충실하면서, 환경과 기술에 종속되지 않고 필요에 따라 재활용될 수 있는 방식으로 설계된 오브젝트이다.
- 토비의 스프링 -
조건
장점
AOP(Aspect Oriented Programming 관점 지향 프로그래밍)는 여러 객체에 공통으로 적용할 수 있는 기능을 구분함으로써 재사용을 높여주는 프로그래밍 기법입니다. AOP는 핵심 기능과 공통 기능의 구현을 분리함으로써 핵심 기능을 구현한 코드의 수정 없이 공통 기능을 적용할 수 있게 만들어줍니다.
PSA(Portable Service Abstraction 서비스 추상화)는 환경의 변화와 관계없이 일관된 방식의 기술로의 접근 환경을 제공하는 추상화 구조를 말합니다. 이는 POJO 원칙을 철저히 따른 Spring의 기능으로 Spring에서 동작할 수 있는 Library들은 POJO 원칙을 지키도록 PSA 형태의 추상화가 되어있음을 의미합니다.
잘 만든 인터페이스 하나가 열 클래스 부럽지 않다. PSA를 '잘 만든 인터페이스'라고도 합니다. PSA가 적용된 코드는 나의 코드가 바뀌지 않고, 다른 기술로 간편하게 바꿀 수 있도록 확장성이 좋고 기술에 특화되어 있지 않는 코드를 의미합니다.
● Spring Web MVC
● @Component
● @Controller
● @Repository
● @Service
● @RequestMapping
● ...
● Spring Transaction
● JDBC
● JPA
● Spring Cache
● Cacheable
● CacheEvict
● ...
IoC(Inversion of Control 제어의 역전)는 Spring뿐만 아니라 모든 프로그래밍에서 사용될 수 있는 범용적인 개념입니다. 쉽게 말해 객체의 제어권이 개발자 본인이 아닌 Spring 컨테이너에게 넘어가는 것입니다.
class ClassA {
}
class ClassB{
private ClassA a;
ClassB() {
this.a = new ClassA();
}
}
위의 코드는 일반적으로 자바에서 객체를 생성하여 객체를 제어하는 코드입니다.
@Component
class ClassA {
}
class ClassB{
@Autowired
private ClassA a;
}
Spring에서의 객체 할당 방식입니다.
Spring의 경우 Bean(Spring에 의해 관리되는 객체)이라면 @Autowired 어노테이션을 통해 손쉽게 객체를 할당할 수 있습니다.
이는 개발자 본인이 객체를 관리하는 것이 아닌 Spring 컨테이너에서 객체를 생성하고 해당 객체를 할당 시켜준 것입니다.
이처럼 객체의 흐름, 생명주기 관리 등을 외부(제3자)에서 처리하는 방식의 모델을 제어의 역전(IoC)라고 합니다.
제어의 역전 개념을 이용하면 프레임워크와 라이브러리의 구분 또한 가능합니다. 프레임워크가 내가 작성한 코드를 제어하고, 대신 실행하면 그것은 프레임워크가 맞습니다.(JUnit)
반면에, 내가 작성한 코드가 직접 제어의 흐름을 담당한다면 그것은 프레임워크가 아니라 라이브러리입니다.
DI(Dependency Injection 의존성 주입)는 객체를 외부로부터 할당받고 이를 통해 객체를 동적으로 할당하는 방식입니다. 사용할 객체들을 컨테이너에 등록한 후 애플리케이션 코드에서 해당 객체를 setter 함수의 매개변수로 받아와서 실행 시 동적으로 의존관계를 설정해 줍니다.
Spring에서는 두 번째 방식인 setter 메소드를 이용한 의존성 주입을 지지합니다. 외부에서 제공받은 객체를 저장해뒀다가 내부의 메소드에서 사용하도록 하는 DI 방식에서 활용하기 좋기 때문입니다.
이 IoC와 DI 덕분에 캡슐화를 통한 높은 응집도와, 객체 간의 낮은 결합도를 이루고 유연한 코드를 작성할 수 있도록 해주며, 개발자들이 개발에 더욱 집중할 수 있도록 해줍니다.