POJO(Plain Old Java Object)
: 오래된 방식의 순수한 자바 오브젝트 (자바 언어 사양 외에 어떠한 제한에도 묶이지 않은 자바 오브젝트)
객체 지향적인 원리에 충실하면서 환경과 기술에 종속되지 않고 필요에 따라 재활용될 수 있는 방식으로 설계된 오브젝트
- POJO 규칙
1. 특정 규약에 종속되지 않는다.
- 자바와 꼭 필요한 API외에는 종속되지 않아야 한다. => 특정 기술을 사용하기 위해서 대부분 제시하는 특정 클래스를 상속하도록 요구한다. 그러나 자바의 경우 단일 상속 제한이 있기 때문에 해당 클래스는 객체 지향적인 설계 기법을 적용하기 어려워지는 문제가 발생한다.
2. 특정 환경에 종속적이지 않는다.
- 환경에 독립적이어야 하며 POJO 클래스는 웹이라는 환경 정보나 웹 기술을 담고 있는 클래스나 인터페이스를 사용해서는 안 된다.
3. 객체 지향적 원리에 충실해야 한다.
- 객체 지향적 원리 : 상속, 캡슐화, 다형성, 추상화
- 상속과 다형성을 적용한 클래스가 아닌 조건문으로 가득 찬 클래스의 오브젝트는 POJO라고 부르기 힘들다.
POJO의 장점
- 간결하게 깔끔한 코드
- 간편하게 테스트 (디버깅 쉬움, 환경 종속적 X )
- 객체지향적인 설계 자유롭게 가능
[참조]
https://velog.io/@hiy7030/Spring-Spring%EC%9D%98-%ED%8A%B9%EC%A7%95-POJO
PSA(Portable Service Abstraction)
PSA란 환경의 변화와 관계없이 일관된 방식의 기술로의 접근 환경을 제공하는 추상화 구조를 말합니다.
이는 POJO 원칙을 철저히 따른 Spring의 기능으로 Spring에서 동작할 수 있는Library들은
POJO원칙을 지키게끔 PSA형태의 추상화가 되어있음을 의미합니다.
"잘 만든 인터페이스 하나가 열 클래스 부럽지 않다"
PSA = 잘 만든 인터페이스
Spring은 Spring Web MVC, Spring Transaction, Spring Cache 등의 다양한 PSA를 제공합니다.
[참조]
https://dev-coco.tistory.com/83
AOP ( Aspect Oriented Programming, 관점 지향 프로그래밍)
흩어진 Aspect를 모듈화할 수 있는 프로그래밍 기법

위의 A, B, C 클래스에서 동일한 색깔의 선들의 의미는 클래스들에 나타나는 비슷한(중복되는) 메소드, 필드, 코드들이 나타난다는 것입니다. 이러한 경우 만약 클래스 A에 주황색 부분을 수정해야 한다면 B, C 클래스들에 주황색 부분에 해당하는 곳을 찾아가 전부 코드를 수정해야 합니다. (SOLID 원칙도 위배하며 유지보수도 쉽지 않을 것입니다.) 이런식으로 반복되는 코드를 흩어진 관심사 (Crosscutting Concerns)라 부릅니다.
이렇게 흩어진 관심사를 AOP는 Aspect를 이용해서 해결합니다. 위의 사진의 아래쪽을 보면 흩어져 있는 부분들을 Aspect를 이용해서 모듈화 시킨 것을 볼 수 있습니다. (모듈화란 어떤 공통된 로직이나 기능을 하나의 단위로 묶는 것을 말합니다.) 그리고 개발자가 모듈화 시킨 Aspect를 사진에서 위에 클래스에 어느 곳에 사용해야 하는지만 정의해주면 됩니다.
결론적으로 Aspect로 모듈화하고 핵심적인 비즈니스 로직에서 분리하여 재사용하겠다는 것이 AOP의 취지다.
[참조]
https://devlog-wjdrbs96.tistory.com/398
Spring AOP란?

스프링도 위에서 본 프록시를 이용해서 AOP를 구현하고 있습니다. AOP의 핵심 기능은 코드를 수정하지 않으면서 공통 기능의 구현을 추가하는 것이라고 강조하고 있습니다. 핵심 기능에 공통 기능을 추가하는 방법에는 아래와 같이 3가지 방법이 존재합니다.
- 컴파일 : 자바 파일을 클래스 파일로 만들 때 바이트코드를 조작하여 적용된 바이트코드를 생성
- 로드 타임 : 컴파일은 원래 클래스 그대로 하고, 클래스를 로딩하는 시점에 끼워서 넣는다.
- 런타임 : A라는 클래스를 빈으로 만들 때 A라는 타입의 프록시 빈을 감싸서 만든 후에, 프록시 빈이 클래스 중간에 코드를 추가해서 넣는다.
스프링에서 많이 사용하는 방식은 프록시를 이용한 세 번째 방법입니다. 스프링 AOP는 프록시 객체를 자동으로 만들어줍니다. 따라서 위에서 본 ProxySimpleEventService 클래스 처럼 상위 타입의 인터페이스를 상속 받은 클래스를 직접 구현할 필요가 없습니다. 단지 공통 기능을 구현한 클래스만 잘 구현하면 됩니다.
IoC /DI (Inversion of control / Dependency Injection)

IoC (Inversion of Control)란?
IoC는 말 그대로 제어의 역전을 의미하며, 전통적인 프로그래밍에서는 개발자가 프로그램의 흐름과 제어를 직접 다루는 반면, IoC는 프레임워크가 객체의 생성, 관리, 제어 흐름을 담당하도록 변경하는 개념이다. Spring은 이를 지원하기 위해 ApplicationContext라는 컨테이너를 제공한다.
ApplicationContext는 애플리케이션의 컴포넌트를 생성하고 조립하며, 객체의 라이프사이클을 관리한다.
과정
1. 객체의 생성 및 관리:
- ApplicationContext를 사용하여 빈(Bean)을 생성하고, 관리한다.
- 빈은 일반적으로 Spring이 제어하며, 개발자는 객체의 생성과 관리를 직접 처리하지 않는다.
2. 의존성 관리:
- 객체 간의 의존성을 Spring이 주입(DI)한다.
- 객체가 필요로 하는 다른 객체를 직접 생성하거나 찾는 대신, Spring 컨테이너가 의존성을 주입해주다.
3. 제어 흐름의 역전:
- 개발자가 코드의 제어 흐름을 결정하지 않고, 프레임워크가 객체의 라이프사이클 및 실행 흐름을 관리한다.
DI (Dependency Injection)란?
DI는 객체 간의 의존성을 프레임워크가 주입하는 개념이다. 객체가 직접 의존하는 객체를 생성하거나 참조하는 대신, 이러한 의존성을 외부에서 주입받도록 한다. Spring은 다양한 방법으로 DI를 지원한다.
DI를 사용하지 않은 경우
public class UserService {
private UserRepository userRepository;
public UserService() {
this.userRepository = new UserRepository(); // 직접 생성
}
// ...
}
위의 코드에서는 'UserService'는 직접적으로 'UserRepository'를 생성하고 의존하고 있다. 이로 인해서 'UserService'와 'UserRepository' 간에 강한 결합이 형성되어 있다. 이런 경우 유지 보수성이 떨어지며, 코드 변경 시 여러 클랠스에 영향을 줄 수 있다.
DI를 사용한 경우
- 1. Constructor Injection: 생성자를 통해 의존성을 주입하는 방식이다. 클래스의 생성자를 정의하고, 의존하는 객체를 매개변수로 받아 필드에 할당한다.
public class UserService {
private UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// ...
}
- 2. Setter Injection: Setter 메서드를 통해 의존성을 주입하는 방식이다. Setter 메서드를 정의하고, 해당 메서드를 통해 의존하는 객체를 주입한다.
public class OrderService {
private PaymentGateway paymentGateway;
@Autowired
public void setPaymentGateway(PaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
// ...
}
- 3. Field Injection: 필드에 직접 의존성을 주입하는 방식이다. 주로 '@Autowired' 어노테이션을 사용하여 필드에 의존성을 주입한다.
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
// ...
}
- 4. Method Injection: 메서드의 매개변수로 의존성을 주입하는 방식이다.
@Component
public class ReportGenerator {
private EmailService emailService;
@Autowired
public void setEmailService(EmailService emailService) {
this.emailService = emailService;
}
public void generateReport() {
// Use the emailService here...
}
}
- 5. @Qualifier 어노테이션 사용 (빈의 특정 구현체 주입): 같은 타입의 여러 빈 중에서 어떤 빈을 주입할지 선택할 때 사용
public class OrderService {
private PaymentGateway paymentGateway;
@Autowired
public OrderService(@Qualifier("creditCardGateway") PaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
// ...
}
- 6. XML 설정을 통한 의존성 주입: XML 파일을 사용하여 의존성 주입을 정의할 수 있다.
<bean id="userService" class="com.example.UserService">
<constructor-arg ref="userRepository" />
</bean>
<bean id="userRepository" class="com.example.UserRepository" />
- 7. Java Config: Java 설정 클래스를 사용하여 의존성 주입을 정의할 수 있다.
@Configuration
public class AppConfig {
@Bean
public UserService userService(UserRepository userRepository) {
return new UserService(userRepository);
}
@Bean
public UserRepository userRepository() {
return new UserRepository();
}
}'개발일기' 카테고리의 다른 글
| Http Request Method (0) | 2024.05.17 |
|---|---|
| 기술부채 (0) | 2024.05.16 |
| 컬렉션 프레임워크(collections framework) (0) | 2024.05.13 |
| Dangling meta character '+' near index 0+ (0) | 2024.05.10 |
| DevOps란 무엇입니까? (0) | 2024.05.07 |