2018-6-21 스프링 빈

발표자료

빈이란? 빈객체의 등록

  • 스프링이 생성하는 객체를 빈(Bean)이라고 부른다. 이것에 대한 정보는 applicationContext.xml 파일 <bean>태그 안에 들어있다.
  • <bean>태그의 속성은 id, name이 있는데, id는 빈 객체를 구분할 때 사용하는 이름, name은 빈객체를 생성할때 사용하는 클래스이다.
//applicatinoContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.1.xsd">
    <context:annotation-config/>
    <bean id="member" class="domain.Member" scope="prototype"></bean>
</beans>
<bean id="greeter" class="domain.Greeter">
      <property name="format" value="안녕하세요!"></property>
</bean>

Greeter greeter = new Greeter();
greeter.setFormat("%s, 안녕하세요");

//Main
public class Main {
    public static void main(String[] args) {
    	// Bean객체를 생성
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationContext.xml");
        // Bean객체를 제공
        Greeter g1 = ctx.getBean("greeter", Greeter.class);
        Greeter g2 = ctx.getBean("greeter", Greeter.class);
        String msg = g.greet("gradle을 이용해서 빈객체를 생성");
        System.out.println(msg);
        ctx.close();
    }
}
  • 위의 bean태그를 등록을 하면, 스프링컨테이너가 동작을 할때, Greeter greeter = new Greeter()와 같은효과를 발휘?한다.

스프링은 객체 컨테이너

  • 스프링의 핵심은 객체를 생성하고 초기화를 하는 것이다.
  • GenericApplicationContext는 인터페이스이고, 그것의 밑에있는 3개의 Context가 구현체이다. (위의 메인문에서, applicationContext.xml을 읽어왔다.)
  • GenericXmlApplicationContext : XML로부터 객체 설정 정보를 가지고 온다.
  • AnnotaionConfigApplicationContext : 자바 어노테이션을 이용한 클래스로부터 객체설정정보를 가지고 온다.

    스프링은 별도의 설정이 하지 않으면 한개의 빈객체만을 생성을 한다. 이를 싱글톤이라고 한다.

의존이란?

public class CarRegisterService {
    private CarDao carDao = new CarDao();

    public void regist(String name) {
        Car car = carDao.selectByName(name);
        carDao.insert(car);
    }
}

  • CarRegisterService의 경우 CarDao객체를 생성을 해서, 역할을 수행을 하고 있다. 클래스에서 다른클래스의 메서드를 실행을 하는 경우 의존한다고 표현을 한다.
  • 의존을 하는 경우, 의존객체를 위의 경우처럼 직접 생성을 하면 좋지만, 유지보수 관점에서 힘들다.
  • 어떻게 해야될까?

DI를 통한 의존 처리

public class CarRegisterService {
    private CarDao carDao;

    public CarRegisterService(CarDao carDao) {
        this.carDao = carDao;
    }
  • DI(의존주입)는 의존하는 객체를 직접 생성하지않고, 생성자나 setter메서드를 통해 의존객체를 전달받는것이다.
CarDao carDao = new CarDao();
CarRegisterService regSvc = new CarRegisterService(carDao);
CarBuyService buySvc = new CarBuyService(carDao);
  • 위의 코드에서 변경사항이 발생하면, carDao를 생성하는곳만 수정을 하면된다.
public class Assembler {
    private CarDao carDao;
    private CarRegisterService regSvc;
    private CarBuyService buySvc;

    public Assembler() {
        carDao = new CarDao();
        regSvc = new CarRegisterService(carDao);
        buySvc = new CarBuyService(carDao);
    }

    public CarDao getCarDao() {
        return carDao;
    }

    public CarRegisterService getRegSvc() {
        return regSvc;
    }

    public CarBuyService getBuySvc() {
        return buySvc;
    }
}

  • 위의 코드처럼 객체를 따로 생성을 하고, 주입을 하는 조립기 객체를 만든다.
  • 조립기 객체를 만들고, get메서드를 이용을 해서 객체를 가지고온다.

스프링의 DI설정

  • 이전에는 조립기를 이용을 해서 DI를 진행했지만, 스프링은 DI를 제공을 하는 조립기자체이다.
    <bean id="carDao" class="dao.CarDao"></bean>

    <bean id="carRegSvc" class="service.CarRegisterService">
        <constructor-arg ref="carDao" />
    </bean>

    <bean id="carBuySvc" class="service.CarBuyService">
        <constructor-arg ref="carDao" />
    </bean>
  • applicationContext파일에 미리 빈객체들을 등록을 시켜놓는다.
  • <constructor-arg ref=”carDao” />를 통해 인자를 전달을 한다. 이름이 carDao인 객체를 생성자에 전달.

설정메서드 타입

  • 인스턴스변수를 선언을 하고, get메서드, set메서드를 사용
  • set메서드를 사용을 하는 경우, <property>태그를 사용하고 이 태그는 name속성과 ref속성이 있다. value속성을 이용하면 기본타입의 데이터를 전달할 수 있다.
  • property의 name은 set메서드의 이름을 사용한다.

설정메서드 vs 생성자방식

  • 생성자방식 : 빈객체를 생성하는 시점에 모든 의존객체가 주입
  • 설정메서드방식 : property태그의 name속성을 통해 어떤 객체가 주입되는지 알 수 있다.

의존 자동주입

  • @autowired어노테이션을 통해서 설정에 의존객체를 명시하지 않아도 스프링이 자동으로 필요한 빈객체를 생성을 한다.
  • 즉 @Autowired를 사용안하면 노가다. 사용을 하면 굉장히 편하다.
    <bean id="carDao" class="dao.CarDao"></bean>
    <bean id="carRegSvc" class="service.CarRegisterService"></bean>
    <bean id="carBuySvc" class="service.CarBuyService"></bean>
  • 위와 같이 단순해진다.
  • 설정에 <context:annotation-config />를 추가해야한다.
  • @Autowired태그를 사용하면 constructor-arg태그나 property태그를 사용을 할 필요가 없다.
  • @Autowired태그는 스프링타입을 이용해서 의존대상객체를 검색을 한다.

@Resource

  • @Autowired어노테이션은 빈의 타입을 기준으로 검색을 한다. 반면 @Resource어노테이션은 빈의 이름을 기준으로 검색을 한다.
  • 하지만 @Resource어노테이션은 메서드나 필드에만 적용이 가능하고, 생성자에는 적용이 안된다.

@Resource 어노테이션 적용순서

  1. name에서 속성한 빈객체를 찾는다.
  2. name속성이 없을경우 동일한 타입을 찾는다.
  3. name속성이 없고 동일한 타입을 갖는 빈 객체가 2개이상이면, 같은 이름을 가진 빈객체를 찾는다.

@Autowired vs @Resource

  • @Autowired어노테이션은 required속성을 사용할 수 있다.

Java코드를 이용한 빈객체

  • GenericXmlApplicationContext클래스 대신 AnnotaionConfigApplicationContext클래스를 이용을 해서 스프링 컨테이너를 생성을 한다.
@Configuration
public class JavaConfig {
    @Bean
    public CarDao carDao() {
        return new CarDao();
    }

    @Bean
    public CarRegisterService carRegSvc() {
        return new CarRegisterService(carDao());
    }

    @Bean
    public CarBuyService carBuySvc() {
        return new CarBuyService(carDao());
    }
}

  • xml에서 설정을 하던 방법을 자바객체의 형태로 등록을 할 수 있다.
  • xml설정은 빈객체를 스프링컨테이너가 직접생성을 하지만, 자바설정에서는 자바설정코드에서 직접객체를 생성한다.
  • xml설정에서는 <context:annotation-config>설정을 추가해야 자동주입이 가능했지만, 자바설정파일에서는 별도의 설정파일이 필요가 없다.
ApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class)

빈라이프사이클과 범위

public class Main {
    public static void main(String[] args) {
    // 1. 컨테이너 초기화
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationContext.xml");
        //2. 컨테이너 사용
        Greeter g = ctx.getBean("greeter", Greeter.class);
        String msg = g.greet("gradle을 이용해서 빈객체를 생성");
        System.out.println(msg);
        //3. 컨테이너 종료
        ctx.close();
    }
}
  • 컨테이너초기화 : 빈객체의생성과 의존객체주입 및 초기화
  • 컨테이너종료 : 빈객체의소멸

객체범위

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
        Member member = context.getBean("member", Member.class);
        Member member1 = context.getBean("member", Member.class);
        System.out.println("member == member1" + member.equals(member1));
    }
}

@Configuration
public class JavaConfig {

    @Bean
    @Scope("prototype")
    public Member member() {
        return new Member();
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.1.xsd">
    <context:annotation-config/>
    <bean id="member" class="domain.Member" scope="prototype"></bean>
</beans>
Written on June 21, 2018