BoostCourse | Spring Core

judyzero·2025년 2월 3일

BoostCourse

목록 보기
5/7

Spring이란?

Spring Framework

반제품을 이용해서 자신이 원하는 제품을 만드는 것을 상상해보자. 나무집을 만든다고 생각하면 언제 나무를 자르고 페인트칠하고.. 복잡하니깐 반제품, 즉 이미 다 잘려져 있고 물감도 주는 제품을 사서 완제품을 만든다.
이처럼 프로그래밍을 할 때 처음부터 만드는것이 아닌 이미 구축되어있는거에 뭔가를 붙여 완성시키는 것을 Freamwork라고 한다.

Spring Framework 특징

  • 모듈화가 잘 되어 있다.
  • IoC 컨테이너이다.
  • 선언적으로 트랜잭션을 관리할 수 있다.

IoC/DI 컨테이너

컨테이너란?

  • 인스턴스의 생명주기를 관리한다.

    인스턴스를 생성하고 소멸되는 과정을 직접하지 않고, 컨테이너가 관리해준다.
    Servlet 클래스를 인스턴스화하는 과정을 tomcat이 대신 해준 것과 같다.

  • 생성된 인스턴스들에게 추가적인 기능을 제공한다.

IoC란?

  • Inversion of Control의 약어이다. 제어의 역전이라고 번역한다.
  • 개발자는 프로그램의 흐름을 제어하는 코드를 작성한다. 그런데, 이 흐름의 제어를 개발자가 하는 것이 아니라 다른 프로그램이 그 흐름을 제어한다.

    리모컨을 생각해보면 거의 모든 리모컨의 디자인이 동일하다. 그래서 어떤 리모컨이던 쉽게 사용할 수 있다. 이러한 디자인을 Interface라고 한다. Interface를 통일하면 TV가 바뀌더라도 쉽게 사용할 수 있다.

DI란?

  • Dependency Injection의 약자로, 의존성 주입이란 뜻을 가지고 있다.
  • DI는 클래스 사이의 의존 관계를 Bean 설정 정보를 바탕으로 컨테이너가 자동으로 연결해주는 것을 말한다.
    DI가 적용이 안됐을 때는 개발자가 직접 인스턴스를 생성해야 한다.
    DI를 적용하면 스프링 컨테이너가 자동으로 인스턴스를 할당해준다. TV = new TV() 를 안써도 된다는 말.

Spring에서 제공하는 IoC/DI 컨테이너

  • ApplicationContext: IoC/DI에 대한 기본 기능, 트랜잭션 처리, AOP 처리 등을 할 수 있다.

XML 파일을 이용한 설정

Bean class 특징

Java 클래스를 Bean 클래스라고 부른다.

  • 기본 생성자를 가진다.
  • 필드는 private하게 선언한다.
  • getter, setter 메소드를 가진다.
  • getName() setName() 메소드를 name property라고 한다.
package or.kr.boostcourse;

public class UserBean {
    private String name;
    private int age;
    private boolean male;

    public UserBean(){ }
    public UserBean(String name, int age, boolean male) {
        this.name = name;
        this.age = age;
        this.male = male;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isMale() {
        return male;
    }

    public void setMale(boolean male) {
        this.male = male;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

UserBean 클래스에 getter, setter, 생성자를 만들었다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean id="userBean" class="or.kr.boostcourse.UserBean"></bean>
</beans>

resource/applicationContext.xml 파일을 만들고 bean을 등록하였다.
<bean id="userBean" class="or.kr.boostcourse.UserBean"></bean> 이 부분이 중요하다.

package or.kr.boostcourse;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationContextExam01 {

    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("초기화 완료");

        UserBean userBean = (UserBean)ac.getBean("userBean");
        userBean.setName("kang");

        System.out.println(userBean.getName());

        UserBean userBean2 = (UserBean)ac.getBean("userBean");
        if(userBean == userBean2) {
            System.out.println("same instance");
        }
    }

}

ApplicationContextExam01에 실제로 Bean을 만들어보았다.
ClassPathXmlApplicationContext에 등록된 Bean들을 모두 생성한다. ApplicationContextgetBean 파라미터로 Bean을 불러올 수 있고, 리턴은 object 타입으로 되기 때문에 형변환을 해줘야 한다.
Bean은 싱글톤 패턴으로, 하나의 객체만 생성된다. 때문에 userBean == userBean2이다.
객체를 대신 생성해주고, 싱글톤 패턴으로 관리해주는 것을 IoC/DI라고 한다.

의존성 주입

public class Engine {
    public Engine(){
        System.out.println("Engine 생성자");
    }
    public void exec(){
        System.out.println("엔진이 동작합니다.");
    }
}

Engine.java

public class Car {
    private Engine v8;
    public Car() {
        System.out.println("Car 생성자");
    }
    public void setEngine(Engine e) {
        this.v8 = e;
    }

    public void run(){
        System.out.println("엔진을 이용하여 달립니다.");
        v8.exec();
    }

    public static void main(String[] args) {
        Engine e = new Engine();
        Car c = new Car();
        c.setEngine(e);
        c.run();
    }
}

Car.java

Engine 생성자
Car 생성자
엔진을 이용하여 달립니다.
엔진이 동작합니다.

이렇게 작동이 된다.
하지만 Car.java에 있는 Engine e = new Engine(); Car c = new Car(); 이 코드가 마음에 들지 않는다. 이건 spring IoC 컨테이너가 생성해줄 것이다.
이런 과정을 spring이 해줄려면 bean을 등록해주어야 한다.

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean id="userBean" class="or.kr.boostcourse.UserBean"></bean>
  <bean id="e" class="or.kr.boostcourse.Engine"></bean>
  <bean id="c" class="or.kr.boostcourse.Car">
    <property name="engine" ref="e"></property>
  </bean>
</beans>

ApplicatonContext.xml에 bean을 등록하였다.
Car 인스턴스에 Engine을 set하기 위해 property를 넣어준다.
property는 getter, setter을 의미한다고 했다. 즉, setEngine()을 말하고 있는 것이다. 근데 위의 Car.java를 확인하면 setEngine() 메서드에 Engine을 파라미터로 넣고 있다. 그래서 ref로 아이디가 e로 선언된 Engine을 파라미터로 넣으라고 말하는 것이다.

public class ApplicationContextExam02 {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        Car car = (Car) ac.getBean("c");
        car.run();
    }
}

ApplicationContextExam02.java 파일을 만들어 보자.
applicationContext.xml을 읽으면서 bean등록을 했고, getBean()으로 Car를 읽어왔다. 이제 car.run()을 통해,

Engine 생성자
Car 생성자
엔진을 이용하여 달립니다.
엔진이 동작합니다.

이런 결과값을 얻을 수 있다. DI를 설정하여 Engine 클래스가 등장하지 않기 때문에 이는 사용자가 Engine을 알지 못하고, Car만 안다면 된다.

Java Config를 이용한 설정

지금까지는 일일이 xml에 bean을 등록하였다. 이를 자동으로 해보자.

@Configuration
public class ApplicationConfig {
    @Bean
    public Car car(Engine e){
        Car c = new Car();
        c.setEngine(e);
        return c;
    }
    @Bean
    public Engine engine(){
        return new Engine();
    }
}
public class ApplicationContextExam03 {
    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);
        Car car = (Car) ac.getBean(Car.class);
        car.run();
    }
}

ac.getBean(Car.class)는 ApplicationContext가 관리하는 객체 중 Car라는 객체가 있으면 그걸 리턴해준다.

@Configuration
@ComponentScan("or.kr.boostcourse")
public class ApplicationConfig2 {
}

@Configuration아래에 @ComponentScan이라는 어노테이션을 추가했다.
@ComponentScan어노테이션은 파라미터로 들어온 패키지 이하에서 @Controller, @Service, @Repository, @Component 어노테이션이 붙어 있는 클래스를 찾아 메모리에 몽땅 올려줍니다.

Spring에서 사용하기에 알맞게 @Controller, @Service, @Repository, @Component 어노테이션이 붙어 있는 객체들은 ComponentScan을 이용해서 읽어들여 메모리에 올리고 DI를 주입하도록 하고, 이러한 어노테이션이 붙어 있지 않은 객체는 @Bean어노테이션을 이용하여 직접 생성해주는 방식으로 클래스들을 관리하면 편리하다.

  • @Configuration: 스프링 설정 클래스를 선언하는 어노테이션
  • @Bean: bean을 정의하는 어노테이션
  • @ComponentScan
    - @Controller, @Service, @Repository, @Component 어노테이션이 붙은 클래스를 찾아 컨테이너에 등록
  • @Component: 컴포넌트 스캔의 대상이 되는 애노테이션 중 하나로써 주로 유틸, 기타 지원 클래스에 붙이는 어노테이션
  • @Autowired: 주입 대상이되는 bean을 컨테이너에 찾아 주입하는 어노테이션

0개의 댓글