1. 스프링 의존성 주입방법 총 3가지
생성자 주입(Constructor Injection) , 수정자 주입(Setter 주입, Setter Injection), 필드 주입(Field Injection)
- 생성자 주입은 생성자를 통해 의존관계를 주입하는 방법으로 생성자의 호출 시점에 호출됨
- 생성자 호출 시점에 1번만 호출된다.
- final 을 사용할 수 있어서 불변객체임이 보장된다.
- 순환참조를 방지한다. (순환참조일 경우 앱구동시 에러)
- 테스트 코드 작성이 용이하다.
* 수정자 주입
- setter 를 사용하여 의존관계를 주입하는 것으로 의존관계 주입은 한 번 일어나면 애플리케이션 종료시점까지 변경되는 일이 거의 없지만, 수정자 주입은 변경될 위험이 있다.
* 필드 주입
- @Autowired 를 통해 주입하는 방식으로 간단하여 많이 사용되는 방법이다.
- 테스트시 불편함이 있다.
2. 불변객체란?
객체 지향 프로그래밍에 있어서 불변객체(immutable object)는 생성 후 그 상태를 바꿀 수 없는 객체를 말한다. 그렇기 때문에 한 번 생성이 되면 신뢰할 수 있는 객체가 된다.
자바에서의 대표적인 불변객체는 String, Boolean , BigDecimal 등이 있다.
* 불변객체 생성 방법
- setter를 사용하지 않는다. (객체의 상태를 변경하는 메소드를 미제공한다. )
- private 으로 선언한다.
- final을 선언한다.
* 왜 불변객체를 사용해야 하는가?
- 불변객체는 근본적으로 쓰레드에 안전하여 동기화를 시킬 필요가 없다. 안심하고 공유가 가능하다는 점은 강한 장점이다.
- 불변객체는 그 자체로 실패 원자성을 제공한다. 실패원자성이란 호출된 메소드가 실패하더라도 해당 객체는 메소드 호출 전 상태가 유지되는 것을 말한다. 불변객체는 상태가 절대로 변하지 않기 때문에 이를 제공한다.
3. 애플리케이션 컨텍스트
애플리케이션 컨텍스트는 프로젝트를하면서 초기 설정 이후 많이 안건드리는 부분이다 보니 자세한 기능을 알고 있지 못했다. 우선 개념으로는 빈의 생성과 관계설정 같은 제어를 담당하는 빈 팩토리를 상속 받아 추가적인 기능등을 확장한 것이 애플리케이션 컨텍스트이라고한다. 실무의 예를 들어보자면 페이지를 만들 때 로그인 관련 기능을 만든적이 없는데도 로그인을 해야하는 페이지의 알림창이 떴었다. 알고보니 애플리케이션 컨텍스트에서 로그인 안해도되는 페이지를 설정해주는 부분이있었다. 그때 컨텍스트에 대한 인지가 있었는데 새롭게 공부하게 되니 많이 알게되어서 신기했다.
4. 싱글톤 레지스트리
싱글톤 패턴의 단점이 네가지가 있는데, 읽기만했을 때 이해가 안 돼서 예시를 직접 찾아봤다. https://diqmwl-programming.tistory.com/97
일단 네가지 단점에 대한 예시는 아닌데 싱글톤 패턴이 왜 쓰이기 어려운지 잘 나와있는 코드같다. 여기 나와있는 네 개의 코드를 보고 더 이해가 잘갔는데 참고하셨음 좋겠다. 예시도 찾아보고 검색을 해보니 싱글톤이 왜 안티패턴인지 이해가 갔다. 우선 독립적으로 오브젝트가 생기기때문에 각각 구분하지도 못할뿐더러 전역 상태로 만들어 자유롭게 접근하고 수정하고 공휴하는게 최대 단점인 것 같다. 그 예시가 링크의 맨밑에 있는 코드인데, 확실히 수정할 수 있는 변수가 예시로있으니 더 이해가 잘 됐다.
이후 싱글톤 레지스트리를 이해해보니 더 이해가 잘됐다. 스프링이 싱글톤 형태의 오브젝트를 만들고 관리하는 기능을 제공하니 새삼 편하다고 느꼈다.
5. 리플렉션
리플렉션이란 구체적인 클래스 타입을 알지 못해도, 그 클래스의 메소드, 타입, 변수들을 접근할 수 있도록 해주는 자바 API이다.
public class Car {
public void drive() {
// do Some Thing
}
}
public class Main {
public static void main(String[] args) {
Object car = new Car();
car.drive(); // 컴파일 에러
}
}
위의 코드 블록에서 컴파일 에러가 나는 이유는 Object라는 타입으로 Car 클래스의 인스턴스를 담을 수는 있지만, 사용 가능한 메소드는 Object의 메소드와 변수들뿐이기 때문이다. 이렇게 구체적인 타입의 클래스를 모를 때 사용하는 것이 리플렉션이다.
대표적으로 프레임워크나 IDE에서 이러한 동적 바인딩을 이용한 기능을 제공한다. ex) IntelliJ의 자동완성, 스프링의 어노테이션 등
이것이 가능한 이유는 자바 클래스 파일은 바이트 코드로 컴파일되어 Static영역에 위치하게 된다. 때문에 클래스 이름만 알고 있다면, 언제든 이 영역을 뒤져서 클래스에 대한 정보를 가져올 수 있는 것이다.
6. 싱글톤 컨테이너
스프링 컨테이너는 싱글톤 패턴을 적용하지 않아도, Default로 객체를 싱글톤으로 관리한다. 이처럼, 싱글톤 객체를 생성하고 관리하는 기능을 싱글톤 레지스트리라 한다.
스프링 컨테이너는 싱글톤 패턴의 모든 단점을 해결하면서 싱글톤으로 유지할 수 있다.
- 싱글톤 패턴 코드 필요 없음
- DIP/OCP/테스트/private 생성자로부터 자유롭게 싱글톤을 사용할 수 있다.
@Configuration이 붙은 설정 클래스 파일은 스프링이 CGLIB(Code Generator Library)을 사용하여 바이트코드 조작을 통해서 AppConfig 클래스를 상속받은 임의의 다른 클래스를 만들고, 다른 클래스를 스프링 빈으로 등록한다.
@Configuration 내부에 있는 @Bean으로 등록되는 빈들은 바이트 코드 조작이 되어 객체를 반환하여 빈으로 등록하는 경우, 싱글톤으로 한 번만 등록되도록 한다.
@Bean
public MemberRepository memberRepository() {
if(memoryMemberRepository가 이미 스프링 컨테이너에 등록되어 있으면?) {
return 스프링 컨테이너에서 찾아서 반한;
} else { // 스프링 컨테이너에 없으면
기존 로직을 호출해서 MemoryMemberRepository를 생성하고 스프링 컨테이너에 등록
return 반환
}
- CGLIB(Code Generator Library) : 코드 생성 라이브러리로서 런타임에 동적으로 자바 클래스의 프록시를 생성해주는 기능을 제공한다. CGLIB를 사용하면 매우 쉽게 프록시 객체를 생성할 수 있으며, 성능 또한 우수하다. 더불어, 인터페이스가 아닌 클래스에 대해서 동적 프록시를 생성할 수 있기 때문에 다양한 프로젝트에서 널리 사용되고 있다. 예를 들어, Hibernate는 자바빈 객체에 대한 프록시를 생성할 때 CGLIB를 사용하며, Spring은 프록시 기반의 AOP를 구현할 때 CGLIB를 사용하고 있다.
7. 추상클래스와 인터페이스
추상클래스 : 클래스 내부에 추상 메소드가 하나 이상 포함되거나 abstract로 정의된 경우
인터페이스 : 모든 메소드가 추상 메소드인 경우. 따라서 abstract를 적지 않는다.
공통점
- 추상클래스와 인터페이스는 선언부만 있고 구현 내용이 없는 클래스이다.
- 자기 자신이 직접 객체를 생성할 수 없으며, 자식 클래스가 추상클래스를 상속(extends)받거나, 인터페이스를 구현(implements)하여 객체를 생성할 수 있다.
- 선언된 type과 자식의 type이 같아야만 한다.
차이점
- 추상클래스는 단일상속, 인터페이스는 다중상속이 가능하다.
- 추상클래스의 목적은 상속을 받아서 기능을 확장시키는 것이다.
- 인터페이스의 목적은 구현하는 모든 클래스에 대한 특정한 메소드가 반드시 존재하도록 강제하는 역할이다. (즉 구현 객체가 같은 동작을 한다는 것을 보장하기 위함)
8. 오브젝트와 의존 관계
스프링이란
: 스프링 프레임워크(영어: Spring Framework)는 자바 플랫폼을 위한 오픈 소스 애플리케이션 경량화 프레임워크
- 스프링의 특징 7가지
- 경량 컨테이너로서 자바 객체를 직접 관리한다. 각각의 객체 생성, 소멸과 같은 라이프 사이클을 관리하며 스프링으로부터 필요한 객체를 얻어올 수 있다.
- 스프링은 Plain Old Java Object 방식의 프레임워크이다. 일반적인 J2EE 프레임워크에 비해 구현을 위해 특정한 인터페이스를 구현하거나 상속을 받을 필요가 없어 기존에 존재하는 라이브러리 등을 지원하기에 용이하고 객체가 가볍다.
- 스프링은 제어 반전(IoC : Inversion of Control)을 지원한다. 컨트롤의 제어권이 사용자가 아니라 프레임워크에 있어서 필요에 따라 스프링에서 사용자의 코드를 호출한다.
- 스프링은 의존성 주입(DI : Dependency Injection)을 지원한다. 각각의 계층이나 서비스들 간에 의존성이 존재할 경우 프레임워크가 서로 연결시켜준다.
- 스프링은 관점 지향 프로그래밍(AOP : Aspect-Oriented Programming)을 지원한다. 따라서 트랜잭션이나 로깅, 보안과 같이 여러 모듈에서 공통적으로 사용하는 기능의 경우 해당 기능을 분리하여 관리할 수 있다.
- 스프링은 영속성과 관련된 다양한 서비스를 지원한다. iBATIS나 하이버네이트 등 이미 완성도가 높은 데이터베이스 처리 라이브러리와 연결할 수 있는 인터페이스를 제공한다.
- 스프링은 확장성이 높다. 스프링 프레임워크에 통합하기 위해 간단하게 기존 라이브러리를 감싸는 정도로 스프링에서 사용이 가능하기 때문에 수많은 라이브러리가 이미 스프링에서 지원되고 있고 스프링에서 사용되는 라이브러리를 별도로 분리하기도 용이하다.
빈과 빈 팩토리 ( 애플리케이션 컨텍스트 )
: 스프링의 핵심을 담당하는 건 빈 팩토리 또는 애플리케이션 컨텍스트라고 불리는 것이다.
(스프링에서 말하는 WebApplicationContext는 ApplicationContext를 확장한 WebApplicationContext 인터페이스의 구현체를 말하며,
WebApplicationContext는 ApplicationContext를 상속받아서 사용한다. 스프링 컨테이너에서 관리하고 동작한다고 생각하면 된다.
DispatcherServlet이 여러 개일 경우 공통으로 사용할 빈들을 Root WebApplicationContext에 선언해두고 공유할 수 있게 하는 것.)
빈(bean)이란 스프링이 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트를 말하며, 오브젝트 단위의 애플리케이션 컴포넌트라고도 한다.
동시에 스프링 빈은 스프링 컨테이너가 생성과 관계설정, 사용 등을 제어해주는 제어의 역전이 적용된 오브젝트를 가리키는 말이다.
스프링에서는 빈의 생성과 관계설정 같은 제어를 담당하는 IoC 오브젝트를 빈 팩토리(bean factory)라고 부른다.
보통 빈 팩토리보다는 이를 좀 더 확장한 애플리케이션 컨텍스트(application context)를 주로 사용한다.
애플리케이션 컨텍스트는 별도의 정보를 참고해서 빈(오브젝트)의 생성, 관계설정 등의 제어 작업을 총괄한다.
개방 폐쇄 원칙을 따르자 ( SOLID 객체지향 설계 원칙도 항상 기억 )
: 클래스나 모듈은 확장에는 열려 있어야 하고 변경에는 닫혀 있어야 한다는 원칙이다. 소프트웨어 공학적으로 스프링 프레임워크를 활용하여 좀 더 쉽게 응집도는 높고 결합력은 약하게 만들 수 있다.
스프링에서 주입은 생성자주입 방식으로 사용하자
final사용가능, 순환참조방지(서버실행시 바로 에러 파악 가능), 테스트코드 작성 용이. -> 필드주입과 수정자 주입은 먼저 빈을 생성한 후, 주입하려는 빈을 찾아 주입한다. -> But 생성자 주입은 먼저 생성자의 인자에 사용되는 빈을 찾거나 빈 팩토리에서 만든다. 그 후 찾은 인자 빈으로 주입하려는 빈의 생성자를 호출한다. 즉, 먼저 빈을 생성하지 않고 주입하려는 빈을 먼저 찾는다.
lombok ex)
@Controller
@RequiredArgsConstructor
public class BoardController {
private final IBoardItemService boardItemService;
/* 이하 생략 */
}
디자인패턴 3가지(1장에서는 Dao 마다 DBConnection 객체를 생성하는 부분을 관심사의 분리와 빈 주입을 통해 리팩토링해 나가는 예제 )
1) 템플릿 메소드 패턴
: 슈퍼 클래스에 기본적인 로직의 흐름을 만들고, 그 기능의 일부를 추상 메소드나 오버라이딩이 가능한 protect 메소드 등으로 만든 뒤 서브 클래스에서 이런 메소드를 필요에 맞게 구현해 사용하도록 하는 방법. -> 즉 슈퍼 클래스에 기본적인 메소드가 정의되어 있고 세부적인 메소드는 추상 메소드로 두어 서브 클래스에서 구현해 사용하는 방법
package com.kjh.hojak.controller;
public class Main {
public static void main(String[] args) {
Chrome chrome = new Chrome();
chrome.working();
System.out.println();
Ie ie = new Ie();
ie.working();
}
}
abstract class Work {
public void working(){
System.out.println("컴퓨터 킨다.");
browser();
System.out.println("검색을 한다.");
System.out.println("컴퓨터를 끈다.");
}
public abstract void browser();
}
class Chrome extends Work {
public void browser(){
System.out.println("크롬을 킨다.");
}
}
class Ie extends Work {
public void browser(){
System.out.println("인터넷 익스플로어를 킨다.");
}
}
2) 팩토리 메소드 패턴
: 서브클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것.( 객체 생성 등 예제 참고 )
abstract class UserDao {
public void add(User user) {
Connection c = getConnection();
}
public User get(String id) {
Connection c = getConnection();
}
public abstract Connection getConnection();
}
class OracleUserDao extends UserDao{
public Connection getConnection(){
// 오라클 connection 생성코드
}
}
class MySqlUserDao extends UserDao{
public Connection getConnection(){
// MySql connection 생성코드
}
}
3)전략패턴
: 자신의 기능 맥락(context)에서, 필요에 따라 변경이 필요한 알고리즘을 인터페이스를 통해 통째로 외부로 분리시키고, 이를 구현한 구체적인 알고리즘 클래스를 필요에 따라 바꿔서 사용할 수 있게 하는 디자인 패턴이다.
ex) UserDao는 전략 패턴의 컨텍스트에 해당한다. UserDaoTest 클라이언트는 컨텍스트가 사용할 전략을 바꿔가면서 사용할 수 있다. (예제 참고)
-Tip
퍼시스턴스 프레임워크는 데이터의 저장, 조회, 변경, 삭제를 다루는 클래스 및 설정 파일들의 집합이다.
Spring IoC 컨테이너가 관리하는 자바 객체를 **빈(Bean)**이라 한다.
싱글톤 레지스트리란 싱글톤 패턴을 사용함으로써 발생되는 문제점들을 보완하기 위해 스프링 프레임워크에서 직접 싱글톤을 생성, 관리 해주는 기능이다.(싱글톤 오브젝트는 멀티스레드 환경에서 동시에 접근이 가능하므로 상태정보를 내부에 갖고 있지 않은 무상태 방식으로 만들어져야함)
1장 오브젝트와 의존 관계 정리
- 먼저 책임이 다른 코드를 분리해서 두 개의 클래스로 만들었다.(관심사의분리-SoC, 리팩토링)
- 그중에서 바뀔 수 있는 쪽의 클래스는 인터페이스를 구현하도록 하고, 다른 클래스에서 인터페이스를 통해서만 접근하도록 만들었다. 이렇게 해서 인터페이스를 정의한 쪽의 구현 방법이 달라져 클래스가 바뀌더라도, 그 기능을 사용하는 클래스의 코드는 같이 수정할 필요가 없도록 만들었다.(전략 패턴)
- 이를 통해 자신의 책임 자체가 변경되는 경우 외에는 불필요한 변화가 발생하지 않도록 막아주고, 자신이 사용하는 외부 오브젝트 기능은 자유롭게 확장하거나 변경할 수 있게 만들었다.(개방 폐쇄 원칙)
- 결국 한쪽의 기능변화가 다른 쪽의 변경을 요구하지 않아도 되게 했고(낮은결합도), 자신의 책임과 관심사에만 순수하게 집중하는(높은 응집도) 깔끔한 코드를 만들 수 있었다.
- 오브젝트가 생성되고 여타 오브젝트와 관계를 맺는 작업의 제어권을 별도의 오브젝트 팩토리를 만들어 넘겼다. 또는 오브젝트 팩토리의 기능을 일반화한 IoC 컨테이너로 넘겨서 오브젝트가 자신이 사용할 대상의 생성이나 선택에 관한 책임으로부터 자유롭게 마들어줬다(제어의역전-IoC)
- 전통적인 싱글톤 패턴 구현 방식의 단점을 살펴보고, 서버에서 사용되는 서비스 오브젝트로서의 장점을 살릴 수 있는 싱글톤을 사용하면서도 싱글톤 패턴의 단점을 극복할 수 있도록 설계된 컨테이너를 활용하는 방법에 대해 알아봤다(싱글톤 레지스트리)
- 설계 시점과 코드에는 클래스와 인터페이스 사이의 느슨한 의존관계만 만들어놓고, 런타임 시에 실제 사용할구체적인 의존 오브젝트를 제3자(DI컨테이너)의 도움으로 주입받아서 다이내믹한 의존관계를 갖게 해주는 IoC의 특별한 케이스를 알아봤다.(의존관계 주입-DI)
- 의존오브젝트를 주입할 때 생성자를 이용하는 방법과 수정자 메소드를 이용하는 방법을 알아봤다(생성자 주입과 수정자 주입)
- 마지막으로, XML을 이용해 DI 설정정보를 만드는 방법과 의존 오브젝트가 아닌 일반 값을 외부에서 설정하게 런타임 시에 주입하는 방법을 알아봤다.(XML 설정)
Reference
3. 싱글톤 컨테이너 :: 이석준 개발블로그 (tistory.com)
CGLIB를 이용한 프록시 객체 만들기 :: 자바캔(Java Can Do IT) (tistory.com)
wiki-스프링이란
빈과 빈팩토리 - 애플리케이션 컨텍스트
필드주입 대신 생성자주입 방식을 사용하자
Autowired, Resource, Inject 차이
디자인패턴-팩토리메소드패턴 템플릿메소드패턴 차이
디자인패턴-전략패턴&디비커넥션예제
SOLID 객체지향 설계 원칙
애플리케이션컨텍스트
디스패처서블릿
토비스프링 1장 정리
Spring Boot를 사용해야 하는 이유
maven vs gradle
Maven With Nexus
인프런-싱글톤 DIP위반?
'스터디정리방' 카테고리의 다른 글
[기록] 220112 (0) | 2022.01.16 |
---|---|
[기록] 220105 (0) | 2022.01.09 |
[기록] 211229 (0) | 2022.01.02 |
[기록] 211222 (0) | 2021.12.26 |
[기록] 211215 (0) | 2021.12.18 |
댓글