。゚(*´□`)゚。

코딩의 즐거움과 도전, 그리고 일상의 소소한 순간들이 어우러진 블로그

[네이버클라우드] 클라우드 기반의 개발자 과정 7기/웹프로그래밍

[NC7기-89일차(9월1일)] - 웹프로그래밍 70일차

quarrrter 2023. 9. 1. 14:58

*Spring IoC의 property 값 처리 원리 

=> Spring IoC 컨테이너에는 String -> Primitive Type 으로 변환하는 기본 프로퍼티에디터가 내장되어있다.

 

// 프로퍼티 에디터 - 기본으로 내장된 프로퍼티 에디터

String을
     byte, short, int, long, float, double, boolean, char로 바꿀 수 있다.
     => 그 외의 타입은 개발자가 프로퍼티 에디터를 만들어 등록해야 한다.

 

<!-- String을 java.sql.Date 객체로 바꿔주는 변환기가 없기 때문에 직접 Date 객체를 생성해야 한다. 
    단, 이방식은 날짜 프로퍼티 값을 설정할 때마다   매번 작성해야 하기 때문에 불편하다. 
해결책? String을 java.sql.Date 객체로 변환해주는  프로퍼티 에디터를 등록하면 된다.-->

            <bean class="java.sql.Date" factory-method="valueOf">
                <constructor-arg value="2021-6-1"/>
                
                
                
               자바코드면: java.sql.Date date = java.sql.Date.valueOf("2021-6-1");

// 프로퍼티 에디터 만들기 //CustomEditorConfigurer 사용하여 

 

 

// 프로퍼티 에디터 만드는 방법
// => java.beans.PropertyEditor 인터페이스를 구현하면 된다.
// => 그러나 이 인터페이스를 직접 구현하려면 
//    많은 메서드(12개의 메서드)를 모두 구현해야 한다.
//    너무 번거롭다.
// => 그래서 자바는 PropertyEditor를 미리 구현한 
//    PropertyEditorSupport 라는 클래스를 제공한다.
//    따라서 인터페이스를 직접 구현하지 말고 이 클래스를 상속 받아라!
//
// 1) java.beans.PropertyEditorSupport를 상속 받는다.
//
public class CustomDateEditor extends PropertyEditorSupport {
  // 이 메서드는 스프링 IoC 컨테이너가 String 타입의 프로퍼티 값을
  // 다른 타입의 값으로 바꿀 때 호출하는 메서드이다.
  @Override
  public void setAsText(String text) throws IllegalArgumentException {
    System.out.println("CustomDateEditor.setAsText()");
    // 파라미터로 넘어온 String 타입의 프로퍼티 값을
    // 원하는 타입(java.sql.Date)의 값으로 바꿔 내부에 저장한다.
    // => 그러면 스프링 IoC 컨테이너를 이 값을 꺼내서 객체에 주입할 것이다.
    this.setValue(Date.valueOf(text));
  }

  // 언제 어떤 메서드가 호출되는지 확인하기 위해 상속 받은 메서드를 오버라이딩 해보자!
  @Override
  public void setValue(Object value) {
    // 이 메서드는 호출되었을 때 그것을 표시하기 위해 오버라이딩 했다.
    System.out.println("CustomDateEditor.setValue()");
    super.setValue(value); // 원래 하던 일을 수행한다.
  }

  @Override
  public Object getValue() {
    // 이 메서드는 호출되었을 때 그것을 표시하기 위해 오버라이딩 했다.
    System.out.println("CustomDateEditor.getValue()");
    return super.getValue(); // 원래 하던 일을 수행한다.
  }
}
    <!-- String 값을 java.sql.Date 객체로 변환시키는 프로퍼티 에디터 장착하기 -->
    <!-- Spring IoC 컨테이너가 XML 설정 파일을 읽을 때: 
         만약 CustomEditorConfigurer 객체가 정의되어 있다면 
         그 객체를 설정파일에 정의된 대로 만들고 준비시킨다.
         그리고 프로퍼티 값을 저장할 때 이 객체에 정의된 프로퍼티 에디터를 사용할 것이다.   -->
    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
    // id를 설정할 필요는 없음 , id 없이 클래스만 있는건 이미 약속이 있는거임. 
	    <property name="customEditors"> 
	        <!-- setCustomEditors(Map<Class,Class> param) {...} -->
	        <map>
	            <!-- 프로퍼티 에디터를 설정하는 방법
	                 key: String 값을 어떤 타입의 값으로 바꿀 것인지에 대한 타입 이름이다.
	                 value: 커스텀 에디터(프로퍼티 값 변환기) 클래스 이름이다. 
	                 의미?
	                 => 스프링 IoC 컨테이너가 프로퍼티 값을 설정할 때 
	                    특히 String 값을 java.sql.Date 객체로 바꿔야 할 때 
	                    이 클래스를 사용하여 값을 바꾸라는 뜻이다.-->
                        
                        
             <entry key="java.sql.Date" 
	                   value="com.eomcs.spring.ioc.ex07.c.CustomDateEditor"/>
// 프로퍼티 에디터 만들기
package com.eomcs.spring.ioc.ex07.d;

import java.beans.PropertyEditorSupport;
import com.eomcs.spring.ioc.ex07.Engine;

public class CustomEngineEditor extends PropertyEditorSupport {
  @Override
  public void setAsText(String text) throws IllegalArgumentException {
    String[] values = text.split(",");

    Engine engine = new Engine();
    engine.setMaker(values[0]);
    engine.setValve(Integer.parseInt(values[1]));
    engine.setCylinder(Integer.parseInt(values[2]));

    this.setValue(engine);
  }
}

// 의존 객체 주입 자동화하기 - 자동화 전, XML 설정을 통한 수동 주입

Dependencty Injection 수동 주입 

    <bean id="c1" class="com.eomcs.spring.ioc.ex08.a.Car">
        <property name="model" value="티코"/>
        <property name="maker" value="비트자동차"/>
        <property name="cc" value="890"/>
        <property name="auto" value="true"/>
        <!-- 의존 객체 주입(Dependency Injection; DI) -->
        <property name="engine" ref="e1"/>
    </bean>
    
    <bean id="e1" class="com.eomcs.spring.ioc.ex08.a.Engine">
        <property name="maker" value="비트자동차"/>
        <property name="valve" value="16"/>
        <property name="cylinder" value="4"/>
    </bean>

 자동주입 

Spring IoC 컨테이너의 BeanPostProcessor 

기본
BeanPostProcessor

*BeanPostProcessor 예1

AutoWired 있으면 자동연결시키고 없음 말고

[동작원리]

1) 스프링 IoC 컨테이너는 객체를 만든다.

2) 프로퍼티 값을 설정한다.

3) 객체 생성 후 IoC 컨테이너에 등록된

리스너(BeanPostProcessor)에게 통보한다.

4) AutowiredAnnotationBeanPostProcessor 리스너가 있다면,

@Autowired 애노테이션을 처리한다.

    <!-- 의존 객체를 자동 주입하는 기능을 쓰고 싶어요!
         => 그 일을 할 객체를 등록하세요.
         어떤 객체인가요?
         => AutowiredAnnotationBeanPostProcessor 입니다.
         이 객체는 어떻게 사용하나요?
         => 셋터 메서드 또는 필드에 @Autowired를 붙이면 됩니다.
    -->
    <!-- @Autowired 애노테이션을 셋터 메서드에 붙였다고 해서 
         의존 객체가 자동 주입되는 것이 아니다.
         @Autowired 애노테이션이 붙은 셋터에 대해
         프로퍼티 값을 자동으로 주입하는 일을 할 객체를 등록해야 한다.
    -->
    <!-- @Autowired 애노테이션 도우미 등록방법:
         다음 클래스의 객체를 등록하면 된다.
         org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
    -->
    <!-- 동작원리:
         => Spring IoC 컨테이너가 설정 파일에 적혀있는 대로 객체를 생성한다.
         => 객체 생성 후에 BeanPostProcessor에게 보고한다.
         => AutowiredAnnotationBeanPostProcessor는 생성된 객체에 대해 
            @Autowired 애노테이션을 검사하여 
            이 애노테이션이 붙은 프로퍼티 값을 자동 주입하는 일을 한다.
         => 이 객체를 스프링 IoC 컨테이너에 등록하지 않으면,
            @Autowired 애노테이션은 처리되지 않는다. 
    -->
    <!-- 객체 생성 후 작업을 수행하는 역할자를 정의하는 방법:
         => BeanPostProcessor 규칙에 따라 클래스를 정의한 후 객체를 등록하면 된다. 
    -->
    <!-- BeanPostProcessor 인터페이스:
         => 스프링 IoC 컨테이너는 객체 중에 이 인터페이스를 구현한 객체가 있다면,
            설정 파일에 적혀있는 객체를 생성한 후에
            이 구현체의 postProcess....() 메서드를 호출한다. 
         => 즉 빈 생성 이후의 마무리 작업을 진행시킨다.
         => 그래서 이 인터페이스의 이름이 
            BeanPostProcessor(객체 생성 후 처리기) 인 것이다.

=> 주입할 의존 객체가 없으면 오류가 뜬다. null로 띄우고 싶으면 설정해야한다.

 

<선언적 프로그래밍>

init-method

객체생성후 바로 호출할 메서드가 있으면 호출 

각 객체를 만들고 나서 매번 호출됨.

    <bean id="c1" class="com.eomcs.spring.ioc.ex08.c1.Car" init-method="init">
        <property name="model" value="티코"/>
        <property name="maker" value="비트자동차"/>
        <property name="cc" value="890"/>
        <property name="auto" value="true"/>
    </bean>
// Spring IoC 컨테이너에 새 기능을 추가하는 예:
// => 새 기능이 IoC 컨테이너가 생성한 객체를 사용해야 한다면,
//    객체 생성 후에 그 작업을 수행하면 된다.
// => 이렇게 개발자가 컨테이너의 기능을 확장할 수 있도록
//    BeanPostProcessor라는 규칙을 제공한다.
//
// 즉 빈 생성 후에 어떤 작업을 수행할 객체를 만들고 싶다면?
// => BeanPostProcessor 규칙에 따라 클래스를 만들라!
// => 옵저버 디자인 패턴이 적용된 대표적인 예이다.
//
// BeanPostProcessor
// => 스프링 IoC 컨테이너는 빈을 생성하고 세터를 모두 호출한 난 후
//    이 구현체에게 보고한다.
//
public class MyBeanPostProcessor implements BeanPostProcessor {

  public MyBeanPostProcessor() {
    System.out.println("MyBeanPostProcessor()");
  }

  @Override
  public Object postProcessBeforeInitialization( 
      Object bean, String beanName) throws BeansException {
    // XML 설정에서 init-method 속성에 지정된 메서드가 호출되기 전에
    // 이 메서드가 먼저 호출된다.
    //
    System.out.println("postProcessBeforeInitialization()");
    System.out.printf("    => %s : %s\n", //
        beanName, //
        bean.getClass().getName());
    System.out.printf("    => %s\n", bean.toString());
    return bean;
  }


  @Override
  public Object postProcessAfterInitialization(
      Object bean, String beanName) throws BeansException {
    // XML 설정에서 init-method 속성에 지정된 메서드가 호출된 후에
    // 이 메서드가 호출된다.
    //
    System.out.println("postProcessAfterInitialization()");
    System.out.printf("    => %s : %s\n", //
        beanName, //
        bean.getClass().getName());
    System.out.printf("    => %s\n", bean.toString());
    return bean;
  }

}

/ BeanPostProcessor 사용법 - BeanPostProcessor 활용 예

// Spring IoC 컨테이너가 생성한 객체의 클래스 명을 로그로 남기고 싶다.

// => LogBeanPostProcessor 를 만들어 처리한다.

ApplicationContext iocContainer = new ClassPathXmlApplicationContext(//

"com/eomcs/spring/ioc/ex08/c2/application-context.xml");

 

// Spring IoC 컨테이너에 들어 있는 객체 출력

SpringUtils.printBeanList(iocContainer);

// 의존 객체 주입 자동화하기 - 인스턴스 필드에 @Autowired 애노테이션 붙이기

// // 필드에 @Autowired를 붙인 경우,

// // 셋터를 통해 값을 넣는 것이 아니라,

// // 인스턴스 필드에 직접 값을 넣는다.

// // private 이라도 상관없다.

// // 따라서 셋터를 정의하지 않아도 된다.

// @Autowired

// private Engine engine;

여기에 엔진객체 주입이 없지만 engine 클래스에 Autowired붙어있어서 자동 주입된다.

private은 setter로 불러와야함. 하지만,,!

// => Reflection API 사용하면 private 멤버도 접근할 수 있다.

Field f = Car.class.getDeclaredField("model");

f.setAccessible(true); // private 멤버이지만 난 접근할래!!!

f.set(c2, "오호라2");

System.out.println(c2);

 

// 의존 객체 주입 자동화하기 - 생성자를 이용하여 의존 객체 주입

  // Spring IoC 컨테이너로부터 의존 객체를 주입 받고 싶다면,
  // 생성자에 파라미터를 선언하라.
  // @Autowired 는 붙일 필요가 없다. (붙여도 된다)
  // 주의!
  // => 이 일 또한 AutowiredAnnotationBeanPostProcessor 객체가 처리한다.
  //
  public Car(Engine engine) {
    System.out.println("Car(Engine)");
    this.engine = engine;
  }
  
  
  
      <!-- 생성자를 통해 의존 객체 주입하기
      => @Autowired 나 @Resource를 사용할 필요가 없다.
      => 스프링 전문가들 사이에서는 이 방식을 권고하기도 한다.
         왜?
         생성자의 파라미터로 선언하면 해당 의존 객체가 필수 항목이 된다.
         즉 그 의존 객체없이 생성자를 호출할 수  없기 때문이다.
      => 파라미터를 받는 다른 생성자를 호출하여 의존 객체를 자동주입하려면 다음 객체를 등록해야 한다.
         AutowiredAnnotationBeanPostProcessor
    -->

    <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>

// 의존 객체 주입 자동화하기 - 필수 의존 객체와 선택 의존 객체

@Autowired의 required 값은 기본이 true이다.

=> 즉 의존객체 주입이 필수사항이다.

해당하는 의존 객체가 없으면 예외가 발생한다.

=> 선택사항으로 바꾸고 싶으면 false로 설정하라!

=> required를 false로 설정하면 해당 객체가 없더라도 오류가 발생하지 않는다.

 

// 의존 객체 주입 자동화하기 - 같은 타입의 의존 객체가 여러개 있을 때

  @Autowired
  @Qualifier("e2")
  // 의존 객체가 여러 개 있을 경우, 주입할 의존 객체의 이름을 지정하라!
  // 주의!
  // @Qualifier 애노테이션을 처리할 BeanPostProcessor를 등록해야 한다.
  private Engine engine;
<!-- 
      클래스에 붙은 특정 애노테이션을 처리할 BeanPostProcessor 등록하기
         @Autowired => AutowiredAnnotationBeanPostProcessor
         @Qualifier => ?
         @Resources => ?
         @...       => ?
         위와 같이 특정 애노테이션을 처리하고 싶다면 
         그 애노테이션을 처리할 객체를 등록해야 한다.
         문제는, 
         각각의 애노테이션에 대해 어떤 클래스가 처리하는지 암기를 해야하고,
         또한 다음 AutowiredAnnotationBeanPostProcessor의 경우와 같이 
         <bean> 태그를 이용하여 그 객체를 등록해야 한다.
      => 결론! 
         매우 번거롭고 불편하다.
         그래서 스프링 프레임워크는 이런 개발자의 어려움을 덜어주고자
         애노테이션을 처리할 클래스를 자동 등록하는 특별한 단축 태그를 제공한다. 
      => <annotation-config> 태그
         이 태그를 선언하면,
         스프링 IoC 컨테이너는 
         애노테이션 처리와 관련된 BeanPostProcessor 들을 자동으로 생성할 것이다.
         개발자가 일일이 BeanPostProcessor를 등록할 필요가 없다.
         따라서 개발자는 각각의 애노테이션을 처리할 BeanPostProcessor의 이름을 
         암기할 필요가 없어서 편하다!
         이 태그는 context 네임스페이스 들어 있다. 
         이 태그를 사용하려면 먼저 context 네임스페이스를 선언해야 한다.
    -->
    <!--  
    <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
    -->
    
    <context:annotation-config/>
    
    <!-- 같은 타입(Engine)의 의존 객체가 여러 개 있을 때? 
       => 어떤 것을 꼽아야 할 지 알 수 없기 때문에 Car 객체를 생성하지 못한다. 오류 발생!
       => 해결책! 
          @Qualifier("객체이름")을 사용하여 어떤 객체를 꼽을 것인지 지정하라!

// 의존 객체 주입 자동화하기 - @Resource = @Autowired + @Qualifier

  // => 이 애노테이션은 스프링 프레임워크가 아닌 자바에서 제공한다.
  // => 자바 기본 라이브러리에 포함되어 있지 않다.
  // => 따로 라이브러리를 다운로드 받아 포함시켜야 한다.
  // => search.maven.org 에서 'javax.annotation'으로 검색하라.
  //    1.3.2 이상의 버전 사용.
  @Resource(name = "e1")
  //  @Autowired
  //  @Qualifier("e1")

// 객체 자동 생성 - @Component 애노테이션

// @Component
// => 스프링 IoC 컨테이너는 이 애노테이션이 붙은 클래스에 대해 객체를 자동 생성한다.
// 문법:
//      @Component(value="객체이름")
//      @Component("객체이름")
// 만약 다음과 같이 객체의 이름을 생략하면
// 클래스 이름을 객체 이름으로 사용한다.
//      예) bitcamp.java106.step09.Car => "car"
// 즉 클래스 이름에서 첫 알파벳을 소문자로 한 이름을
// 객체 이름으로 사용한다.
//
@Component
public class Car {
  String model;
  String maker;
  int cc;
  boolean auto;
  Date createdDate;
  Engine engine;

  // 의존 객체는 생성자에서 주입하는 것이 좋다.
  // 의존 객체라는 말에서 이미 그 객체없이는 작업을 수행할 수 없다는 의미이기 때문에
  // 보통 필수 객체이다.
  // 따라서 생성자에서 필수 객체를 받게 하는 것이 유지보수에 좋다.
  // 즉 의존 객체없이 해당 객체를 생성하는 일을 방지할 수 있기 때문이다.
  public Car(Engine engine) {
    this.engine = engine;
  }

applicaiont-context

   
    <!-- 애노테이션을 처리할 도우미 객체를 등록한다. -->
    <context:annotation-config/>
    
    <!-- 객체를 생성하기 위해 bean 태그를 사용하지 않고도
         객체를 자동 생성할 수 있다.
         방법은?
         클래스 선언에 @Component 애노테이션을 붙이는 것이다.
         단 이 애노테이션을 처리할 객체를 등록해야 한다.
    -->
    <!-- component-scan 태그는 @Component, @Service, @Repository, @Controller 
         애노테이션이 붙은 클래스를 찾아서 객체를 자동 생성시키도록 명령한다.
       => base-package 속성 
          어느 패키지의 있는 클래스를 찾아서 등록할 것인지 지정하는 속성이다.
       => @Component : 일반 클래스에 대해 붙인다.
       => @Repository : DAO 역할을 수행하는 클래스에 대해 붙인다.
       => @Service : 비즈니스 로직을 수행하는 클래스에 대해 붙인다.
       => @Controller : MVC 구조에서 컨트롤러 역할을 하는 클래스에 대해 붙인다.
       => @RestController : MVC 구조에서 REST API 컨트롤러 역할을 하는 클래스에 대해 붙인다.
       이렇게 역할에 따라 애노테이션으로 클래스를 분류해두면 나중에 통제하기가 편하다. 
    -->
     
    <context:component-scan base-package="com.eomcs.spring.ioc.ex09"/>

<context:annotation-config> 태그 생략하기

    <context:component-scan base-package="com.eomcs.spring.ioc.ex09"/>
    
    <!-- component-scan 태그를 추가하면 
         내부적으로 annotation-config 태그가 자동으로 추가된다. 
         따라서 다음과 같이 생략해도 된다. -->
<!-- 
    <context:annotation-config/> 
-->

// 객체 자동 생성 - 특정 패키지의 클래스에 대해 객체 생성하지 않기 exclue

   <context:component-scan base-package="com.eomcs.spring.ioc.ex09">
        <!-- 다음 패키지의 클래스 중에서 @Component,@Service,@Controller,@Repository
             애노테이션이 붙은 것은 객체를 생성한다. -->
        <context:include-filter type="regex" 
            expression="com.eomcs.spring.ioc.ex09.p2.Service2"/>
        
        <!-- 특정 패키지의 특정 클래스를 객체 생성 대상에서 제외하기  -->
        <context:exclude-filter type="regex" 
            expression="com.eomcs.spring.ioc.ex09.p2.Service1"/>
        
        <!-- 특정 애노테이션이 붙은 클래스는 객체 생성에서 제외시킨다. -->
        <context:exclude-filter type="annotation" 
            expression="org.springframework.stereotype.Controller"/>
            
        <!-- 특정 패키지만 제외하기 -->
        <context:exclude-filter type="regex" 
            expression="com.eomcs.spring.ioc.ex09.p4.*"/>
            
        <!-- 특정 패키지에서 지정된 패턴의 이름을 가진 클래스를 제외하기 -->
        <context:exclude-filter type="regex" 
            expression="com.eomcs.spring.ioc.ex09.p5.*Truck"/>
    </context:component-scan>

----

xml 탈출

// 클래스를 이용하여 스프링 설정하기

public class Exam01 {

  public static void main(String[] args) {
    ApplicationContext iocContainer = new ClassPathXmlApplicationContext(//
        "com/eomcs/spring/ioc/ex09/a/application-context.xml");

    SpringUtils.printBeanList(iocContainer);
  }

}

에서 변함


  public static void main(String[] args) {
    ApplicationContext iocContainer =
        new AnnotationConfigApplicationContext(AppConfig.class);

    SpringUtils.printBeanList(iocContainer);
  // @Component와 같은 애노테이션을 사용할 수 없는 경우
  // Java Config 에서 수동으로 객체를 생성할 수 있다.
  // 방법:
  // 1) 객체를 생성하여 리턴하는 메서드를 정의한다.
  // 2) 그리고 그 메서드에 @Bean 애노테이션을 붙인다.
  //
  // @Bean 애노테이션을 붙이면,
  // 스프링 IoC 컨테이너(AnnotationConfigApplicationContext)는
  // 해당 메서드를 호출하고,
  // 그 메서드가 리턴한 객체를 컨테이너에 보관한다.
  // 컨테이너에 보관할 때 사용할 객체 이름은
  // @Bean(객체이름) 애노테이션에 설정된 이름을 사용한다.
  // 만약 @Bean 애노테이션에 이름이 없으면,
  // 메서드 이름을 객체 이름으로 사용한다.
  //
  @Bean("car") // 애노케이션에 지정한 이름으로 리턴 값을 보관한다.
  public Car getCar2() {
    Car c = new Car(null);
    c.setMaker("비트자동차");
    c.setModel("티코");
    c.setCc(890);
    c.setAuto(true);
    return c;
  }

  @Bean // 이름을 지정하지 않으면 메서드 이름을 사용하여 저장한다.
  public Car getCar() {
    Car c = new Car(null);
    c.setMaker("비트자동차");
    c.setModel("티코");
    c.setCc(890);
    c.setAuto(true);
    return c;
  }

  // 실무에서는 스프링 설정용으로 사용하는 클래스에서
  // 객체를 리턴하는 메서드를 만들 때
  // 그 메서드의 이름을 객체 이름과 같게 짓는다.
  // => 보통 어떤 값을 리턴할 때는 getXxx()라는 이름으로 메서드를 만드는데,
  //    이처럼 객체이름으로 사용할 수 있도록 메서드를 만드는 경우도 있으니
  //    당황하지 말라!
  @Bean
  public Car car2() {
    Car c = new Car(null);
    c.setMaker("비트자동차");
    c.setModel("티코");
    c.setCc(890);
    c.setAuto(true);
    return c;
  }

// 클래스를 이용하여 스프링 설정하기 - @Configuration 애노테이션

// AppConfig 클래스가 스프링 설정 정보를 갖고 있는 클래스임을 선포한다!
// 그러면 AnnotationConfigApplicationContext 에서
// 이 클래스를 찾아 적절한 작업을 수행할 것이다.
//
// => AnnotationConfigApplicationContext 컨테이너에
// Java config 클래스를 직접 지정할 경우에는
// 굳이 @Configuration 애노테이션을 붙일 필요가 없다.
// 예) ApplicationContext iocContainer =
// new AnnotationConfigApplicationContext(AppConfig1.class);
//
// => 그런데 다음과 같이 컨테이너에
// Java config 클래스를 직접 알려주지 않을 경우에는,
// 예) ApplicationContext iocContainer =
// new AnnotationConfigApplicationContext("com.eomcs.spring.ioc.ex10");
//
// 이 클래스가 Java config 클래스임을 표시해야만 컨테이너가 알 수 있다.
// Java config 클래스임을 표시할 때 붙이는 애노테이션이
// 바로 @Configuration 이다.

  


// @ComponentScan
// => <context:component-scan/> 태그와 같은 일을 한다.
//
// 사용법1:
// => 한 개의 패키지를 지정하기
//@ComponentScan(basePackages = {"com.eomcs.spring.ioc.ex11"})

// => 배열 항목이 한 개일 경우 중괄호({}) 생략 가능
@ComponentScan(basePackages = "com.eomcs.spring.ioc.ex11")

// 사용법2:
// => 여러 개의 패키지 지정하기
//@ComponentScan(basePackages = {
//    "com.eomcs.spring.ioc.ex11.p1",
//    "com.eomcs.spring.ioc.ex11.p2",
//    "com.eomcs.spring.ioc.ex11.p3"
//})

// 사용법3:
// => 특정 패키지나 클래스 제외하기
//@ComponentScan(
//    basePackages = "com.eomcs.spring.ioc.ex11",
//    excludeFilters = {
//        @ComponentScan.Filter(
//            type = FilterType.REGEX,
//            pattern = "com.eomcs.spring.ioc.ex11.p2.*"
//            ),
//        @ComponentScan.Filter(
//            type = FilterType.ANNOTATION,
//            value = org.springframework.stereotype.Controller.class
//            )
//    })
// 위의 설정은 XML에서 다음과 같다.
//<context:component-scan base-package="com.eomcs.spring.ioc.ex11">
//  <context:exclude-filter type="regex"
//    expression="com.eomcs.spring.ioc.ex11.p2.*"/>
//  <context:exclude-filter type="annotation"
//    expression="org.springframework.stereotype.Controller"/>
//</context:component-scan>


public class AppConfig {
  @Bean
  public Car car2() {
    Car c = new Car(null);
    c.setMaker("비트자동차");
    c.setModel("티코");
    c.setCc(890);
    c.setAuto(true);
    return c;
  }
}