IoC 컨테이너는 객체를 빈이라는것으로 관리를 한다?
컨테이너에 객체(빈)를 등록하여 컨테이너가 객체를 사용하는 권한을 가진다?
컨테이너 안 객체들 사이에 의존성을 주입 하여 객체들 간의 관계를 정리한다?
IoC (Inversion of Control, 제어의 역전)
👉🏻애플리케이션의 제어 권한을 개발자(혹은 프로그램 코드)에서 프레임워크나 컨테이너(SPRING)로 넘기는 것
Spring에서는 IoC를⭐DI (Dependency Injection)⭐ 방식을 통해 구현
Spring의 IoC 컨테이너를 이용하여 Bean을 등록하는 방법
1️⃣ XML 파일을 이용한 Bean 등록
2️⃣ Java Config 클래스를 이용한 Bean 등록: @Configuration과 @Bean을 사용하여 빈을 등록 ▶️외부 객체
3️⃣ 애노테이션을 이용한 Bean 등록: @Component, @Service, @Controller, @Repository 등을 사용하여 Bean을 정의하고, @ComponentScan으로 Bean을 스캔 ▶️ 자신이 만든 객체
➕@SpringBootApplication 사용 시 기본 스캔
- Spring Boot 애플리케이션에서 @SpringBootApplication 어노테이션이 붙은 클래스가 자동으로 컴포넌트를 스캔
- @SpringBootApplication은 기본적으로 현재 클래스가 위치한 패키지와 그 하위 패키지를 스캔.
DI (Dependency Injection, 의존성 주입)
👉🏻객체 간의 의존 관계를 Spring 컨테이너가 설정하고 주입하는 것
▪️객체를 생성할 때 필요한 의존성을 직접 생성하는 대신 외부에서 주입 받음
➡️객체 변경 시 객체를 사용하는 쪽에서 객체를 변경하는 것이 아니라 외부에서 변경함
▪️장점
👍🏻객체 간 결합도를 줄여 유연성과 재사용성 높다
👍🏻객체 간의 관계를 명확히 하여 코드 유지보수 용이
DI의 방식
1️⃣필드 주입 (Field Injection) (비추천. 스프링에 의존적)
@Autowired를 사용하여 클래스의 필드에 의존성을 직접 주입
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
}
2️⃣생성자 주입 (Constructor Injection) (추천) 생성자가 하나뿐일 때는 @Autowired 생략 가능.
@Service
public class UserService {
private final UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
3️⃣Setter 주입 (Setter Injection)
@Service
public class UserService {
private UserRepository userRepository;
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
🔹@Component: Spring이 관리할 일반적인 빈(Bean)을 등록
@Component //기본은 생성자 주입
public class Dice {
private int face;
public Dice() {
System.out.println("Dice Constructor");
}
public Dice(int face) {
this.face = face;
System.out.println("Dice Constructor(int) 실행");
}
public int getNumber(){
return (int)(Math.random()*face)+1;
}
}
@Component
public class Game {
private List<Player> list; //플레이어 리스트도 스프링 공장을 통해서 생성, 주입 받음
public Game() {
}
public Game(List<Player> list) {
System.out.println("Game(List<Player>) list 생성자 실행");
this.list = list;
}
public void setList(List<Player> list) {
this.list = list;
}
public void play(){
for(Player player : list){
player.play();
}
}
}
▫️ @component(”id”) id를 등록
▫️ 아무것도 안쓰면 클래스이름의 첫 글자를 소문자로 바꾼 아이디로 설정
@Component("bbb")//id는 bbb로 등록 아무것도 안쓰면 클래스이름의 첫 글자를 소문자로 바꾼 아이디로 설정 됨
public class Book {
private String title;
private int price;
public Book() {
System.out.println("Book 생성");
}
}
🔹 @Component 사용 안하고 수동으로 빈을 등록 할 수도 있음
public class Player {
private String name;
private Dice dice; //실행 될 때 주사위를 주입 받아야 함 (의존성 주입 DI)
public Player() {
}
public Player(Dice dice) {
this.dice = dice;
}
public void setDice(Dice dice) {
this.dice = dice;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void play() {
System.out.println(name+"은 주사위를 던져서"+dice.getNumber()+"가 나왔습니다");
}
}
🔹 @ComponentScan 을 사용하여 @@Component가 붙은 빈들을 등록
🔹 basePackages = "" 스캔 할 패키지 지정
@ComponentScan(basePackages = "sample") //sample 패키지 아래
@PropertySource({"classpath:game.properties"})//이 파일의 설정 사용
public class GameConfig {
// @Bean
// public Dice dice(@Value("${face}")int face) {
// return new Dice(face);
// }
@Bean
public Player kang(Dice d) {
//Player player=new Player(d); 생성자 주입
Player player = new Player();
player.setDice(d);
player.setName("Kang");
return player;
}
@Bean
public Player hwang(Dice d) {
//Player player=new Player(d); 생성자 주입
Player player = new Player();
player.setDice(d);
player.setName("hwang");
return player;
}
@Bean
public Player kim(Dice d) {
//Player player=new Player(d); 생성자 주입
Player player = new Player();
player.setDice(d);
player.setName("kim");
return player;
}
@Bean
public Game game(List<Player> players) {
Game game = new Game();
game.setList(players);
return game;
}
}
🔹 resource → game.properties 생성하여 face 값을 생성
face=45
public class SpringExam02 {
public static void main(String[] args) {
ApplicationContext context=new AnnotationConfigApplicationContext(GameConfig.class);
Game game=context.getBean("game", Game.class);
game.play();
Book book=context.getBean("bbb",Book.class); //Book이라는 클래스에 @Component 사용해서 자동으로 빈 등록이 됨
//GameConfig 컨테이너에서 이를 감지해 빈을 가져옴
MyBean myBean=context.getBean(MyBean.class);
myBean.setName("jiyun");
System.out.println(myBean.getName());
}
}
ApplicationContext context = new AnnotationConfigApplicationContext(GameConfig.class);
▫️Spring 컨테이너를 초기화하며, 설정 클래스로 GameConfig.class를 사용 GameConfig는 Java Config 방식으로 Spring에서 사용할 Bean을 정의한 클래스
Game game = context.getBean("game", Game.class);
game.play();
▫️ game이라는 이름으로 등록된 Game 타입의 Bean을 가져옴
🔹 수동으로 빈 등록 시
public class MyBeanConfig {
//스프링 공장에게 어떤 빈을 관리하게 할것인지 알려줘야 함
//XML
//<bean id="myBean" class = "sample.been.MyBeen"/>
//기본 설정이 싱글턴
//아이디가 다르면 다른 객체 생성
@Bean
public MyBean myBean() {
return new MyBean();
}
@Bean
public MyBean myBean2() {
return new MyBean();
}
@Bean
@Scope("prototype") // 매번 다른 객체가 생성
public MyBean myBean3() {
return new MyBean();
}
@Bean
public Book book() {
return new Book();
}
}
▫️ 기본적으로 같은 아이디를 써서 생성한 빈은 싱글턴 객체이다
빈 공장이 생성 될 때 객체가 생성되고 객체가 불릴 때 이미 생성된 객체를 리턴해줌
▫️ 다른 아이디로 생성한 빈은 다른 객체
▫️ @Scope("prototype")을 설정한 빈은 생성될 때 마다 매번 다른 객체가 생성 된다
빈 공장이 생성 될 때 생기지 않고 객체가 불릴 때 마다 객체를 생성해서 리턴 해줌
public class SpringExam01 {
public static void main(String[] args) {
//직접 사용하는 경우
MyBean bean = new MyBean();
bean.setName("abd");
System.out.println(bean.getName());
//스프링이 제공하는 공장을 통해서 사용
//1.BeanFactory --단순한 일만 한다 AOP 같은 기술은 사용할 수 없다
ApplicationContext context = new AnnotationConfigApplicationContext(MyBeanConfig.class);
MyBean bean1 = (MyBean) context.getBean("myBean"); //lookup 방식
MyBean bean2 = context.getBean("myBean",MyBean.class); //lookup 방식+형변환 안해도 됨
if(bean1==bean2) {
System.out.println("같은 인스턴스 입니다");
}else{
System.out.println("다른 인스턴스 입니다");
}
MyBean bean3 = context.getBean("myBean2",MyBean.class);
if(bean3==bean2) {
System.out.println("같은 인스턴스 입니다");
}else{
System.out.println("다른 인스턴스 입니다");
}
MyBean bean4 = (MyBean) context.getBean("myBean3",MyBean.class);
MyBean bean5 = (MyBean) context.getBean("myBean3",MyBean.class);
if(bean4==bean5) {
System.out.println("bean4 == bean5 같은 인스턴스");
}else {
System.out.println("bean4 != bean5 다른 인스턴스");
}
//id 없이 타입만 가지고 룩업 해줌
//이 타입의 빈이 하나만 있어야함
Book book = context.getBean(Book.class);
System.out.println(book);
}
어노테이션 | 역할 및 용도 |
@Component | 일반적인 Spring Bean으로 등록. 주로 서비스, 유틸리티 클래스를 Bean으로 관리. |
@Service | 비즈니스 로직 계층을 나타내는 Bean. 기능적으로 @Component와 동일하나 의미적으로 구분. |
@Repository | DAO(Data Access Object) 계층. 예외 변환과 같은 추가 기능 제공. |
@Controller | Spring MVC에서 HTTP 요청을 처리하는 컨트롤러 클래스를 나타냄. |
@RestController | REST API를 처리하는 컨트롤러. @Controller와 @ResponseBody를 결합한 형태. |
@Configuration | Java 기반 설정 클래스를 나타냄. Bean 정의 메서드를 포함. |
@Bean | Java Config에서 Bean을 정의하는 메서드에 사용. 반환된 객체가 Spring 컨테이너에 등록됨. |
@ComponentScan | 지정된 패키지에서 @Component, @Service, @Repository, @Controller 등을 스캔하여 Bean 등록. |
'TIL' 카테고리의 다른 글
250121 TIL (1) | 2025.01.22 |
---|---|
250120 TIL (4) | 2025.01.21 |
250116 TIL (0) | 2025.01.16 |
250110 TIL (0) | 2025.01.10 |
250109 TIL (5) | 2025.01.09 |