24장
Java 객체의 생성 및 관리를 위한 spring framework 이해하기
스프링으로 어떻게 객체를 생성할까?
여태까지는 우리가 bean을 직접 만들었지만, 스프링이 직접 만들 수 있게 해 보자.
이전에 클래스를 나누어 만들었던 것을 main에 합쳐서 실행한다. 역시 실행 잘 된다.
이제 @configuration을 public class에게 하고, 그 안에 @bean들을 집어넣는다. Main 함수에서 context에서 사용할 클래스를 Gaming 클래스에서 App03 GamingSpringBean으로 바꿔서 넣어준다. 실행하면 역시 잘 된다.
이제 spring에게 bean을 만들어달라고 하자. 어떻게 해야 할까?
사용하고자 하는 클래스에 @Component를 입력해 주면 된다.
이는 spring이 관리할 컴포넌트라는 의미이다. 어노테이션 기반의 configuration에서 자동 감지를 하겠다는 뜻이다. 즉 spring이 우리에게 Pacman의 인스턴스를 생성해 주는 것이다.
이제 pacman에 대한 bean을 지우고, @configuration 밑에 @componentscan을 입력해 준다.그러면 우리가 @component를 입력했던 Pacman 클래스를 자동으로 찾아와서 사용할 것이다. GameRunner 클래스도 없애보자.
@Configuration
@ComponentScan
public class App03GamingSpringBean {
public static void main(String[] args) {
var context = new AnnotationConfigApplicationContext
(App03GamingSpringBean.class);
context.getBean(GamingConsole.class).up();
context.getBean(GameRunner.class).run();
}
}
이렇게 하면, 역시 정상적으로 실행된다.
스프링 프레임워크는 우리가 수동으로 빈을 생성하지 않아도 대신 만들어준다. 객체를 관리하고auto-wiring 해줄 뿐 아니라 객체를 생성해 준다.
26장
Spring 컴포넌트에 대한 primary 및 qualifier 어노테이션 알아보기
마리오게임에도 @component를 지정해 주고 main에서 실행해 보자.
이런 에러 문구가 뜰 것이다. 두 가지 bean이 발견된 상태이다.
스프링 프레임워크가 GamingConsole 인터페이스의 구현을 찾고 있는데, 2개를 발견한 것이다. 둘 중 하나를 스프링이 임의로 선택할 수 없기 때문에 우리가 지정해주어야 한다.
1) @Primary를를 사용한다.
마리오게임에 @primary를 부여해 보자.그러면, 여러 후보를 발견할 경우 가장 우선권을 준다는 뜻이다.
이렇게 변경 후 실행을 하면,
두 개의 컴포넌트(마리오게임, 팩맨)중 마리오게임을 실행한다.
2)@qualifier를 사용한다.
supercontra에도 @component를 주입했을 때 실행 결과는 여전히 마리오게임이 나온다. 3개의 컴포넌트(슈퍼콘트라, 팩맨, 마리오)중 마리오에게 @primary가 주입되어 있기 때문이다. 그러면, 슈퍼콘트라에 @qualifier (한정자를 의미한다)에 주입하고 GameRunner 클래스에서 @qualifier가 주입되어 있는 클래스를 읽으라고 설정해 보자.
@Component
public class GameRunner {
//마리오게임의 인스턴스를 만들어준다.
GamingConsole game;
//생성자
public GameRunner(@Qualifier("SupercontraGameQualifier") GamingConsole game) {
this.game = game;
}
//게임을 실행하긴 하지만, 좋은 예는 아니다. 보통 로깅 프레임워크를 사용하는 것이 좋다.
public void run() {
System.out.println("Running game : " + game);
game.up();
game.down();
game.left();
game.right();
}
이렇게 하고 실행하면,
슈퍼콘트라게임이 실행되는 것을 확인할 수 있다.
27장
Primary와 Qualifier – 어떤 spring 어노테이션을 사용해야 할까?
1) primary : 여러 후보가 자격이 잇는 경우, 해당 bean에게 우선권을 주는 것이다.
2) qualifier : 특정하게 지정된 bean을 auto-wired 하는 것이다.
28장
Spring framework 알아보기 – 의존성 주입의 다양한 유형
1) constructor-based
2) setter-based
3) field
의존성 주입 확인을 위해 새로운 public class를 만들고, 실행해본다.
위에 필수적인 빈들이 출력되고, 스프링부트로 연결되어 있는 빈들 역시 출력이 된다.
역시 @component로 의존성 주입한 모든 것들이 출력이 된다.
@Component
class YourBusinessClass{
dependency1 dependency1;
dependency2 dependency2;
public String toString(){
return "Using " + dependency1 + " and " +dependency2;
}
}
YourBusinessClass에 의존성을 주입한 후 출력을 하면
이렇게 나온다. 의존성들을 자동 와이어링하지 않았기 때문이다. 자동와이어링을 하려면 @Autowired를 해주어야 한다.
이렇게 하고 실행을 해보면,
이런 식으로 출력되는 것을 확인할 수 있다. 이는 필드주입을 한 것이다. 세터나 생성자 없이 리플렉션을 사용해서 주입했다.
이번에는 세터와 게터 주입을 보자.
세터 인젝션이 사용되는 것을 확인할 수 있다.
생성자로 인젝션을 살펴보자.
@Autowired
public YourBusinessClass(DepInjectionLauncherApplication.game.dependency1 dependency1, DepInjectionLauncherApplication.game.dependency2 dependency2) {
System.out.println("Constructor Injection - YourBusinessClass");
this.dependency1 = dependency1;
this.dependency2 = dependency2;
}
역시 잘 되는 것을 확인할 수 있다.
어느 유형이 적절할까?
생성자 기반 주입을 추천한다. 모든 초기화가 하나의 메서드에서 이루어지기 때문에 간편하고 간결하다.
29장
Java framework – 중요한 용어 이해하기
1) @component : @component를 클래스에 추가하는 경우, 클래스의 인스턴스는 스프링 프레임워크가 관리하게 된다. 어노테이션 중 가장 중요한 것 중에 하나로 볼 수 있다. 특정 클래스가 컴포넌트 스캔에 있다면 해당 클래스의 인스턴스, 즉 스프링 빈이 생성되고 스프링 프레임워크에 의해 관리된다.
2) component scan : 스프링은 컴포넌트의 위치를 파악해야 한다. 컴포넌트 스캔을 통해 패키지를 스캔한다.(이름을 명시해주어야 한다. 명시하지 않는다면, 현재 페이지의 패키지로 스캔된다.)
3) dependency injection : 애플리케이션을 실행하면 스프링 프레임워크는 가장 먼저 컴포넌트 스캔을 한다. 모든 구성 요소를 찾으려고 하는데, 컴포넌트의 의존성이 무엇인지 식별하고 모두 와이어링한다. 이 과정을 dependency injection이라 한다. Bean과 의존성을 식별하고 모두 와이어링하는 작업이다.
4) IOC : 기존에 객체 생성을 위해 우리가 직접 코드를 작성했다. 이는 코드 제어에 대한 권한이 우리에게 있는 것이다. 그러나 우리가 컴포넌트스캔 / 컴포넌트를 이용하여 와이어링 작업을 모두 스프링프레임워크에게 제어 권한을 넘겼기 때문에 IOC(제어 반전)이라고 한다.
비교 | @Component | @Bean |
어디서? | 모든 클래스에서 가능 | Configuration 클래스에서 가능 |
사용 편리도 | 매우 쉽다. 추가만 하면 된다. | 모든 코드에 써야 한다. |
자동와이어링 | 필드/세터/생성자 인젝션 | 특정 메소드/파라미터 호출 |
누가 생성하는지? | 스프링 프레임워크 | 개발자가 직접 코딩 |
권장 | 일반적으로 대부분 권장 | 서드파티 라이브러리를 인스턴스화할 때(스프링 시큐리티 코드 등) |
31장
Java spring 애플리케이션에 의존성이 있는 이유가 무엇일까?
실제 만들어야 할 앱에서는 수 천 개의 의존성이 존재하게 된다. 스프링 프레임워크를 사용하게 되면 객체가 아닌, 의존성과 와이어링에 집중할 수 있다. 애플리케이션의 로직에 집중하게 된다. 또한 객체의 생명 주기를 관리하는데, 프레임워크를 이용하여 @component를 표시하고 @autowired 어노테이션을 사용하여 의존성을 표시하기만 하면 된다.
예를 들어, 데이터서비스 인터페이스가 있다 하면, 여러 가지 데이터가 있을 수 있다(mongoDB, MYSQL). 각db 간의 유연한 이동이 가능해야 한다.
33장
Java와 함께 spring framework 알아보기
배운 과정
Coupling -> Java interfaces -> spring container -> java bean vs spring bean -> dependeny injection -> dependency injection types -> annotations -> @bean vs @component -> @primary vs @qualifier -> hands-on
배울 내용
Lazy initialization -> bean scopes -> postconstruct & predestroy -> Jakarta EE -> context & dependency injection -> XML configuration -> Alternatives - @component -> spring big picture -> spring Modules & projects -> why is spring popular?
35장
Spring framework beans의의 지연 초기화와 즉시 초기화 알아보기
스프링 빈의 기본 초기화는 즉시 초기화이다.
현재 빈을 생성하고 있는 ClassA가 있고, ClassA 빈을 사용하여 초기화하고 있는 ClassB가 있다.
@Component
class ClassA{
}
@Component
class ClassB{
private ClassA classA;
public ClassB(ClassA classA){
System.out.println("Some initialization Logic");
this.classA = new ClassA();
}
}
@Configuration
@ComponentScan
public class LazyinitializationLauncherApplication {
public static void main(String[] args) {
var context = new AnnotationConfigApplicationContext
(LazyinitializationLauncherApplication.class);
}
}
이 상태로 실행하면,
빈을 로드하지도 않고, 빈에서 메서드를 호출하지 않았음에도 자동으로 빈이 초기화된다. 그러나, @Lazy 어노테이션을 추가해서 실행하게 되면 초기화되어 실행되지 않는다.
그러면 classB 빈은 언제 초기화될까?
확인해 보기 위해 classB에 아무 클래스나 만든다.
context.getBean(ClassB.class).doSomething();
를 이용해서 빈을 출력한다.
이와 같이, 빈을 사용하려고 할 때 로드된다. 즉 @Lazy 어노테이션은 사용하기 전까지 초기화를 지연시킨다.
즉시 초기화를 권장한다. 그래야 에러를 찾기 쉽다. 복잡한 초기화 논리가 많고 초기화를 지연시키고자 할 때만 사용하는 것이 좋다.
36장
지연 초기화와 즉시 초기화 비교하기
지연 초기화 | 즉시 초기화 | |
초기화 시간 | 빈이 앱에서 처음 사용될 때 초기화 | 앱이 시작되거나 스프링 컨텍스트가 시작될 때 |
Default | Not default | default |
에러 발생 시 | 런타임 에러가 난다. | 앱이 시작되지 않는다. |
사용도 | 거의 x | 자주 사용 |
메모리 소비량 | 적다. | 일반적이다. |
37장
Java spring framework bean 스코프 – 프로토타입 및 싱글톤
프로토타입과 싱글톤 스코프를 비교해 보자.
스코프를 입력하지 않은 것과 입력한 것(프로토타입)을 비교해 보자.똑같은 것을 여러 번 출력하고 결과를 확인해 보자.스코프의 타입을 정하는 방법은
@scope(value = configurableBeanFactory. 을 하면, SCOPE_PROTOTYPE과 SCOPE_SINGLETON이 나온다.
메인에서 실행을 하면, 노말클래스는 해시코드가 전부 일정하지만, 프로토타입클래스는 해시코드(인스턴스)가 매번 변한다는 것을 확인할 수 있다. 기본적으로 스프링 프레임워크에서 생성되는 모든 bean은 싱글톤이다. 빈을 요청할 때마다 매번 같은 인스턴스를 출력한다. 매번 다른 인스턴스를 출력하고 싶으면 프로토타입을 사용하면 된다.
- 싱글톤 : spring IOC 컨테이너당 객체 인스턴스가 하나이다.
- 프로토타입 : spring IOC 컨테이너당 객체 인스턴스가 여러 개다.
웹 애플리케이션 :
-Request : 웹 애플리케이션에는 HTTP request가 있다. HTTP 요청당 객체 인스턴스 하나가 생성된다.
-Session : 동일한 사용자에게 속하는 여러 번의 요청이 같은 세션에 속할 수 있다. 사용자 HTTP 세션당 객체 인스턴스 하나가 생성된다.
-Application : 웹 애플리케이션 하나당 객체 인스턴스 하나
-Websocket : 웹소켓 인스턴스당 객체 인스턴스 하나
l 자바 Singleton(GOF) vs Spring Singleton
자바 싱글톤 : JVM 가상 머신당 객체가 하나이다.
스프링 싱글톤 : spring IOC 컨테이너당 객체 인스턴스가 하나이다.
JVM에 spring IOC 컨테이너를 하나만 실행한다면 둘은 같은 의미일 수 있으나, JVM에 여러 컨테이너를 사용하면 다를 수 있다. 보통 99.9% JVM에는 컨테이너를 하나만 실행하기 때문에 차이가 있다는 것만 유의하면 된다.
38장
프로토타입과 싱글톤 비교하기 – Spring framework bean 스코프
Prototype | Singleton | |
Instances | Per Spring IOC Container | One per Spring IOC Container |
Beans | 빈을 참조할때마다 새로운 빈 인스턴스가 생긴다. | 계속 같은 빈을 사용한다. |
Default | Not default | Default |
사용도 | 거의 사용 x | 99.9% |
시나리오 | Stateful beans | Stateless beans |
39장
Spring bean 알아보기 – PostConstruct 및 PreDestroy
@Component
class SomeClass{
private SomeDependency someDependency;
public SomeClass(SomeDependency someDependency){
super();
this.someDependency = someDependency;
System.out.println("All dependencies are ready!");
}
}
@Component
class SomeDependency{
}
SomeClass에 생성자로 SomeDependency somedDependency를 파라미터로 집어넣고 출력한다.
이렇게 출력이 된다. 이번에는 someDependency에 있는 메서드를 가져와서 출력해 볼 것이다.
스프링은 자동으로 의존성을 연결하고, 의존성을 자동 연결하는 대로 @postconstruct를 어노테이션 한 메서드를 호출한다. @postconstruct는 초기화를 수행하기 위해 의존성 주입이 완료된 후 실행해야 하는 메서드에서 사용하며, 이 메서드는 클래스를 사용하기 전에 호출된다. 애플리케이션이 실행되고 빈이 로드된다.
1) 생성자가 호출될 때, 빈은 초기화되지 않는다.
2) 이럴 때 @postConstruct를 사용하면 의존성 주입이 끝나고 실행됨이 보장되기 때문에 빈의 초기화에 대해 생각할 필요 없다.
3) bean의 생애 주기에서 한 번만 실행된다(앱이 실행될 때) -> 여러 번 초기화 방지
또한 애플리케이션이 종료되기 전에/컨텍스트에서 빈이 삭제되기 전에 뭔가 해야 할 수도 있다. 이는 @preDestroy 어노테이션을 통해 이루어진다.
컨테이너에서 인스턴스를 삭제하는 과정 중에 있음을 알려주는 콜백 알림으로 메서드에서 사용한다. predestroy를 어노테이션 한 메서드는 보유하고 있던 리소스를 해제하는데 일반적으로 사용된다.
@PreDestroy
public void cleanup(){
System.out.println("Cleanup");
}
둘은 딱 한 번만 받아오면 되는 값을 사용할 시 주로 이용한다.
40장
Jakarta EE의 발전 - J2EE 및 JAVA EE와 비교
J2EE -> Java EE -> Jakarta EE라고라고 부른다. 초기 엔터프라이즈 개발은 JDK에서 JAVA 언어로 직접 구축되었다.
Jakarta EE :
-JSP(웹 애플리케이션에 뷰를 만드는 데 사용된다)
-JSTL(웹 페이지에 동적 정보를 나타내는 데 사용할 수 있는 태그 라이브러리
-EJB
-JAX-RS
-CDI
-JPA
41장
Spring framework 및 Java를 통해 Jakarta CDI(Contexts & Dependency Injection) 알아보기
CDI는 규격이고, 인터페이스이다. CDI에는 중요한 몇 가지 API 어노테이션이 있다.
- Inject / Named / Qualifier / Scope / Singleton
CDI를 사용하려면 pom.xml에 의존성을 추가해야 한다.
@NAMED는 @COMPONENT를 대체할 수 있고, @INJECT는 @Autowired를 대체할 수 있다.
43장
JAVA spring xml 설정 알아보기
XML로도 빈을 관리할 수 있다. Resources에 새로운 xml 파일을 만들어준다. 그 후 bean을 직접 추가해 준다.
출력을 하면 빈의 아이디와 값이 출력이 된다.
그러나 최근 스프링 버전을 사용하면 xml 설정을 할 필요가 거의 없기 때문에 간단하게 알고 넘어가면 된다.
44장
JAVA 어노테이션과 XML 설정 알아보기
Annotations | XML | |
사용 난이도 | 매우 쉽다 | 번거롭다 |
길이 | 짧다 | 매우 길다 |
관리성 | 쉽다 | 어렵다 |
유지성 | O | X |
디버그 난이도 | 어렵다 | 중간 |
45장
Spring framework 스테레오 타입 어노테이션 – component 등
여태까지는 @component 어노테이션을 사용했지만, 다른 것들도 있다.
@component : 제네릭 어노테이션이며 모든 클래스에 적용 가능하다. 특정 클래스에 spring bean을 생성하려는 경우에 사용한다.
-@service : 클래스에 비즈니스 논리가 있으면 주로 사용
@controller : 웹 컨트롤러와 같이 컨트롤러 클래스인 경우 주로 사용(웹 애플리케이션과에서 사용)
-@Repository : bean이 데이터베이스와 통신하는 경우, 데이터를 저장하거나 검색, 조작하는 경우
최대한 구체적인 어노테이션을 사용하는 것이 좋다.
1) 구체적인 어노테이션을 사용하면 프레임워크에 자신이 의도했던 바를 더 자세하게 나타낼 수 있다. 특정 클래스의 역할에 대한 정보를 더 자세하게 준다.
2) 나중에 AOP를 사용하여 어노테이션을 감지하고 부가적인 동작을 추가할 수 있다.
46장
간단한 복습 – 중요한 spring framework 어노테이션
Annotation | Description |
@Configuration | 클래스가 @bean 메서드를 하나 이상 선언함을 나타낸다. |
@componentscan | 컴포넌트를 스캔할 특정 패키지를 정의한다. |
@component | 어노테이션한 클래스가 컴포넌트임을 나타낸다. @component 클래스가 @componentscan에 속한다면 스프링 빈이 생성된다. |
@service | 어노테이션한 클래스에 비즈니스 논리가 있음을 나타내는데 사용한다. |
@controller | 어노테이션한 클래스가 웹 애플리케이션/rest api임을 나타낸다. |
@primary | 여러 bean이 단일 값 의존성에 자동 연결될 후보일 때 bean에 우선 순위를 부여한다. |
@qualifier | 자동 연결 시 후보 빈의 한정자로, 필드나 매개변수에서 사용된다. |
@lazy | 지연 초기화 역할을 한다. |
@scope | 특정 컴포넌트에 프로토타입 스코프를 정의할 수 있다. 빈을 참조할 때마다 인스턴스가 새로 만들어진다는 뜻이다. |
@postconstruct | 의존성 주입이 수행된 이후 초기화를 위해 실행될 메서드. |
@preDestroy | 컨테이너에서 인스턴스를 삭제하는 과정을 거치고 있음을 알려주는 콜백 알림을 수신한다. |
47장
간단한 복습 -중요한 spring framework 개념
Dependency injection( = IOC) | 스프링 프레임워크는 빈을 확인해야 하고, 의존성을 확인해야 한다. 의존성을 빈에 주입해야 하는데, 이 과정을 의존성 주입이라 한다. |
IOC container | 스프링 빈과 빈의 수명을 책임지는 컨텍스트. 빈 생성, 전체 수명, 종료를 담당한다. 빈 팩토리와 어플리케이션 컨텍스트가 있다. |
Spring beans | 스프링에서 관리하는 모든 객체 |
Auto-wiring | 올바른 의존성을 찾아 빈에 연결해야 한다. |
48장
Spring 전체 구조 알아보기 – framework, 모듈, 프로젝트
Spring core : IOC 컨테이너, 의존성 주입, Auto-wiring 등이 있다. 이 모든 것들이 기본 기능이다. 이러한 기본 개념들을 통해서 앞으로 어떤 웹 애플리케이션을 만들든 유용하게 사용할 수 있다.
이제 더 큰 관점에서 바라보면 Spring Modules에서 볼 수 있다.
Spring models – [spring core, spring test, spring MVC, spring JDBC..]등이 있다.
스프링 프레임워크가 유명한 주된 이유 중 한 가지는 ‘유연성’이다. 경우에 따라서 다양한 모듈을 사용할 수 있다.
이번에는 spring projects 관점에서 바라보자.
Spring projects – [spring boot, spring cloud, spring data, spring security..]등이 있다.
스프링이 인기 있는 이유는 무엇일까?
1) 느슨한 결합이 가능하다. 그래서 유지 보수/테스트가 쉽다.
2) boilerplate code가 적다. 그래서 비즈니스 논리에 집중할 수 있고, 메서드마다 예외 처리를 작성할 필요 없다.
3) 아키텍쳐 유연성이 뛰어나다. 모듈/프로젝트가 나누어져 있기 때문에 필요한 부분만 사용하여 개발할 수가 있다.
'스프링,스프링부트' 카테고리의 다른 글
유데미 RANGA 86장-92장 요약 (2) | 2024.07.02 |
---|---|
유데미 RANGA 74-85장 요약 (0) | 2024.06.28 |
유데미 RANGA 50-73장 요약 (0) | 2024.06.28 |
유데미 RANGA 스프링부트 13-23장 요약 (0) | 2024.06.24 |
유데미 RANGA 스프링부트 1-12장 요약 (0) | 2024.06.22 |