TGIF-STUDY / Toby-s-Spring

토비의 스프링 1권 궁금 모음집
1 stars 0 forks source link

[1장] 오브젝트와 의존관계 #1

Open her0807 opened 1 year ago

her0807 commented 1 year ago

Q. jsp bean vs EJB bean vs spring bean 차이점이 뭘까?

p.55 스프링 빈 오브젝트가 너무 당연하게 사용해와서 한번도 이전 형태에 대해서 궁금해하지 않았던 것 같음.

Q. 예외를 던지는 경우와 잡아서 바로 처리하는 경우의 기준?

p.56 보통 어드바이저를 사용해서 전역에서 발생하는 예외 처리에 대한 핸들링을 하는데 어떤기준으로 처리하는가? checked exceptionunchecked exception 의 차이와 비슷한 내용일수도 있겠다는 생각이든다.

Q. Spring 내부에서 query 처리시 왜 PreparedStatement 를 기본으로 사용하는가?

p.57 쿼리 전체를 클라이언트에서 받아서 바로 실행시키면 sql inject 공격에 취약해지기 때문이다. 그런데 구체적으로 쿼리 실행 과정에 대해서 한번 더 보면 좋을 듯

Q. Main method 는 왜 static 일까?

p.58

Q. 스프링에서 커넥션을 가져와서 맺고 끝는 전 과정 한번더 살펴보기

next step 책 참고

Q. 리팩토링 시 메서드를 추출해야겠다고 생각하는 나만의 기준은?

p.64

Q. 자바는 왜 다중상속을 허용하지 않을까?

p.70

Q. 상속의 한계 or 단점

Q. Spring 이란 무엇인가?

p.87

Q. SpringApplication 을 실행시키면 bean 을 찾아서 주입하는 과정을 설명해보세요. (애플리케이션 컨텍스트 동작 방식)

p.93 예를 들면

  • configuration 어노테이션이 붙은 패키지의 하위 클래스를 탐색하며 빈으로 등록시킴
  • 수동 빈 등록 절차가 이뤄짐 ~
her0807 commented 1 year ago

p.100 까지만 등록했어요. (아직 진행중)

eejihoon commented 1 year ago

Q. Main method 는 왜 static 일까?

저도 이게 궁금했던 적이 있습니다. 그래서 오래 전에 한 번 찾아보고 정리해둔 글이 있는데요. 이게 도움이 될 지 모르겠습니다. 왜 main()는 public static void인가? 정말 아무것도 모를 때 찾아보고 쓴 글이라 틀린 점이 많을 것 같은데요.. 지적해주시면 저도 배울 것 같습니다. 여기에 전문을 옮겨둡니다.

왜 main()는 public static void인가?

자바에서 main()는 뭘까? 너무나 당연하게 그 자리에 있어서 이것이 특별한 메서드라는 생각조차 하지 않게 된다. main()는 자바 프로그램의 시작점이다. main()은 다른 메서드와 다르게 그 자리에서 실행해볼 수 있다. 좋다. 그런데 어떻게 이런 일이 가능해지는 걸까? 이름 빼고 선언부가 완전히 같은 다른 메서드를 정의해도 그것을 main()를 거치지 않고 실행하기란 불가능하다.

왜 public인가?

우리는 IDE의 Java Application Run으로 프로그램을 실행하는데 익숙하다. 이는 프로그램을 실행하는 주체가 main()이라고 착각하게 만든다. 하지만 잘 알다시피 프로그램을 실행하는 것은 main()이 아니라 JVM이다. 우리는 단지 main() 위에서 Run버튼을 눌렀을 뿐이지만 어디선가는 이런 일이 일어날 것이다.

  1. JVM을 실행한다.
  2. 실행된 JVM에게 우리가 Run버튼을 눌렀던 위치에 있는 main()를 실행하라고 명령한다.

여기서 main()는 왜 public이어야 하는가?라는 질문에 답을 찾을 수 있다. 2번 명령을 수행하기 위해 클래스 밖에, 패키지 밖에 존재하는 JVM이 main()에 접근할 수 있어야 하기 때문이다

왜 static인가?

static이 아니면 무엇이어야 할까? main()이 일반 메서드라고 상상해보자. JVM은 main()에 접근하기 전에 인스턴스를 생성(new) 해야 한다. 메서드를 가지고 있는 객체의 참조를 모르고서 그 메서드에 접근할 방법이 없기 때문이다. JVM이 실행하고 싶은 것은 main()다. static메서드로 만들어 JVM을 실행할 때 메모리(Method Area)에 올려두고 바로 접근하면 그만이다. static을 쓰면 코드가 더 길어진다는 이유로 거추장스러운 단계를 추가할 이유가 없다.

왜 void인가?

String일 수도 있고 Object일 수도 있는데 왜 void여야 할까? 자바 프로그램은 main() 위에서 실행된다. main() 내에 정의된 명령을 수행하고 나면 프로그램은 종료된다. 이미 말했듯이 main()은 프로그램의 시작점이다. 그럼 프로그램이 종료하는 지점, 도착지는 어디일까? main()의 모든 명령을 실행하고 나면 다시 main()만 남는다. main()에서 시작해서 main()에서 끝난다. main()이 반환하는 값을 사용할 어떤 것도 남아있지 않다. int를 반환하여 작업이 끝난다는 것을 명시적으로 알릴 수도 있지만 굳이 그럴 이유가 없다. main()은 운영체제의 프로세스가 아닌, JVM의 메인 스레드를 사용한다. 운영체제의 프로세스를 사용하는 것은 JVM이므로 main()는 종료 되었다는 상태를 반환하지 않아도 된다.

왜 main인가?

main이라는 이름은 JVM이 식별할 수 있는 키워드다. 만약 메서드 이름이 아니라면 정해진 형식으로 기본 메서드를 정의하라는 메시지를 띄운다.

Error: Main method not found in class, please define the main method as:
public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application

따라서 반드시 메인 메서드의 이름은 main이어야 한다.

String[] args

선언된 파라미터를 가변 인자 String...로 바꾸거나 변수 이름을 바꾸는 것은 상관없다. 하지만 타입을 다른 타입으로 바꿀 수는 없다. 가변 인자야 내부적으로 배열을 사용하기 때문에 상관없지만, 타입을 바꾸는 것은 오버로딩이다. JVM은 정해진 형식의 main()만 식별하므로 사용할 수 없다.

그런데 왜 많은 타입 중에 String일까? 프로그램마다 여러 입력이 존재할 수 있다. 사용자의 입력에 따라 다른 결과를 돌려줘야 한다. 프로그래머 입장에서 사용자의 입력을 판별하기에 String타입이 가장 직관적이다. 또 하나의 입력이 아니라 한 번에 여러 개의 입력이 존재할 수 있으니 String[]으로 설정한 게 아닌가 싶다.

참고

Understanding public static void main(String[] args) in Java

her0807 commented 1 year ago

ApplicationContext 와 BeanFactory 차이점

p.101

초기화 시간:

BeanFactory: 빈을 지연 초기화 함. 즉, 컨테이너 시작 중이 아니라 요청 시 빈을 생성하고 초기화(이때 컨테이너에 빈이 없으면 새로 만들고, 있으면 기존에 있는 빈을 반환하여 싱글톤을 보장함.

ApplicationContext: ApplicationContext는 컨테이너가 시작될 때 모든 싱글톤 Bean을 사전 인스턴스화 함.

구성 소스:

BeanFactory: BeanFactory는 일반적으로 XML 파일이나 Java 구성 클래스에서 Bean 정의를 읽고 기본적인 종속성 주입 기능을 제공 ApplicationContext: ApplicationContext는 BeanFactory를 확장한 것임. 이벤트 전파 및 애플리케이션 수준 구성(예: 환경 프로필, 메시지 소스 및 컨텍스트 계층)과 같은 추가 기능을 제공함 ( 여기서 말하는 추가기능이 뭘까??)

빈 후처리:

BeanFactory: BeanFactory는 'BeanPostProcessor' 구현을 통해 기본 Bean 후처리를 지원하지만 추가적인 후처리가 필요할 경우는 아래와 같은 세팅이 필요함


DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// populate the factory with bean definitions

// now register any needed BeanPostProcessor instances
factory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor());
factory.addBeanPostProcessor(new MyBeanPostProcessor());

// now start using the factory

ApplicationContext: ApplicationContext는 소스 설정 및 프로퍼티 값 조회 기능 ( 우리가 local, devel, prod 별로 설정 값 다르게 하는 것 처럼) 메시지에 대한 국제화(i18n)을 제공하는 인터페이스 등등을 제공한다.

스크린샷 2023-09-04 오후 11 34 11

정리(BeanFactory와 ApplicationContext 차이점은?)

가장 큰 차이점은 로딩방식이 다르다는 것

BeanFactory:

ApplicationContext

BeanFactory : Bean을 생성하고 관계를 설정하는 IoC의 기본 기능에 초점을 둠. ApplicationContext : 별도의 정보를 참고해서 빈의 생성, 관계 설정 등의 제어를 총괄하는 것에 초점을 둠.

her0807 commented 1 year ago

오브젝트 동일성과 동등성의 차이

p.103

자바에서는 두 개의 오브젝트가 완전히 같은 동일한 오브젝트라고 말하는것 ( 동일성) == 연산자로 확인 (주소 확인) 동일한 정보를 가지고 있는 오브젝트(동등성) 두개의 차이가 명확하다. ( equals 로 확인)

두개의 오브젝트가 동일하다면 사실 하나의 오브젝트만 존재하는 것 ( 싱글톤) 두 개의 오브젝트의 참조값이 동일하지는 않지만, 동등한경우에는 두 개의 각기 다른 오브젝트가 메모리상에 존재하는 것이다.

her0807 commented 1 year ago

기존 싱글톤객체와 스프링이 만들어주는 싱글톤 객체의(빈) 차이

p.107

기존 싱글톤 만드는 법은 생성자를 private 로 하고 최초 한번만 인스턴스를 생성해서 사용하는 것임. 그래서 내부에 들어가는 의존성을 최초 한번만 주입이 가능해서 목객체 사용이 불가능함.( 테스트 불가)

스프링 빈에서 만들어주는 싱글톤은 CGLIB 를 사용하여 바이트 코드 조작으로 프록시를 만들어 빈에 등록해주기 때문에 의존성 주입이 언제든지 가능함.

싱글톤은 멀티 스레드 환경이라면 여러 스레드가 동시에 접근해서 사용할 수 있기 때문에 상태를 가지고 있으면 관리에 주의해야함.

her0807 commented 1 year ago

빈의 스코프 활용법?

Spring Bean Scope

Spring에는 다양한 유형의 Bean Scope가 존재한다. 이 Bean Scope은 사용하는 Context에서 Bean의 Life Cycle을 정의하는 기능을 수행합니다.

종류

이 Scope 중에서 request, session, application 그리고 websocket은 Web 환경에서만 사용할 수 있다.

Singleton Scope

Singleton Scope으로 설정했을 때, Container는 해당하는 Bean의 단 하나의 인스턴스를 생성한다. 모든 요청은 cache된 하나의 인스턴스를 사용할 것이고 모든 수정 사항도 적용될 것이다. Default Scope이며 아무런 설정을 하지 않는다면 Singleton Scope이 적용된다.

@Bean
@Scope("singleton")
public Person personSingleton() {
    return new Person();
}

Prototype Scope

Prototye Scope로 설정한 Bean은 Container에서 요청할 때마다 다른 인스턴스를 반환단다.

@Bean
@Scope("prototype")
public Person personSingleton() {
    return new Person();
}

Request Scope

Request Scope으로 설정한 Bean은 요청이 발생할 때마다 Bean 객체가 생성되여 자동으로 주입된다. 즉, 하나의 HTTP 요청이 들어오면 생성이 되어 응답이 나갈 때까지 유지되는 Scope이며 요청 별로 인스턴스가 생성되고 관리된다.

또한, Request Scope는 Target 클래스에 proxyMode()를 기본적으로 적용한다.

Session Scope

Session Scope는 Http Session과 동일한 Life Cycle을 가진 Scope이다.

브라우저가 요청을 발생시키고 브라우저를 닫을 때까지의 Scope을 의미한다.

request.getSession()을 호출해 세션 영역의 객체를 얻을 수 있다.

Application Scope

ServletContext의 Life Cycle에 대한 Bean 인스턴스를 생성한다.

Singleton과 유사하지만 Application Scope은 여러 Servlet 기반 어플리케이션에서 공유되지만 Singleton은 단일 어플리케이션 컨텍스트 범위로 한정된다는 차이점이 있다.

WebSocket Scope

WebSocket Scope으로 지정된 Bean은 WebSocket Session 속성에 저장된다. WebSocket Session 동안 Bean에 접근한다면 동일한 인스턴스를 반환한다. (싱글톤 동작이지만 WebSocket Session에 국한된다.)

Web Scope in 터놓고

@RequestScope

@Component
@RequestScope
public class MemberTypeCache {
    private MemberType memberType;

    public MemberType getMemberType() {
        return memberType;
    }

    public void setMemberType(MemberType memberType) {
        this.memberType = memberType;
    }
}

현재 사용하고 있는 클래스로는 MemberTypeCache라는 클래스에 적용하여 사용 중이다. 사용 목적은 사용자가 어떤 요청을 했을 때 요청에 맞는 Member Type인지 확인하기 위한 데이터였다. (ex. Coach가 크루의 면담 예약 신청 페이지에 접속할 경우 Exception)

AOP 기능에 적용되어 사용 중이며 Context나 Session의 범위에 사용은 불필요하여 각각의 HTTP 요청마다 생성하여 비교하도록 @RequestScope를 사용하여 구현하였다.

참고 자료

her0807 commented 1 year ago

의존하고 있다는 것은 무슨 의미일까?

클래스 사이 Dependency

스크린샷 2023-09-04 오후 11 50 58

패키지 의존성

her0807 commented 1 year ago

DI 와 IOC 의 차이는 무엇인가?


- IOC 는 제어의 역전 객체를 생성하고 관계를 맺어주는 것 ( 빈을 생성할 떄 ApplicatiolnContext 에서 빈을 찾아서 주입해주는 역할)
her0807 commented 1 year ago

Q. 의존 관계 주입과 의존 관계 검색의 차이는?

의존 관계 주입은 무조건 스프링 빈이어야하고 검색은 검색할 때 생성해도 됨.

her0807 commented 1 year ago

빈 생성자 주입과 수정자 주입의 차이?

완결성 이 핵심이지 않을까/ 오브젝트가 생성이 됐는데, 미완성 객체인 것이.. 좋은 방식일까?

생성자 주입 방식(Constructor Injection)

@Controller
public class ConstructorInjectionController {

    private ConstructorInjectionService constructorInjectionService;

    // 생성자가 1개인 경우 @Autowired를 생략해도 주입 가능하도록 지원
    @Autowired
    public ConstructorInjectionController(ConstructorInjectionService constructorInjectionService) {
        this.constructorInjectionService = constructorInjectionService;
    }
}

(생성자가 1개만 있을 경우에 @Autowired를 생략해도 주입이 가능하도록 Spring 프레임워크에서 지원됩니다.)

생성자 주입 방식을 사용하게 되면 객체의 불변성(Immutable)을 확보할 수 있기 때문에 주입받을 필드를 final으로 선언 가능합니다.또한 컴파일 시점에 누락된 의존성을 확인할 수 있다는 장점과 객체 생성 시점에 필수적으로 빈 객체 초기화를 수행해야 하기 때문에 NullPointerException을 방지할 수 있다는 장점이 있습니다.

@Controller
@RequiredArgsConstructor
public class ConstructorInjectionController {

    private final ConstructorInjectionService constructorInjectionService;
}

또한 final 키워드를 붙임으로써 Lombok과 결합되어 코드를 간결하게 작성할 수 있게 됩니다.

(Lombok에는 final 변수를 위한 생성자를 대신 생성해주는 @RequiredArgsConstructor 어노테이션이 존재합니다.)

또한 런타임 시점에 순환 참조 파악가능

her0807 commented 1 year ago

스프링이란?

어떻게 오브젝트가 설계되고, 만들어지고 어떻게 관계를 맺고 사용되는지에 관심을 갖는 프레임 워크

her0807 commented 1 year ago

Q. (빈 등록 방식) xml vs 어노테이션

A.

her0807 commented 1 year ago

DI 가 IOC 안에 포함되는 개념인가?

DI 는 Ioc 를 실현하는 방법중에 하나이다.

her0807 commented 1 year ago

Q. 예외를 던지는 경우와 잡아서 바로 처리하는 경우의 기준?

통제할 수는 없는데, 어떤 결과를 바로 내보내야한다거나 그럴 때 예외를 바로 처리함.

즉 추가 수정이 필요할 때, 잡을 것 같은데,

예외 처리가 비지니스 로직에서 처리되면 중요한 로직을 가리게 되는 것 같다.

코틀린에서 checked Exception 을 없었다. throws 가 사라진 이유.. 자바는 좀 IO Exception 같은 거추장 스러운 throws 가 있다..

her0807 commented 1 year ago

스프링은 원래 MVC 모델 추가하지 않으면 바로 끝난다.

그런데 우리가 붙잡고 있는 것이다.