프레임워크는 애플리케이션을 효율적으로 개발하기 위해 설계된 표준화된 뼈대이다. 라이브러리와 달리 제어의 역전(IoC)이 일어나서, 프레임워크가 애플리케이션의 흐름을 제어하거나 라이프사이클을 관리하기도 한다.
사용자는 프레임워크가 제공하는 기반 코드를 이용해 높은 품질의 코드를 빠른 시간 내에 완성 및 유지 보수할 수 있다.
라이브러리는 프로그램 기능 구현에만 도움을 줄 수 있다. 하지만 프레임 워크는 기능과 전체 구조를 함께 제공한다. 프레임워크라는 큰 틀 안에서 코드가 동작하고 프레임워크에 의해 애플리케이션 흐름이 제어되기도 한다. 반면 라이브러리는 필요한 기능을 구현할 때만 호출하여 손쉽게 개발하고자할 때 사용한다.
엔터프라이즈용 자바 애플리케이션 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크다. Spring의 핵심은 POJO(Plain Old Java Object), 즉 순수한 자바 객체를 사용하여 복잡한 비즈니스 로직을 구현할 수 있게 돕는 것이다.
POJO (Plain Old Java Object)란 순수 자바만을 통해서 생성한 객체를 의미한다. 즉 자바 및 자바 스펙에 정의된 기술만을 사용한다는 의미이다. 어떤 객체가 외부의 라이브러리나 외부의 모듈을 가져와서 쓰는 것이 아니라 순수한 자바만을 사용해 만든 객체이다.
만약 외부 라이브러리를 import해 메서드를 사용하고 있는 객체가 있다면 해당 라이브러리가 Deprecated될때 해당 라이브러리를 사용하고 있는 모든 객체의 코드를 수정해야한다.
반면 POJO는 순수 자바 객체만을 사용하기 때문에 특정 기술 및 환경에 종속되지 않는다. 따라서 외부 규약이나 변화에 얽매이지 않아서 보다 유연하게 변화와 확장에 대처할 수 있다.
단순히 외부 라이브러리를 사용한다고 해서 POJO가 깨지는 것은 아니다. POJO 여부를 판단하는 핵심은 그 객체가 특정 기술 환경에 얼마나 강하게 결속(Coupling)되어 있는가에 있다.
// POJO - 라이브러리를 사용하지만 POJO임
@Entity
@Getter @Setter // Lombok
public class User {
@Id
private Long id;
private String name;
}
// Non-POJO - 프레임워크에 종속됨
public class UserBean implements EntityBean {
// EJB 인터페이스 구현 강제
public void ejbActivate() { ... }
public void ejbPassivate() { ... }
}
객체가 특정 프레임워크의 클래스를 상속하거나 인터페이스를 구현해야만 동작한다면, 그건 POJO가 아니다.
Hibernate나 Spring처럼 비침투적(Non-invasive)인 프레임워크를 사용할 때는 POJO가 유지된다고 볼 수 있다.
Hibernate는 POJO 기반의 프로그래밍을 가능하게 해주는 ORM 이라고 할 수 있다. 과거 EJB(Enterprise JavaBeans, 스프링 이전 자바 프레임워크 표준) 시절에는 데이터베이스에 저장하기 위해 특정 인터페이스를 상속받거나 프레임워크에 종속된 코드를 강제로 작성해야 했다.
반면, Hibernate는 "특정 기술에 오염되지 않은 순수한 자바 객체(POJO)"를 그대로 DB 테이블과 매핑하는 것을 목표로 탄생했다.
Hibernate를 사용하면 특정 클래스를 상속받거나 인터페이스를 구현하지 않아도 된다. JPA 어노테이션을 사용하지만 이는 메타 데이터일 뿐 클래스의 본질적인 구조를 바꾸지 않는다.
따라서 Hibernate는 POJO 지향적이라고 할 수 있다.
스프링은 POJO를 위해 3가지 기술을 지원한다.
제어의 역전 이라는 의미로, 애플리케이션 흐름을 개발자가 아닌 스프링이 대신 제어한다는 뜻이다. 즉, 객체의 생성 및 의존성 설정을 개발자가 직접하지 않고 프레임워크가 대신해준다는 것이다.
스프링에서는 객체의 생성부터 생명주기를 스프링 컨테이너가 관리한다. 제어권이 넘어갔다 하여 제어의 역전이라고 하는데, 그런 의미에서 스프링 컨테이너를 IoC 컨테이너라고도 한다.
스프링에서의 IoC는 다음과 같은 절차로 이뤄진다.
1. 객체 생성
2. 의존성 주입 (객체를 스스로 만들지 않고 스프링이 만들어놓은 객체를 외부에서 주입)
3. 의존성 객체의 메서드 호출
이렇게 생성된 객체는 스프링에서 Bean이라고 하며, 스프링이 실행될때 생성하여 필요한 곳에 주입한다. 이 Bean들은 스프링 컨테이너에서 싱글톤으로 관리한다. IoC를 통해 객체끼리 느슨하게 결합될 수 있고, 유연한 코드를 작성할 수 있게 되었다.
의존성 주입이라는 의미로, 객체를 직접 생성하는 것이 아니라 외부에서 생성 후 주입 시켜주는 방법을 말한다.
DI방식을 사용하게 되면 개방 폐쇄 원칙(OCP)의 이점과 같은 이점을 얻을 수 있다. 코드 재사용을 높여 소스코드를 다양한 곳에 사용할 수 있으며 모듈간의 결합도도 낮출 수 있다.
DI 방식에는 3가지가 있다. 생성자 주입, Setter주입, 필드 주입 이렇게 3가지이다.
1. Setter Injection(setter메서드 주입)
// setter 메서드를 통한 의존 주입
public class MemberService {
private MemberRepository memberRepository;
@Autowired // 없어도 됨
public void setMemberRepository(MemberRepository memberRepository){
this.memberRepository = memberRepository;
}
}
2. Field Injection(필드 주입)
// 필드에 애노테이션을 붙여 의존 주입
public class MemberService {
@Autowired
private MemberRepository memberRepository;
}
3. Contructor Injection(생성자 주입)🌟
// 생성자를 통한 의존 주입
@RequiredArgsConstructor //final이 붙은 필드에 생성자를 만들어줌, 이 애노테이션만 붙여도 의존 주입이 가능함
public class MemberService {
private final MemberRepository memberRepository;
// RequiredArgsConstructor 애노테이션을 붙이면 주석처럼 생성자를 만들지 않아도 됨
//@Autowired 생성자가 하나 있을 때 스프링이 알아서 등록을 해줌
/*public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}*/
}
Spring을 포함한 DI 프레임워크에서는 생정자 주입을 권장하고 있다. 객체의 불변성을 확보할 수 있으며, 테스트가 편리하고, final키워드와 Lombok을 활용해서 간결하게 작성이 가능하고, 순환 참조 에러를 방지할 수 있다.
AOP는 여러 객체에 공통으로 적용할 수 있는 기능을 구분함으로써 재사용성을 높여주는 프로그래밍 기법이다.
애플리케이션 전반에 걸쳐 공통적으로 사용하는 기능을 공통 관심 사항이라고 한다. 또한 애플리케이션의 목적 달성을 위한 핵심 로직에 대한 관심사를 핵심 관심 사항이라고 한다.
예를 들어 커피 주문 애플리케이션이 있다고 할 때 커피 메뉴 등록, 커피 주문, 커피 주문 변경 등등 기능들이 핵심 관심 사항이고, 공통적으로 처리해야 할 부분인 로깅, 보안, 트랜잭션 같은 경우를 공통 관심 사항이라 할 수 있다. AOP를 이용하면 이런 공통 로직을 따로 분리하여 코드 중복을 없애면서도 간결하게 구현할 수 있다.
AOP 사용시 이점은 다음과 같다.
PSA는 특정 기술과 관련된 서비스를 추상화하여 일관된 방식으로 사용할 수 있도록 한것이다.
예를 들어 데이터베이스를 MySQL에서 PostgreSQL로 바꿔야한다고 해보자. DB마다 사용방법이 다르다면 작성한 코드를 전부 지우고 새로 작성하거나 수정해야할 수도 있다. 이때 스프링을 사용하면 동일한 사용방법을 유지한 채 데이터베이스를 바꿀 수 있다.

스프링은 JDBC(Java Database Connectivity)라고 불리는 데이터베이스 서비스를 추상화한 인터페이스를 제공해준다. 각 데이터베이스 회사들은 자신의 데이터베이스에 접근하는 드라이버를 Java 코드 형태로 배포하는데 이 드라이버에 해당하는 Java 코드 클래스가 JDBC를 구현한다. 따라서 JDBC기반으로 데이터베이스 접근코드를 작성해두면 이후에 데이터베이스를 바꾸어도 기존에 작성한 데이터베이스 접근 로직을 그대로 사용할 수 있다. 이렇게 JDBC처럼 특정한 기술을 추상화하여 일관된 서비스를 사용할 수 있도록 하는 것을 PSA라고 한다.
스프링 부트는 스프링으로 애플리케이션을 만들 때에 필요한 설정을 간편하게 처리해주는 별도의 프레임워크이다.
스프링 부트를 사용하면 다음의 이점을 누릴 수 있다.
.jar 파일로 빌드할 수 있어 클라우드 서비스 및 도커와 같은 가상화 환경에 빠르게 배포할 수 있다.프레임워크는 애플리케이션을 효율적으로 개발하기 위해 설계된 준화된 뼈대이다. 라이브러리와는 달리 제어의 역전이 일어나 애플리케이션의 흐름을 제어하기도 하고 라이프 사이클을 관리하기도한다. 프레임워크를 사용하면 구조화된 틀 안에서 코드를 작성하게 되어 효율적이고 유지보수성이 높아진다. 스프링은 자바 애플리케이션을 개발할 수 있는 프레임워크다. POJO라 불리는 순수 자바 객체를 사용하여 복잡한 비즈니스 로직을 구현할 수 있게 돕는다. 이를 위해 스프링이 제공하는 핵심 기술 3가지가 있다. 첫번째는 IoC/DI로 객체의 생성과 관리를 개발자가 아닌 Spring 컨테이너가 담당한다. 직접 new로 생성하지 않고 Spring이 자동으로 주입해준다. 이렇게 하면 결합도가 낮아지고 테스트가 쉬워진다. 두번째는 AOP이다. 로깅, 트랜잭션 관리 같은 공통 관심사를 비즈니스 로직에서 분리하여 코드의 간결성을 유지하고 재사용성을 높여준다. 예를 들어 @Transactional 어노테이션 하나로 트랜잭션 처리를 자동화할 수 있다. 마지막으로 PSA이다. 일관화된 서비스 추상화라는 뜻으로 특정 기술에 종속되지 않도록 추상화 계층을 제공한다. 예를 들어 스프링에서는 JDBC라는 데이터베이스를 추상화한 인터페이스를 제공한다. 따라서 JDBC기반으로 코드를 작성해두면 데이터베이스를 나중에 변경해도 기존 로직을 수정하지 않아도 된다. 특정 기술을 추상화하여 일관된 서비스 사용하도록 하는 것이 PSA이다.