이번 포스팅에서는 스프링 bean 사용방법과 왜 굳이 spring bean을 사용하는지, 그리고 @Autowired 존재 이유에 대해 정리해보겠다.
(글에서 자주 등장하는 TIL 참고 링크는 제일 하위에 작성해두었다.)
spring에서 java bean을 만드는 방법은 클래스에 @Component를 붙여 자동으로 만드는 방법과, 클래스에는 @Configuration을 메서드에는 @Bean을 붙여 수동으로 자바 빈을 만드는 2가지 방법이 있다.
각각의 예제를 간단히 살펴보자.
@Configuration
public class App03GamingSpringBeans {
@Bean
public GameConsole game() {
var game = new PacmanGame();
return (game);
}
@Bean
public GameRunner gameRunner(GamingConsole game){
var gameRunner = new GameRunner(game);
return (gameRunner);
}
public static void main(String[] args){
var context = new AnnotationConfigApplicationContext(pp03GamingSpringBeans.class);
System.out.println(context.getBean(GamingConsole.class));
context.getBean(GamingConsole.class).up();
context.getBean(GameRunner.class).run();
}
}
위 수동으로 자바 빈을 만들었던 예제코드에서 코드를 더 지워 간결하게 만들 것이다.
이때 자동으로 스프링이 자바 빈을 만들 수 있는 이유는 컴포넌트 스캔에 있다.
스프링 프레임워크가 알아서 런타임 때 @ComponentScan의 기본 패키지 및 하위 패키지에 @Component로 등록된 컴포넌트를 스캔해 찾고, 자신이 관리할 스프링 빈 클래스로 등록해놓기에, 객체를 new 연산자없이도 자동으로 만들 수 있는 것이다.
package com.in28minutes.learnspringframework.game;
@Component
public class PacmanGame implements GamingConsole {
public void up() {
System.out.println("Up");
}
public void down() {
System.out.println("Down");
}
public void left() {
System.out.println("Left");
}
public void right() {
System.out.println("Right");
}
}
// Configuration 클래스의 gameRunner 클래스를 지우자.
package com.in28minutes.learnspringframework;
@Configuration
public class App03GamingSpringBeans {
//@Bean
//public GameRunner gameRunner(GamingConsole game) {
// var gameRunner = new GameRunner(game);
// return (gameRunner);
//}
public static void main(String[] args) {
var context = new AnnotationConfigApplicationContext(App03GamingSpringBeans.class);
System.out.println(context.getBean(GamingConsole.class));
context.getBean(GamingConsole.class).up();
context.getBean(GameRunner.class).run();
}
}
// gameRunner클래스에 자동 관리를 위해 @Component 어노테이션 추가
// 참고로, 패키지 경로는 동일해서 별다른 설정이 필요없었다.
@Component
public class GameRunner {
private GamingConsole game;
public GameRunner(GamingConsole game) {
this.game = game;
}
public void run() {
System.out.println("run : " + game);
game.up();
game.down();
game.left();
game.right();
}
}
이렇게 스프링 프레임워크가 PacmanGame과 GameRunner에 빈을 자동으로 생성하도록 @Component 어노테이션을 사용했다.
그 결과, @Configuration클래스 코드가 굉장히 간단하졌다. 수동으로 new 연산자로 자바객체를 직접 생성하지 않아도 되었다.
또한, 스프링은 런타임 시, 올바른 패키지를 스캔해 Component을 찾고, 객체를 생성하고, 이를 자동으로 추가해 전체 어플리케이션을 잘 작동시켜준다.
이처럼, 스프링에서 자바 빈을 만드는 2가지 방법에 대해 살펴보았다. 하지만 왜 굳이 스프링 프레임워크에서 자바 빈을 만들어 사용하는 것일까?
결론부터 말하자면, 동일한 역할을 수행하는 객체를 여러 번 만들지 않아도 되기 때문이다. 또한 주로 스프링 빈은 DI(의존성 주입)에서 사용된다.
게시판 웹사이트가 있다고 해보자. 해당 웹사이트에서는 login기능, add-article 기능, delete-article 기능 등등이 있다고 하자.
만일 스프링의 Bean객체를 사용하지 않는다면, 각각의 객체마다 new 연산을 수행해 객체를 만들어야 한다. 또한 동일한 객체가 아니기에 서로 가진 정보도 다르고, 메모리는 또 메모리대로 쓰는 등의 비효율적인 문제가 생긴다.
하지만, 싱글톤 - 특정 클래스의 동일 인스턴스가 생길 때마다 "동일한" 메모리의 인스턴스 사용 (TIL - 1.Spring - 2.2 참고) - 의 특징을 가진 스프링의 Bean을 사용한다면, 동일한 역할을 수행하는 객체를 여러 번 만들지 않아도 된다! 딱 1번 만들어두면, 동일한 역할의 인스턴스일 경우 앞서 만들어둔 자바 빈만 계속 재활용한다!
다시 말해, 스프링 컨테이너가 빈을 관리하므로 싱글톤 패턴을 적용시켜 동일한 인스턴스를 여러 곳에서 공유해 사용할 수 있다는 것이다. 훨씬 효율적이다!
또한, @Autowired 어노테이션을 사용해, Bean에 등록된 객체를 사용할 수 있게 된다. @Autowired가 없었다면 또 객체별로 new 연산자를 이용해 각각의 객체를 모두 초기화해야 했는데, 주로 생성자에서의 @Autowired를 사용해, 그럴 필요가 없어졌다. (TIL - 1. Spring - 3.3과 3-4 참고!)
따라서, 스프링을 사용하는 이유 중 하나는, 객체의 관리와 의존성 주입을 스프링 컨테이너에 위임해, 개발자가 보다 효율적으로 어플리케이션을 개발할 수 있도록 하기 위함이다.
출처 : https://cnu-jinseop.tistory.com/36
TIL : 2-2 and 3-1 정리 ; https://github.com/minjikimkim2222/TIL/blob/main/Spring-and-Springboot/1. Spring/2-2. Spring 개념 - Spring 컨테이너%2C 스프링 컨테이너의 생성과 빈 등록 과정.md