POJO (Plain Old Java Object)
”오래된 방식의 간단한 자바 객체”
- Getter, Setter와 같은 기본 기능만을 갖는 기본 객체를 의미.
- 특정 기술에 종속되어 있는 상태로 개발하지 않는 개념을 위해 등장한 언어.
- 종속성으로 인해 시스템 업그레이드, 모듈 교체와 같은 상황에서 많은 불편함이 있었기에 POJO라는 개념이 등장함.
(여기서 특정 기술이라함은 framework를 의미)
Spring은 POJO 개념을 잘 지킨 프레임워크이다.
- IoC, DI, AOP와 같은 개념들이 모두 결합력을 느슨하게 하여 의존성을 낮춤으로써 종속성이 낮아지는 현상이 발생.
- POJO에 가까운 개발이 가능하다!!
- 특정 기술들이 종속성을 가지게 되면, 객체지향적인 설계가 힘들거나 불가능한 경우가 발생. 그렇다보니 코드의 유지보수와 재사용이 매우 불편해짐.
Hibernate도 POJO 개념을 잘 지킨 프레임워크이다!
Hibernate는 자바 객체의 순수성을 해치지 않으면서도 DB 매핑을 자동으로 처리해주는, POJO 친화적 ORM 프레임워크.
Hibernate는 매핑할 엔티티 클래스를 아래와 같이 순수한 POJO로 유지할 수 있도록 설계되어 있음.
@Entity public class User { @Id private Long id; private String name; private int age; // 기본 생성자, getter, setter }
위의 코드는 다음과 같은 집에서 POJO의 개념을 지킴.
- 어떤 ORM 전용 클래스도 상속하지 않음.
- 어떤 특수한 인터페이스도 구현하지 않음.
- 필드와 메서드는 일반적인 자바 객체 방식으로 정의
- 필요한 것은 @Enitity, @Id 같은 JPA 표준 애노테이션뿐.
즉, Hibernate는 엔티티 클래스를 특정 기술에 종속시키지 않고 자바 객체 그대로 사용할 수 있게 해줌. → Hibernate가 POJO 친화적인 이유
POJO를 지킨 코드
public class POJOClass { private String name; private int age; public String getName() { return name; } public String setName(String name) { this.name = name; } public int getAge() { return age; } public int setAge(int age) { this.age = age; } }
- 단순한 Getter, Setter로 POJO의 개념을 매우 잘 지킨 것을 확인할 수 있음.
POJO를 지키지 않은 코드
public class POJOClass extends UserService { private String name; private int age; @Override public List<User> findUsers() { return super.findUsers(); } }
- UserService의 기능을 사용하기 위해 extends를 받았다.
- 이렇게 되면 UserService의 메서드를 사용하기 위해 많은 양의 코드 리팩토링은 물론 코드의 가독성 및 유지보수 확장 측면에서 어려움이 생길 수 있음.
Spring의 POJO 개념을 지킨 코드
public class POJOClass { @Autowired UserRepository userRepository; private String name; private int age; public void test() { userRepository.findAll(); } }
- @Autowired를 활용하여 의존성 주입
- 느슨한 결합력을 갖게 되면서 직접적으로 extends, implements를 하지 않아도 해당 클래스의 메서드에 접근이 가능해짐.
- extends를 하여 직접 메서드를 override하여 작성하지 않아도 되면서 userRepository 코드에 변경이 생겨도 같이 변하는 장점이 있다.
POJO 조건
객체지향적인 설계를 하였는가?
특정 기술에 종속되어 있지 않은가?
특정 환경에 종속되어 있지 않은가?
테스트가 간편하고 용이한가?
비즈니스 로직에 단순 자바 오브젝트가 아닌 HttpSession과 같은 특정 기술이나 특정 환경에 종속적이지 않고 객체지향 설계가 적용되어야 POJO라고 할 수 있음.
애노테이션을 사용하는 경우, 부가적인 정보를 담고 있고 그 때문에 특정 환경에 종속적이지 않다면 POJO라 할 수 있음.
하지만, 애노테이션이나 엘리먼트에 특정 기술과 환경에 종속적인 정보를 담고 있으면 POJO가 아님.
POJO의 장점
- POJO의 조건인 특정 기술과 환경에 종속적이지 않는 코드는 깔끔한 코드가 될 수 있음.
- 특정 기술 및 환경의 제약은 테스트 코드 작성이 힘들기 때문에 POJO로 개발된 코드는 자동화된 테스트에 매우 유리함.
- POJO의 코드는 매우 유연한 방식으로 원하는 레벨에서 코드를 빠르고 명확하게 테스트할 수 있음.
- POJO는 객체지향적인 설계를 자유롭게 적용할 수 있음.
- 재활용 가능한 설계 모델인 디자인 패턴 등은 POJO가 아니고 적용하기 힘듦.
그렇다면, 이제 대략적으로 POJO가 무엇인지 살펴봤으니 이를 구성하고있는 각각에 대하여 더 자세하게 알아보도록 하자.
AOP란?
- AOP(Aspect Oriented Programming, 관점 지향 프로그래밍)
- 프로그래밍을 할 때 핵심 관점과 부가 관점을 나눠서 개발하는 것
- 프로그래밍에 대한 관심을 핵심 관점, 부가 관점으로 나눠
관심 기준으로 모듈화하는 것
을 의미한다.
예시 - 계좌 이체, 고객 관리하는 프로그램
- 각 프로그램에는 로깅 로직, 즉 지금까지 벌어진 일을 기록하기 위한 로직 + 여러 데이터를 관리하기 위한 db 연결 로직이 포함됨.
- 여러 기능중에서도 관점을 나눌 수 있음.
- 핵심 관점: 소프트웨어 시스템의 주요 기능이나 핵심 비즈니스 로직과 관련된 것. ⇒ 계좌 이체, 고객 관리 로직
- 부가 관점: 핵심 관점 이외의 기능이나 시스템 전반에 걸쳐 중복되거나 공통적으로 발생하는 것. ⇒ 로깅, db 연결 로직
- 로깅, db 연결은 모두 계좌 이체와 고객 관리에 필요한데, 여기에 AOP를 적용하면 부가 관점에 해당하는 로직을 모듈화해서 개발이 가능하다.
부가 관점 코드를 핵심 관점 코드에서 분리
할 수 있게 해준다.- 이때문에 개발자는 핵심 관점 코드에만 집중할 수 있게 될 뿐만 아니라 프로그램의 변경과 확장에도 유연하게 대응이 가능하다.
IOC란?
- IoC(Inversion of Control, 제어의 역전)
- 객체의 생성과 관리를 개발자가 하는 것이 아니라 프레임워크가 대신하는 것
- 다른 객체를 직접 생성하거나 제어하는 것이 아니라, 외부에서 관리하는 객체를 가져와 사용하는 것.
// 클래스 A에서 클래스 B 객체 생성 예
public class A {
b = new B();
}
위의 코드에 제어의 역전을 적용하면? 아래와 같이 된다.
// 스프링 컨테이너가 객체를 관리하는 방식 예
public class A {
private B b;
}
- 클래스 B객체를 직접 생성하는 것이 아니므로, 어딘가에서 받아와서 사용하고 있다고 추측가능.
- 이처럼 제어의 역전을 적용하면 객체를 외부에서 관리하게 되고, 실제로 사용할 때는 외부에서 제공해주는 객체를 받아오게 됨. 스프링에서 제어의 역전 개념은 중요하며, 객체를 관리하고 관리하는 주체를 스프링 컨테이너라고 함.
DI란?
- DI(Dependency Injection, 의존성 주입)
- 외부에서 객체를 주입받아 사용하는 것
- 스프리에서는 객체들을 관리하기 위해 제어의 역전을 사용함.
- 이때, 제어의 역전을 구현하기 위해 사용하는 방법이 DI!!!
- DI는 어떤 클래스가 다른 클래스에 의존한다는 뜻임.
// 객체를 주입받는 모습 예시
public class A {
// A에서 B를 주입받음
@Autowired
B b;
}
- 이때, @Autowired라는 애노테이션은 스프링 컨테이너에 있는 빈이라는 것을 주입하는 역할.
- 빈이란? 스프링 컨테이너에서 관리하는 객체
- 이전에는 직접 B객체를 생성했지만, 위의 코드에서는 B b;라고 선언만 했을 뿐 직접 개체는 생성하고 있지는 않다. 즉, 객체를 주입받고 있다.
- 스프링 컨테이너라는 곳에서 객체를 주입했기 때문에 프로그램은 잘 동작하게 된다. 즉, 스프링 컨테이너가 B 객체를 만들어서 클래스 A에 준 것이다.
PSA란?
- PSA(Portable Service Abstraction, 이식 가능한 서비스 추상화)
- 어느 기술을 사용하던 일관된 방식으로 처리하도록 하는 것
- 스프링에서 제공하는 다양한 기술들을 추상화해 개발자가 쉽게 사용하는 인터페이스.
예시
- 스프링에서 db에 접근하기 위한 기술로는 JPA, MyBatis, JDBC 같은 것들이 있음.
- 여기에서 어떤 기술을 사용하든 일관된 방식으로 db에 접근하도록 인터페이스를 지원함.
- WAS도 PSA의 하나인데, 코드는 그대로 두고 WAS를 톰캣이 아닌 언더토우나 Netty와 같은 다른 곳에서 실행해도 기존 코드를 그대로 사용가능하기 때문.
빈과 스프링 컨테이너
- 스프링은 스프링 컨테이너를 제공한다.
- 스프링 컨테이너는 빈을 생성하고 관리한다.
- 즉, 빈이 생성되고 소멸되기까지의
생명주기를 스프링 컨테이너가 관리
한다. - @Autowired 같은 애노테이션을 사용해 빈을 주입받을 수 있게 DI를 지원하기도 한다.
여기서 빈이란?
- 스프링 컨테이너가 생성하고 관리하는 객체
// 객체를 주입받는 모습 예시
public class A {
// A에서 B를 주입받음
@Autowired
B b;
}
- 위의 코드에서 @Autowired로 주입받은 B 객체가 바로 빈이다.
- 스프링은 빈을 스프링 컨테이너에 등록하기 위해 XML 파일에서 설정하거나, 애노테이션으로 등록하는 등의 여러 방법을 제공한다.
// 클래스를 빈으로 등록하는 방법 예시
@Component
public class MyBean {
}
- 여기서는 @Component 애노테이션을 붙였기에 MyBean 클래스가 빈으로 등록된다.
- 이후에는 스프링 컨테이너에서 이 클래스를 관리하게된다.
- 이때 빈의 이름은 클래스 이름의 첫 글자를 소문자로 바꿔 관리한다. (myBean)
참고자료
'공부' 카테고리의 다른 글
[Spring] 순환참조문제 (0) | 2025.04.04 |
---|---|
[Spring] spring의 의존성 주입 방법 4가지 (0) | 2025.04.04 |
[DDD] Aggregate란? (0) | 2025.04.01 |
[JPA] JPA의 N + 1 문제 정리 (0) | 2025.03.27 |
[JPA] FetchType 정리 (0) | 2025.03.27 |