반응형

spring

spring #ex01

        // IoC(Inversion Of Control) 컨테이너 // bean container // 인스턴스의 생성과 관리를 담당한다.

        // 각 객체가 의존하는 객체(dependency)를 주입 // "의존 객체 주입(dependency injection; DI)"이라 부른다.

        // "DI 컨테이너"라고도 부른다. 

        // Spring IoC 컨테이너 // spring.io 사이트에서 제공하는 프레임워크

        // 프로젝트에 Spring IoC 컨테이너 포함하기 // 

        // mvnmvnrepository.com 또는 search.maven.org 접속 - 'spring context' 검색

        // org.springframework:spring-context // 버전 클릭 // Gradle Groovy DSL 복사

        // - 라이브러리 정보를 dependencies {} 블록에 추가 - 'gradle cleanEclipse' - 'gradle eclipse'

        // ApplicationContext 인터페이스 // 스프링 IoC 컨테이너의 사용 규칙을 정의한 인터페이스

        // 모든 스프링 IoC 컨테이너는 이 규칙에 따라 IoC 컨테이너가 정의되어 있다.

        // ApplicationContext 구현체 (implements, 인터페이스를 구현한 클래스 또는 그 클래스의 인스턴스)의 종류

        // XML 파일에서 설정 정보를 읽어들이는 IoC 컨테이너

        // ClassPathXmlApplicationContext // 설정 파일을 자바 CLASSPATH 경로에서 찾는다.

        // FileSystemXmlApplicationContext // 설정 파일을 OS 경로에서 찾는다.

        // 자바 클래스 파일의 애노테이션에서 설정 정보를 읽어 들이는 IoC 컨테이너

        // AnnotationConfigApplicationContext // 설정 정보를 자바 클래스에서 찾는다.

        // 설정파일 // a 폴더 안에 applicaion context.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans.xsd">
  
</beans>

a

Exam01 -> 1. 자바 CLASSPATH 에서 설정 파일을 찾는 IoC 컨테이너 // 스프링을 초기화 시키는 방법 3가지

        // ApplicationContext iocContainer1 = new ClassPathXmlApplicationContext(

        // "com/eomcs/spring/ioc/ex01/a/application-context.xml");

        // 자바 CLASSPATH // 즉, JVM이 자바 클래스 파일(.class)을 로딩하기 위해 찾는 경로이다.

        // JVM을 실행할 때 -classpath 옵션이나 -cp 옵션으로 경로를 지정한다.

        // JVM이 클래스 파일을 찾을 JVM의 기본 경로($JAVA_HOME/lib)를 가장 먼저 뒤진다.

        // 파일 경로이기 때문에 패키지와 패키지 사이에는 . 대신에 /를 사용해야 한다.

        // java 파일일 경우에는 .을 사용하고, 일반 파일인 경우에는 /를 사용한다.

        // 설정 파일이 패키지 파일 아래에 있다면 이 경우를 사용한다.

b

Exam01 -> 2. 운영체제의 파일 시스템에서 설정 파일을 찾는 IoC 컨테이너 // 스프링을 초기화 시키는 방법 3가지

        // ApplicationContext iocContainer2 = new FileSystemXmlApplicationContext(
        "file://C:/Users/heusw/git/bitcamp-study/bitcamp-java/src/main/java/com/eomcs/spring/ioc/ex01/b/application-context.xml");

        // 위 경로 넣고 실행했을 때 오류 발생함. // 설정 파일 경로를 지정할 때 직접 파일 시스템 경로를 지정해야 한다.

        // 설정 파일 경로를 지정할 때 URL 형식으로 지정해야 한다.

        // URL 형식에서는 파일 시스템을 가리킬 때 다음의 접두어를 붙인다. // ex) file://

      // 이클립스에서 Project Explorer - 마우스 오른쪽 - properties - Location에 나온 경로를 복사 붙혀넣기 하면 된다. 

c

Exam01 -> 3. 자바 class 파일의 애노테이션에서 설정 정보를 추출 // java config // 스프링을 초기화 시키는 방법 3가지

        // ApplicationContext iocContainer3 = new AnnotationConfigApplicationContext(AppConfig.class);

        // c패키지 안에 AppConfig.java가 존재해야 한다. // java config 라 부른다.

        // AppConfig // 클래스 선언부에 애노테이션으로 스프링 설정에 관한 정보를 지정할 수 있다.

        // 필드나 메서드로 스프링 관련 설정을 수행할 수 있다.

        // 생성자에 설정 정보를 갖고 있는 클래스의 타입 정보를 넘긴다. 

d

Exam01 -> IoC 컨테이너에 보관된 객체 확인하기 // a방법

        // application-context.xml로 스프링을 초기화 시켰다 // a방법

        // bean 갯수를 확인 시 0개 // 객체가 아무것도 들어있지 않다

        // iocContainer.getBeanDefinitionCount(); // iocContaier 객체의 bean의 갯수 꺼내는 메소드

        // getBeanDefinitionNames(); // iocContaier bean의 이름을 String 배열로 받아온다.

Exam02 -> IoC 컨테이너에 보관된 객체 확인하기 // c방법

        // AnnotationConfigApplicationContext으로 스프링을 초기화 시켰으면 // c방법

        // bean 갯수 5개 // e처럼 코드를 추가하지 않았음에도, 애노테이션을 처리할 기본적인 객체들이 들어 있다.

        // 5개에는 appConfig에 대한 객체도 포함되어 있다.

e

Exam01 -> IoC 컨테이너에 객체 생성하고 보관기 1 // a방법 

        // <bean id="c1" class="com.eomcs.spring.ioc.ex01.Car"/> // application-context.xml 객체 생성 코드 추가 

        // bean 갯수 1개 // 위에 객체 생성 코드로 인한 갯수 1개

f

Exam01 -> IoC 컨테이너에 객체 생성하고 보관 2 // c방법

public class AppConfig {
  @Bean
  public Car c1() {
    return null;
  }
}

        // AppConfig에 Car 객체를 생성한다. // @Bean 애노테이션을 꼭 붙혀야 한다. // c방법

        // bean 갯수 6개 // 기본 5개에 위에 객체 생성으로 인한 갯수 1개 추가로 총 6개

g

Exam01 -> IoC 컨테이너에서 객체 꺼내기

        // 1. 객체 이름으로 꺼내기 // System.out.println(iocContainer.getBean("c1"));

        // 2. 객체 타입으로 꺼내기 // System.out.println(iocContainer.getBean(Car.class));

Exam02 -> IoC 컨테이너에서 객체 꺼내기 // 예외 발생

        // 존재 않는 객체 꺼내기 // System.out.println(iocContainer.getBean("c2"));

        // NoSuchBeanDefinitionException 예외 발생 // null을 리턴하는게 아니라 예외가 발생한다.

 

spring #ex02

a

Exam01 -> <bean> 태그 사용법

    <bean id="c1" class="com.eomcs.spring.ioc.ex02.Car"></bean>
    <bean id="c2" class="com.eomcs.spring.ioc.ex02.Car"/>     

        // <bean> id // 생성된 객체를 컨테이너에 보관할 때 사용할 key

        // class // 생성할 객체의 클래스 정보. // fully-qualified class name(FQName, QName) 이어야 한다.

        // 시작 태그와 끝 태그 사이에 내용이 없다면 끝 태그를 생략할 수 있다. // 두번째 c2 뒤에 말하는 것.

        // 단, 생략을 표시하기 위해 반드시 시작태그의 끝에 /을 붙여라 // c2 생성 코드 마지막은 />인걸 말하는 것.

b

Exam01 -> 빈의 이름을 지정하는 방법

        // <bean id="c1" class="com.eomcs.spring.ioc.ex02.Car"/> // 이름 출력시 c1

        // 1. id 부여// 빈의 이름을 의미

        // <bean id="c2" name="c3" class="com.eomcs.spring.ioc.ex02.Car"/> // 이름 출력시 c2

        // 2. name 추가 부여 // 빈의 별명을 의미

        // <bean name="c4" class="com.eomcs.spring.ioc.ex02.Car"/> // 이름 출력시 c4

        // 3 name만 부여 // 빈id를 지정하지 않고 name만 지정하면 name이 id로 사용된다.

        // <bean id="c5" name="c51 c52 c53" class="com.eomcs.spring.ioc.ex02.Car"/> // 이름 출력시 c5

        // <bean id="c6" name="c61,c62,c63" class="com.eomcs.spring.ioc.ex02.Car"/> // 이름 출력시 c6

        // <bean id="c7" name="c71;c72;c73" class="com.eomcs.spring.ioc.ex02.Car"/> // 이름 출력시 c7

        // <bean id="c8" name="c81:c82:c83" class="com.eomcs.spring.ioc.ex02.Car"/> // 이름 출력시 c8

        // 4. name을 여러개 부여 // name 속성에 여러 개의 별명을 지정할 수 있다.

        // <bean name="c91 c92 c93" class="com.eomcs.spring.ioc.ex02.Car"/> // 이름 출력시 c91

        // 5. name만 여러개 부여 // id 없이 name에 여러 개의 별명을 지정할 때는 첫 번째 별명이 id로 사용된다.

Exam0210 -> 빈의 별명을 출력하는 방법 // id를 넘겨준다.

    String[] aliases = iocContainer.getAliases("c5");
    for (String alias : aliases) {
      System.out.println(alias);
    }

        // getAliases("id")를 통해 알아내는 방법.

Exam0220 -> 빈의 별명을 출력하는 방법 // id만 설정된 경우 // 별명이 없을 경우

    String[] aliases = iocContainer.getAliases("c1");
    for (String alias : aliases) {
      System.out.println(alias);
    }

        // 아무것도 출력되지 않는다.

Exam0230 -> 빈의 별명을 출력하는 방법 // name 하나만 설정된 경우 // id가 없을 경우

    String[] aliases = iocContainer.getAliases("c4");
    for (String alias : aliases) {
      System.out.println(alias);
    }

        // 아무것도 출력되지 않는다. // name만 설정한 경우, 첫 번째 id로 사용한다. 

        // 두 번째 이상의 name이 설정 되지 않는 경우 name이 없다고 판단하여 아무것도 출력하지 않는다.

Exam0240 -> 빈의 별명을 출력하는 방법 // name만 여러개 설정된 경우 // id가 없을 경우

    String[] aliases = iocContainer.getAliases("c91");
    for (String alias : aliases) {
      System.out.println(alias);
    }

        // 두 번째 이상의 name이 설정 되었다면, 두 번째부터의 name이 출력 된다.

Exam0250 -> 빈의 별명을 출력하는 방법 // name만 여러개 설정된 경우 // id가 없을 경우

        // <bean name="c81:c82:c83" class="com.eomcs.spring.ioc.ex02.Car"/> // 이름 출력시 c81:c82:c83

        // name 속성에 여러 개의 별명을 입력할 때 공백, 콤마(,), 세미콜론(;)을 사용할 수 있다. 

        // name="c81:c82:c83"의 경우 별명이 세개가 지정 된 것이 아닌, c81:c82:c83 자체가 별명이 된 것이다.

c

Exam01 -> 빈 생성 정책

        // scope 속성에 빈의 생성 정책을 지정할 수 있다.

    <bean id="c1" class="bitcamp.java106.step02.Car" />
    <bean id="c2" class="bitcamp.java106.step02.Car" scope="singleton"/>

        // singleton // 한 개의 객체만 생성. 지정하지 않으면 기본이 singleton이다. 

        // scope 속성의 기본 값은 singleton // singleton 객체는 IoC 컨테이너가 생성될 때 미리 준비된다.

    <bean id="c3" class="com.eomcs.spring.ioc.ex02.Car" scope="prototype"/>

        // prototype // getBean() 호출할 때마다 생성

        // request // (웹) 요청이 들어올 때마다 생성       

        // session: // (웹) 세션이 생성될 때마다 생성

    String[] names = iocContainer.getBeanDefinitionNames();
    for (String name : names) {
      System.out.println(name);
    }

        // bean이 생성되지 않았더라도, bean의 이름은 모두 등록이 되어 있다. // c3 말하는 것

Exam02 -> 빈 생성 정책 // singleton

    Car obj1 = (Car) iocContainer.getBean("c1");
    Car obj2 = (Car) iocContainer.getBean("c2");
    Car obj3 = (Car) iocContainer.getBean("c3");

    System.out.println(obj1 == obj2);
    System.out.println(obj1 == obj3);
    System.out.println(obj2 == obj3);

        // Sysout의 결과는 모두 true이다. // obj1, obj2, obj3은 모두 같은 객체다

        // singleton으로 설정된 객체는 하나만 생성이 된다. // getBean()을 여러번 호출해도 하나만 생성이 된다.

Exam03 -> 빈 생성 정책 // prototype

    Car obj1 = (Car) iocContainer.getBean("c3");
    Car obj2 = (Car) iocContainer.getBean("c3");
    Car obj3 = (Car) iocContainer.getBean("c3");

    System.out.println(obj1 == obj2);
    System.out.println(obj1 == obj3);
    System.out.println(obj2 == obj3);

        // Sysout의 결과는 모두 false이다. // obj1, obj2, obj3은 모두 다른 객체다

        // prototype으로 설정된 객체는 getBean() 호출할 때마다 생성이 된다. // 특별한 경우가 아니면 사용하지 않는다.

        // 객체가 계속 생성되기 때문에 가비지가 많이 발생할 수 있다.

        // 그래서 IoC 컨테이너는 singleton 방식으로 객체를 생성한다.

d

Exam01 -> 빈 생성 정책 // 익명 객체

    <bean class="com.eomcs.spring.ioc.ex02.Car"/>
    <bean class="com.eomcs.spring.ioc.ex02.Car"/>
    <bean class="com.eomcs.spring.ioc.ex02.Car"/>
    <bean class="com.eomcs.spring.ioc.ex02.Car"/>
    <bean class="com.eomcs.spring.ioc.ex02.Engine"/>
    <bean class="com.eomcs.spring.ioc.ex02.Engine"/>
    <bean class="com.eomcs.spring.ioc.ex02.Engine"/>

        // application-context.xml에 익명 객체를 추가하고 이름을 출력해보면 출력하면 다음과 같다. // 출력결과다.

com.eomcs.spring.ioc.ex02.Car#0
com.eomcs.spring.ioc.ex02.Car#1
com.eomcs.spring.ioc.ex02.Car#2
com.eomcs.spring.ioc.ex02.Car#3
com.eomcs.spring.ioc.ex02.Engine#0
com.eomcs.spring.ioc.ex02.Engine#1
com.eomcs.spring.ioc.ex02.Engine#2

        // FQName#인덱스번호 // com/eomcs/spring/ioc/ex02.Car#0 

        // 빈의 이름을 지정하지 않을 경우 FQName과 인덱스 번호가 객체의 이름으로 사용된다. 

        // 익명 객체의 수 만큼 인덱스 번호가 증가한다. // 0번 익명 객체의 별명은 클래스명과 같다.

        // com/eomcs/spring/ioc/ex02.Car#0 이름을 가진 익명 객체의 별명은 com/eomcs/spring/ioc/ex02.Car 이다.

        // 그외 익명 객체는 별명이 붙지 않는다. // 인덱스 번호는 클래스마다 0부터 시작한다.

Exam02 -> 빈 생성 정책 // 익명 객체의 별명

        // SpringUtils.printBeanAliases(iocContainer, "com.eomcs.spring.ioc.ex02.Car#0"); // Car#0의 별명 출력

        // SpringUtils.printBeanAliases(iocContainer, "com.eomcs.spring.ioc.ex02.Car#1"); // Car#1의 별명 출력

        // Car#0의 별명은 com.eomcs.spring.ioc.ex02.Car이다. // Car#1의 별명은 별명이 없다.

        // 같은 클래스에 대해 첫 번째 익명 객체만 별명을 갖고, 두번째 익명 객체부터는 별명이 없다.

 

spring #ex03

a

Exam01 -> 호출할 생성자 지정1

    <bean id="c1" class="com.eomcs.spring.ioc.ex03.Car"/>
    <bean id="c2" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg>
            <value>티코</value>
        </constructor-arg>
    </bean>
    
    <bean id="c3" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg>
            <value>1980</value>
        </constructor-arg>
    </bean>
    
    <bean id="c4" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg>
            <value type="int">1980</value>
        </constructor-arg>
    </bean>
    
    <bean id="c5" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg>
            <value type="java.lang.String">소나타</value>
        </constructor-arg>
        <constructor-arg>
            <value type="int">1980</value>
        </constructor-arg>
    </bean>
    <bean id="c6" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg>
            <value type="int">1980</value>
        </constructor-arg>
        <constructor-arg>
            <value type="java.lang.String">소나타</value>
        </constructor-arg>
    </bean>
    
    <bean id="c7" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg name="cc">
            <value type="int">1980</value>
        </constructor-arg>
        <constructor-arg name="model">
            <value type="java.lang.String">소나타</value>
        </constructor-arg>
    </bean>
    <bean id="c8" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg name="model">
            <value type="java.lang.String">소나타</value>
        </constructor-arg>
        <constructor-arg name="cc">
            <value type="int">1980</value>
        </constructor-arg>
    </bean>
    
    <bean id="c9" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg index="0">
            <value type="java.lang.String">소나타</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value type="int">1980</value>
        </constructor-arg>
    </bean>
    <bean id="c10" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg index="0">
            <value type="int">1980</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value type="java.lang.String">소나타</value>
        </constructor-arg>
    </bean>

        // c1 // 생성자의 파라미터 값을 주지 않으면 기본 생성자가 호출

        // c2 //  파라미터 값을 설정하면 그 값에 맞는 생성자가 선택되어 호출

        // <value>티코</value> // 숫자, 문자 상관 없이 <value> 태그 안에 설정하면 된다.

        // c3 // 한 개의 파라미터 값을 받는 생성자가 여러 개 있을 경우

        <value>1980</value> // typr으로 넘겨주지 않으면 무조건 String 타입의 값을 받는 생성자가 우선 선택

        // c4 // 한 개의 파라미터를 가지는 생성자가 여러 개 있을 경우

       // <value type="int">1980</value> // 특정 생성자를 지정하고 싶다면 파라미터의 타입을 지정한다. // 

        // c5, c6 // 파라미터가 여러 개인 생성자를 호출할 경우 IoC 컨테이너가 가장 적합한 생성자를 찾아 호출한다.

        // c5는 (String,int)를 파라미터로 받는 생성자로, c6은 (int, String)를 파라미터로 받는 생성자를 호출하고 싶어도

        // c5와 c6 모두 (String,int)를 파라미터로 받는 생성자를 호출한다. // IoC 컨테이너는 String을 우선시 한다.

       // c7, c8 // 파라미터의 값을 설정할 때 이름을 지정해도 개발자가 임의로 특정 생성자를 호출하게 제어할 수 없다.

        // constructor-arg name="model" // 이렇게 지정해도 컨테이너가 맘대로 결정한다.

        // c9, c10 // constructor-arg index="1" // index 번호를 지정하면 임의로 특정 생성자를 호출 할 수 있다.

b

Exam01 -> 호출할 생성자 지정2

<bean id="c1" class="com.eomcs.spring.ioc.ex03..Car">
        <constructor-arg type="java.lang.String" value="티코"/>
    </bean>
    
    <bean id="c2" class="com.eomcs.spring.ioc.ex03..Car">
        <constructor-arg index="0" type="java.lang.String" value="티코"/>
        <constructor-arg index="1" type="int" value="890"/>
    </bean>
    
    <bean id="c3" class="com.eomcs.spring.ioc.ex03..Car">
        <constructor-arg index="0" value="티코"/>
        <constructor-arg index="1" value="890"/>
    </bean>
    
    <bean id="c4" class="com.eomcs.spring.ioc.ex03..Car">
        <constructor-arg index="0" value="티코"/>
        <constructor-arg index="1" value="aaa"/>
    </bean>
</beans>

        // c1 // constructor-arg type을 지정하고 value를 지정한다.

        // c2 // index로 파라미터 순서를 지정한다. // 위의 c9, c10이랑 다른 점은 c2는 한번에 다 정한다는 점이다.

        // c9, c10은 각자 따로따로 인덱스 지정, value지정하는 방식이다.

        // c3 // IoC 컨테이너가 알아서 value 값을  형변환을 통해 파라미터로 넣는다. // 원래 value는 문자열이다.

c

Exam01 -> 호출할 생성자 지정2 // 예외발생 

        // c4 // index 1의 경우에 파라미터가 int로 받는데, value "aaa"는 int로 형변환이 불가능하다. // 오류발생

        // 원래 b 예제에 포함되어 있었는데 c로 따로 빠지게 됨, 그래서 c4이름을 가지고 있는 것.

d

Exam01 -> 호출할 생성자 지정3

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:c="http://www.springframework.org/schema/c"
    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="c1" class="com.eomcs.spring.ioc.ex03.Car" c:model="티코"/>
    <bean id="c2" class="com.eomcs.spring.ioc.ex03.Car" c:cc="1980"/>
    <bean id="c3" class="com.eomcs.spring.ioc.ex03.Car" c:model="티코" c:cc="890"/>
    <bean id="c4" class="com.eomcs.spring.ioc.ex03.Car" c:_1="티코" c:_0="890"/>
</beans>

        // 생성자의 파라미터 값을 지정할 때 constructor-arg 태그가 아닌 bean 태그의 속성 값으로 지정할 수 있다. 

       // 단, beans 태그의 선언부에 다음 설정을 추가해야 한다. //xmlns:c="http://www.springframework.org/schema/c"

        // c:파라미터명="값" // 이 방식으로는 타입을 지정할 수 없다.

        // IoC 컨테이너에게 적절한 생성자를 호출하도록 맡겨야 한다.

        // c:_인덱스번호="값" // 순서를 지정할 수는 있다.

 

spring #ex04

a

Exam01 -> 프로퍼티 값 지정

Exam02 -> 프로퍼티 값 지정한거 확인

    <bean id="c1" class="com.eomcs.spring.ioc.ex04.Car">
        <property name="model"><value type="java.lang.String">티코1</value></property>
        <property name="maker"><value type="java.lang.String">비트자동차</value></property>
        <property name="cc"><value type="int">890</value></property>
    </bean>
    
    <bean id="c2" class="com.eomcs.spring.ioc.ex04.Car">
        <property name="model"><value>티코2</value></property>
        <property name="maker"><value>비트자동차</value></property>
        <property name="cc"><value>890</value></property>
    </bean>
    
    <bean id="c3" class="com.eomcs.spring.ioc.ex04.Car">
        <property name="model" value="티코3"/>
        <property name="maker" value="비트자동차"/>
        <property name="cc" value="890"/>
    </bean>
              
</beans>

        // Exam01과 Exam02는 같은 application-context.xml을 호출해서, Exam02에 print문 추가한거라 묶어서 적어둠,

        // c1 // 프로퍼티 설정, 셋터 호출하는 방법

        // c2 // c1에서 type을 생략한 것 // IoC 컨테이너가 String을 프로퍼티의 타입에 맞춰서 자동 형변환한다.

        // c3 // value 태그 대신에 property 태그의 value 속성으로 값을 지정할 수 있다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p"
    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="c4" class="com.eomcs.spring.ioc.ex04.Car"
          p:model="티코4" p:maker="비트자동차" p:cc="890"/>
          
</beans>

        // c4 // property 태그 대신에 bean의 속성으로 프로퍼티 값을 설정할 수 있다.

        // xmlns:별명="http://www.springframework.org/schema/p" // bean 속성을 사용하려면 태그에 선언 추가 필요

        // xmlns:p="http://www.springframework.org/schema/p" // ex1 p:프로퍼티명="값"

        // xmlns:okok="http://www.springframework.org/schema/p" // ex2 p:프로퍼티명="값"

        // xmlns:nono="http://www.springframework.org/schema/p" // ex3 p:프로퍼티명="값"

        // 혹여나 xlmns:값으로 인식할까봐 같은 예제 3개를 넣은 것.

b

Exam01 -> 프로퍼티 값 자동 형변환 // 오류발생

    <bean id="c2" class="com.eomcs.spring.ioc.ex04.Car">
        <property name="model" value="티코3"/>
        <property name="maker" value="비트자동차"/>
        <property name="cc" value="aaa"/>
    </bean>

        // "cc"에는 int값을 받는데, String "aaa"를 집어넣으면 오류가 발생한다.

        // 정확하게 말하면, xml에 작성되는 모든 것은 String이고, cc의 값 설정이 int로 되어 있어

        // String을 자동으로 int로 형변환 해주는 것이다. // 근데 "aaa"가 int 값이 아니라 오류가 나는 것.

        // 자동 형변환은 primitive type에 대해서만 가능하다. // 그 외에 대해서는 문자열을 자동 형변환하지 않는다.

        // 형변환하고 싶으면 개발자가 형변환시키는 클래스를 만들어 스프링 프레임워크에 등록해야 한다.

c

Exam01 -> 프로퍼티에 객체 주입하기

    <bean id="e1" class="com.eomcs.spring.ioc.ex04.Engine">
        <property name="maker" value="비트자동차"/>
        <property name="valve" value="16"/>
        <property name="cylinder" value="8"/>
    </bean>
    
    <bean id="e2" class="com.eomcs.spring.ioc.ex04.Engine">
        <property name="maker" value="캠프자동차"/>
        <property name="valve" value="8"/>
        <property name="cylinder" value="4"/>
    </bean>
    
    <bean id="c1" class="com.eomcs.spring.ioc.ex04.Car">
        <property name="model" value="티코A"/>
        <property name="maker" value="비트자동차"/>
        <property name="cc" value="890"/>
        <property name="engine" ref="e1"/>
    </bean>

        // e1, e2, c1 처럼 property name과 value를 이용해서 값을 넣을 수도 있다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p"
    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="c2" class="com.eomcs.spring.ioc.ex04.Car"
          p:model="티코" 
          p:maker="비트자동차" 
          p:cc="890" 
          p:engine-ref="e2"/>
          
</beans>

        // c2처럼 p를 위에 설정하고 해당 명에 집어넣을 수도 있다.

        // p:프로퍼티명-ref="객체이름" // p 속성으로 프로퍼티에 객체를 주입할 때

d

Exam01 -> 프로퍼티 호출 // 객체 주입시 객체 생성 순서

    <bean id="e1" class="com.eomcs.spring.ioc.ex04.Engine">
        <property name="maker" value="비트자동차"/>
        <property name="valve" value="16"/>
        <property name="cylinder" value="8"/>
    </bean>
    
    <bean id="c1" class="com.eomcs.spring.ioc.ex04.Car">
        <property name="model" value="티코A"/>
        <property name="engine" ref="e1"/>
        <property name="maker" value="비트자동차"/>
        <property name="cc" value="890"/>
    </bean>
    

        // e1은 c1안에 들어가는 객체이다. // 그러나 e1을 먼저 호출하고 나중에 c1을 호출해도 된다.

        // 프로퍼티 값을 주입할 때

        // 1. 의존 객체가 생성되지 않은 상태라면 // 먼저 의존 객체를 생성한 후 프로퍼티 값을 주입한다.

        // 2. 의존 객체가 생성된 상태라면, // 그대로 프로퍼티 값을 주입한다.

        // 즉 e1이 먼저 실행되던, c1이 먼저 실행되던 상관 없다.

e

Exam01 -> 프로퍼티 호출 // 의존 객체 주입할 때 즉시 객체 생성

    <bean id="c1" class="com.eomcs.spring.ioc.ex04.Car">
        <property name="model" value="티코A"/>
        <property name="maker" value="비트자동차"/>
        <property name="cc" value="890"/>
        <property name="engine">
          <bean class="com.eomcs.spring.ioc.ex04.Engine">
            <property name="maker" value="비트자동차"/>
            <property name="valve" value="16"/>
            <property name="cylinder" value="8"/>
          </bean>
        </property>
    </bean>
    
        <bean id="c2" class="com.eomcs.spring.ioc.ex04.Car">
        <property name="model" value="소나타"/>
        <property name="maker" value="비트자동차"/>
        <property name="cc" value="1980"/>
        <property name="engine">
            <bean class="com.eomcs.spring.ioc.ex04.Engine">
                <property name="maker" value="비트자동차"/>
                <property name="valve" value="16"/>
                <property name="cylinder" value="8"/>
            </bean>
        </property>
    </bean>

        // bean안의 property의 name을 보고 알아서 property를 호출한다.

        // engine의 value대신, bean을 적고 해당 class를 나타낸 것이다 // 그리고 value 뒤에 >로 끝난다. />아니다.

        // />의 경우 끝났다는 의미기 때문에 engine에 있어서는 value가 들어와야되니깐 />를 적지 않는 것이다.

 

spring #ex05

a

Exam01 -> 컬렉션 타입 프로퍼티 값 설정 // 배열 프로퍼티 값 설정

        // Tire[] tires // Car.java 안에 Tire가 배열일 때

    <bean id="c1" class="com.eomcs.spring.ioc.ex05.Car">
        <property name="tires">
            <array>
                <bean class="com.eomcs.spring.ioc.ex05.Tire" 
                      p:maker="금호타이어" p:width="180"/>
                <bean class="com.eomcs.spring.ioc.ex05.Tire" 
                      p:maker="금호타이어" p:width="180"/>
            </array>
        </property>
    </bean>
    
    <bean id="c2" class="com.eomcs.spring.ioc.ex05.Car">
        <property name="tires">
                <bean class="com.eomcs.spring.ioc.ex05.Tire" 
                      p:maker="금호타이어" p:width="180"/>
                <bean class="com.eomcs.spring.ioc.ex05.Tire" 
                      p:maker="금호타이어" p:width="180"/>
            </list>
        </property>
    </bean>

        // <array>나 <list> 태그를 이용해 처리한다.

b

Exam01 -> 컬렉션 타입 프로퍼티 값 설정 // 배열 프로퍼티 값 설정

        // List<Tire> tires; // Car.java 안에 Tire가 list<>타입일 때

        // 사용법은 배열과 똑같다.

c

Exam01 -> 컬렉션 타입 프로퍼티 값 설정 // 배열 프로퍼티 값 설정

        // Map<String,Object> options // Map 타입 일 때

    <bean id="c1" class="com.eomcs.spring.ioc.ex05.c.Car">
        <property name="options">
            <map>
                <entry>
                    <key><value>sunroof</value></key>
                    <value>true</value>
                </entry>
                <entry key="auto" value="true"/>
                <entry key="spareTire"> 
                    <bean class="com.eomcs.spring.ioc.ex05.c.Tire" p:maker="비트타이"/>
                </entry>
                <entry key="engine" value-ref="e1"/>
            </map>
        </property>
    </bean>
    
    <bean id="e1" class="com.eomcs.spring.ioc.ex05.c.Engine" p:maker="비트자동차"/>  
</beans>

        // <entry> 태그 안에 <key><value>key 값</value></key> // 이렇게 사이에 key 값을 넣어야 한다.

        // <value> 값 </value> // 이렇게 사이에 value 값을 넣어야 한다.

        // 또는 <entry key="auto" value="true"/> // 이렇게 사이에 한번에 지정할 수 있다.

        // 또는 bean을 지정하여, 사용할 수도 있다.

d

Exam01 -> 컬렉션 타입 프로퍼티 값 설정 // 배열 프로퍼티 값 설정

        // Properties라는 값을 사용할 떄 // Car.java에서

    <bean id="c1" class="com.eomcs.spring.ioc.ex05.d.Car4">
        <property name="options">
            <props>
                <prop key="sunroof">true</prop>
                <prop key="auto">true</prop>
                <prop key="jdbc.username">java106</prop>
                <prop key="jdbc.password">1111</prop>
            </props>
        </property>
    </bean>

        // <props>라는 태그를 사용해서 값을 처리한다.

 

spring #ex06

a

Exam01 -> 팩토리 메서드 호출 // static 메서드 호출

        // IoC 컨테이너에서 팩토리 메서드를 사용하기.

    <bean id="c1" class="com.eomcs.spring.ioc.ex06.a.CarFactory"
          factory-method="create">
        <constructor-arg value="티코"/>
    </bean>
    
    <bean id="c2" class="com.eomcs.spring.ioc.ex06.a.CarFactory"
          factory-method="create">
        <constructor-arg value="소나타"/>
    </bean>
    
    <bean id="c3" class="com.eomcs.spring.ioc.ex06.a.CarFactory"
          factory-method="create">
        <constructor-arg value="오호라"/>
    </bean>

        // class="스태틱 메서드가 들어있는 클래스 이름" // factory-method="스태틱 메서드 이름"

        // Object obj = CarFactory.create("티코"); // objPool.put("c1", obj); // 자바코드로 치면 이렇게 된다.

        // c1이라는 이름은 CarFactory 객체가 아니라 create() 메서드가 만들어 리턴한 Car 객체이다.

b

Exam01 -> 팩토리 메서드 호출 // static 메서드 호출 응용

    <bean id="d1" class="java.sql.Date"
          factory-method="valueOf">
        <constructor-arg value="2018-05-04"/>
    </bean>

        // "yyyy-MM-dd" 형식의 문자열을 가지고 java.sql.Date 객체 만들기 

        // Date d1 = Date.valueOf("yyyy-MM-dd"); // 자바코드로 치면 이렇게 된다.

c

Exam01 -> 팩토리 메서드 호출 // 인스턴스 메서드 호출

<bean id="carFactory" class="com.eomcs.spring.ioc.ex06.c.CarFactory"/>
    <bean id="c1" factory-bean="carFactory"
          factory-method="create">
        <constructor-arg value="SM5"/>
    </bean>

 

        // factory-bean="공장역할을 수행하는 객체이름" // factory-method="인스턴스 메서드 이름"

        // factory-bean 속성을 설정하면 factory-method는 스태틱 메서드가 아니라 인스턴스 메서드를 가리키게 된다.

        // CarFactory2 carFactory = new CarFactory2(); // Object obj = carFactory.create("SM5");

        // objPool.put("c1", obj); // 자바코드로 치면 이렇게 된다.

        // 인스턴스 메서드의 경우 static 메서드와는 다르게 id와 class를 먼저 넘겨 Factory 메서드 객체를 만들어야한다.

        // 그 후, factory-bean 값을 넘겨주어 Car 객체를 생성한다.

        // c2이라는 이름은 CarFactory 객체가 아니라 create() 메서드가 만들어 리턴한 Car 객체이다.

d

Exam01 -> 팩토리 메서드 호출 // FactoryBean 구현체

        // 스프링 IoC 컨테이너가 정한 규칙에 따라 공장 클래스를 만들면 객체 생성을 설정할 수 있다.

        // 스프링에서 공장 클래스를 만들 때 제안한 규칙 // org.springframework.beans.factory.FactoryBean 인터페이스

public class CarFactory implements FactoryBean<Car>{
  String model;

  public CarFactory() {
  }

  public void setModel(String model) {
    this.model = model;
  }

  @Override
  public Car getObject() throws Exception {
    Car c = new Car();
    switch (model) {
      case "티코":
        c.setMaker("대우자동차");
        c.setModel("Tico");
        c.setCc(890);
        return c;
      case "소나타":
        c.setMaker("현대자동차");
        c.setModel("Sonata");
        c.setCc(1980);
        return c;
    }
  }

  @Override
  public Class<?> getObjectType() {
    return Car.class;
  }
}



        // 이 인터페이스를 사용할 때는 getObject()와 getObjectType()를 오버라이딩하여 사용하는 것이 중요하다.

        // 이 방식은 객체를 생성할 때 추가적으로 필요한 값을 파라미터로 받을 수 없다. // 프로퍼티로 받는다.

        // Setter를 사용하여 원하는 데이터 값을 입력하도록 한다.

        // getObject()는 해당 객체를 생성해서 리턴하는 메서드이다. // 스프링 IoC 컨테이너는 이 메서드를 호출한다.

        // getObjectType()은 해당 객체를 생성하여 리턴할 때 생성 객체의 타입 정보를 리턴한다.

        // 이 메서드는 IoC컨테이너가 찾을 때, FactoryBean의 getObjectType()을 호출하기 때문에

        // 해당 객체의 타입정보를 리턴하지 않으면 IoC 컨테이너가 객체를 찾을 수 없다.

        // 스프링 IoC 컨테이너가 정한 규칙에 따라 공장 클래스를 만들면, 구현할 때 복잡한 면이 있다.

        // 하지만 빈 생성을 할 때에는 기존보다 쉽다.

    <bean id="c1" class="com.eomcs.spring.ioc.ex06.d.CarFactory">
        <property name="model" value="소나타"/>
    </bean>

        // 위처럼 사용만 하면 된다. // application-context 코드만 보면 CarFactory 객체를 만드는 것처럼 보인다.

       // 하지만 CarFactoryFactoryBean을 구현한 객체라면 그렇지 않다. // CarFactory를 이용해서 Car 객체를 만든다.

            CarFactory carFactory = new CarFactory();
            carFactory.setModel("소나타");
            
            Object obj = null;
            if (carFactory instanceof FactoryBean) {
                obj = carFactory.getObject();
            } else {
                obj = carFactory;
            }
            objPool.put("c1", obj);

         // 자바코드로 치면 이렇게 된다.

e

Exam01 -> FactoryBean 구현체 네이밍

        // FactoryBean을 구현한 객체가 CarFactory라는 이름을 사용하면

        // 이게 CarFactory인지, FactoryBean구현한 객체인지 알 수 없다.

        // 따라서 FactoryBean을 구현한 경우에는 알 수 있게 Bean이라는 이름을 뒤에 붙혀준다. // 개발자들 규칙

        // CarFactoryBean으로 파일명을 바꿔준다. // 다른 개발자가 쉽게 알아보도록 만든다.

 

spring #ex07

a

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

    <bean id="c1" class="com.eomcs.spring.ioc.ex07.a.Car">
        <property name="model" value="티코"/>
        <property name="maker" value="비트자동차"/>
        <property name="cc" value="890"/>
        <property name="auto" value="true"/>
        <property name="createdDate" value="2018-5-8"/>
    </bean>

        // 위처럼 입력했을 때, 실행해보면 오류가 발생한다. // createDate가 잘못 되어서이다.

        // java.lang.String 값을 java.sql.Date 객체로 변환할 수 없어서 생기는 문제이다.

        // 스프링 IoC 컨테이너에 String을 Date으로 바꾸는 변환기가 설치되어 있지 않다.

        // 프로퍼티 에디터 // String 값을 다른 타입의 값으로 변환하는 객체

        // 스프링 빌트인 프로퍼티 에디터(변환기) // primitive 타입 변환기는 기본으로 내장

        // String을 byte, short, int, long, float, double, boolean, char로 바꿀 수 있다.

b

Exam01 -> 프로퍼티 에디터 // 변환기 없이 처리하는 방법

            <bean class="java.sql.Date" factory-method="valueOf">
                <constructor-arg value="2020-3-20"/>

        // 직접 Date 객체를 생성하여 valueOf 메소드를 사용하게끔 한다.

c

Exam01 -> 프로퍼티 에디터 // 변환기를 사용하여 처리하는 방법

        // b 방식은 날짜 프로퍼티 값을 설정할 때마다 매번 작성해야 하기 때문에 불편하다.

        // String을 java.sql.Date 객체로 변환해주는 프로퍼티 에디터를 등록하면 된다.

    </bean>
    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
	    <property name="customEditors">
	        <map>
	            <entry key="java.sql.Date" 
	                   value="com.eomcs.spring.ioc.ex07.c.CustomDateEditor"/>
	        </map>
	    </property>
	</bean>

        // Spring IoC 컨테이너가 XML 설정 파일을 읽을 때, CustomEditorConfigurer 객체가 정의되어 있다면,

        // 객체를 설정파일에 정의된 대로 만들고 준비시킨다.

        // 프로퍼티 값을 저장할 때 이 객체에 정의된 프로퍼티 에디터를 사용할 것이다.

        // 프로퍼티 에디터를 설정하는 방법

        // key: String 값을 어떤 타입의 값으로 바꿀 것인지에 대한 타입 이름이다.

        // value: 커스텀 에디터(프로퍼티 값 변환기) 클래스 이름이다. 

        // 스프링 IoC 컨테이너가 프로퍼티 값을 설정할 때, 이 클래스를 사용하여 값을 바꾸라는 뜻이다.

public class CustomDateEditor extends PropertyEditorSupport {
  @Override
  public void setAsText(String text) throws IllegalArgumentException {
    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(); // 원래 하던 일을 수행한다.
  }

        // 프로퍼티 에디터 만드는 방법 // java.beans.PropertyEditor 인터페이스를 구현하면 된다.

        // 이 인터페이스를 직접 구현하려면 많은 메서드(12개의 메서드)를 모두 구현해야 한다.

        // PropertyEditor를 미리 구현한 PropertyEditorSupport 라는 클래스를 상속 받아 사용하면 된다.

        // setAsText(String text)는 파라미터로 넘어온 String 타입의 프로퍼티 값을 원하는 값으로 바꿔 저장한다.

        // 위 코드에서는 Date 타입의 값으로 바꿔 저장한다. // 

        // setValue()와 getValue()는 언제 호출되는 지를 보기위해 오버라이딩 한 것이다.

d

Exam01 -> 프로퍼티 에디터 만들기

    <bean id="c1" class="com.eomcs.spring.ioc.ex07.Car">
        <property name="model" value="티코"/>
        <property name="maker" value="비트자동차"/>
        <property name="cc" value="890"/>
        <property name="auto" value="true"/>
        <property name="createdDate" value="2018-5-8"/>
        <property name="engine" value="비트자동차,16,4"/>
    </bean>
    
    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
	    <property name="customEditors">
	        <map>
	            <entry key="java.sql.Date" 
	                   value="com.eomcs.spring.ioc.ex07.c.CustomDateEditor"/>
	            <entry key="com.eomcs.spring.ioc.ex07.Engine" 
                     value="com.eomcs.spring.ioc.ex07.d.CustomEngineEditor"/>
	        </map>
	    </property>

        // property engine항목에 value=비트자동차,16,4"를 넘겨준다. 

        // PropertyEditorSupport를 구현한 CustomEngineEditor에 setAsText()를 오버라이딩 한다.

        // text를 받아와 engine에 해당 데이터를 넣는다.

 

spring #ex08

a

Exam01 -> 의존 객체 주입 자동화 // xml로 설정

    <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"/>
        <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>

        // 의존 객체 // Dependency Injection // DI

b

Exam01 -> 의존 객체 주입 자동화 // 애노테이션

        // setter 메서드에 @Autowired로 표시한다.

        // BeanPostProcessor 인터페이스 //스프링 IoC 컨테이너는 객체 중에 이 인터페이스를 구현한 객체가 있다면,

        // 다른 모든 객체를 생성한 후에 이 구현체의 postProcess....() 메서드를 호출하여

        // 빈 생성 이후의 초기화 작업을 진행시킨다. // 그래서 이름이 BeanPostProcessor(객체 생성 후 처리기) 이다.

        // @Autowired 애노테이션을 샛터 메서드에 붙힌다고 의존 객체가 자동 주입되는 것은 아니다.

        // @Autowired 애노테이션을 처리하고 싶다면, 빈 생성 이후에 BeanPostProcessor를 등록하면 된다.

        // IoC 컨테이너는 빈을 모두 생성한 후에 @Autowired 애노테이션을 처리하기 위해 메서드를 호출할 것이다.

        // @Autowired 애노테이션 도우미를 등록하지 않으면 @Autowired 애노테이션은 처리되지 않는다.

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

        // @Autowired 애노테이션 도우미 등록

        // 동작 원리 // Spring IoC 컨테이너가 설정 파일에 적혀있는 대로 객체를 생성한다.

        // 객체 생성 후 마무리 작업을 수행하는 작업자를 실행한다. // 마무리 작업을 수행하는 작업자는 얘기 안해줌

// AutowiredAnnotationBeanPostProcessor가 객체 생성 후 @Autowired 애노테이션 붙은 프로퍼티 값을 자동 주입한다.

c

Exam01 -> 의존 객체 주입 자동화 // BeanPostProcessor

        // Spring IoC 컨테이너에 새 기능을 추가하는 예 //

        // 새 기능이 IoC 컨테이너가 생성한 객체를 사용해야 한다면, 객체 생성 후에 그 작업을 수행하면 된다.

        // 이렇게 개발자가 컨테이너의 기능을 확장할 수 있도록 BeanPostProcessor라는 규칙을 제공한다.

        // 빈 생성 후에 어떤 작업을 수행할 객체를 만들고 싶다면 // BeanPostProcessor 규칙에 따라 클래스를 만든다.

        // 빈 생성 이후의 어떤 작업의 경우, 인터페이스 BeanPostProcessor를 구현한 class에서, 

        // postProcessBeforeInitialization나 postProcessAfterInitialization를 오버라이딩하여 해당 작업을 넣어주면 된다.

d

Exam01 -> 의존 객체 주입 자동화 // 특별히 뭘 한게 없음 안봐도 될 듯

e

Exam01 -> 의존 객체 주입 자동화 // 인스턴스 변수에 @Autowired 애노테이션 붙이기

        // @Autowired 애노테이션을 필드(인스턴스 변수)에 붙여도 된다.

        // 의존 객체를 직접 변수에 주입한다. // 샛터를 호출하지 않는다. 샛터가 없어도 된다.

        // 인스턴스 변수에 직접 의존 객체를 주입한다는 것은 캡슐화를 위배하는 측면이 있어,

        // "객체지향을 파괴하는 방식"이라는 비난을 받는다.

        // 캡슐화 // 외부에서 직접 인스턴스 변수에 접근하는 것을 막는 기법

        // 필드에 @Autowired를 붙인 경우, 셋터를 통해 값을 넣는 것이 아니라, 인스턴스 필드에 직접 값을 넣는다.

        // private 이라도 상관없다. // 따라서 셋터를 정의하지 않아도 된다.

  private String model;
  private String maker;
  private int cc;
  private boolean auto;
  private Date createdDate;
  @Autowired
  private Engine engine;

        // 필드 위에 바로 붙힌다.

f

Exam01 -> 의존 객체 주입 자동화 // 생성자를 이용

  public Car(Engine engine) {
    this.engine = engine;
  }

        // 생성자를 통해 의존 객체(engine)를 주입할 수 있다.

        // AutowiredAnnotationBeanPostProcessor가 이것 또한 처리해준다.

        // 해당 클래스에 기본 생성자가 없을 때, 파라미터를 받는 다른 생성자를 찾아 호출한다.

g

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

  @Autowired(required = false)
  private Engine engine;

        // @Autowired의 required 값은 기본이 true이다. // 의존객체 주입이 필수사항이다.

        // 선택사항으로 바꾸고 싶으면 false로 설정하라. // false로 바꾸면 선택 의존 객체 true는 필수 의존 객체

h

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

        // 같은 타입의 의존 객체가 여러개일 때 Spring IoC 컨테이너가 어떤 것을 주입해야 할 지 몰라 예외가 발생한다.

        // @Qualifier 애노테이션을 사용하여 주입할 객체를 지정한다.

  @Autowired
  @Qualifier("e2")
  private Engine engine;
    <bean id="e2" class="com.eomcs.spring.ioc.ex08.h.Engine">
        <property name="maker" value="비트자동차"/>
        <property name="valve" value="16"/>
        <property name="cylinder" value="4"/>
    </bean>

        // 의존 객체가 여러개 있을 경우 주입할 의존 객체의 이름을 지정한다.

i

Exam01 -> 의존 객체 주입 자동화 // @Resource // @Autowired + @Qualifier

        // @Autowired와 @Qualifier를 묶어서 사용하는 대신에

        // 자바 언어 확장 명세서 'JSR-250'에 정의된 @Resource를 사용할 수 있다.

        // mvnmvnrepository.com 또는 search.maven.org 접속 - 'javax.annotation' 검색

        // org.springframework:spring-context // 버전 클릭 // Gradle Groovy DSL 복사

        // - 라이브러리 정보를 dependencies {} 블록에 추가 - 'gradle cleanEclipse' - 'gradle eclipse'

  @Resource(name = "e1")
  private Engine engine;
<context:annotation-config/>

        // 클래스에 붙은 특정 애노테이션을 처리할 BeanPostProcessor 등록하기

        // 특정 애노테이션을 처리하고 싶다면 그 애노테이션을 처리할 객체를 등록해야 한다.

        // 문제는 각각의 애노테이션에 대해 어떤 클래스가 처리하는지 암기를 해야하고

        // <bean> 태그를 이용하여 그 객체를 등록해야 한다.

        // 이러한 문제점을 해결하기 위하 애노테이션을 처리할 클래스를 자동 등록하는 특별한 단축 태그를 제공한다.

        // @Resource를 사용하면, ConfigurationClassPostProcessor, AutowiredAnnotationBeanPostProcessor

        // CommonAnnotationBeanPostProcessor, EventListenerMethodProcessor, DefaultEventListenerFactory

        // 5개가 등록되어있다. // @Autowired 애노테이션을 처리하는 객체를 직접 등록하지 말라.

        // context:annotation-config // annotation을 처리해야되는 객체들을 모아놓은 단축키라고 생각하자

        // 개발자가 저 위의 이름을 다 외우고 일일히 등록함을 막기 위함이다. // 또한 객체 이름이 변경될 수도 있다.

        // 나중에 직접 찾아가서 다 바꾸어줘야한다. // 즉, @Resource를 사용하자

 

spring #ex09

a

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

     // bean 태그를 사용하지 않아도 객체를 자동 생성할 수 있다. // 클래스 선언에 @Component 애노테이션을 붙힌다.

@Component
public class Car {
  String model;
  String maker;
  int cc;
  boolean auto;
  Date createdDate;
  Engine engine;
@Component
public class Engine {
  String maker;
  int valve;
  int cylinder;

        // @Component // @Component(value="객체이름") // @Component("객체이름")

        // 스프링 IoC 컨테이너는 이 애노테이션이 붙은 클래스에 대해 객체를 자동 생성한다.

        // 만약 다음과 같이 객체의 이름을 생략하면 클래스 이름을 객체 이름으로 사용한다.

        // 클래스 이름에서 첫 알파벳을 소문자로 한 이름을 객체 이름으로 사용한다. // ......ex09.Car => "car"

        // @Compoenet로 객체를 생성할 때에는 이렇게 생성된다.  // 익명 클래스에서는 Car#0로 붙었던 것과 다르다.

        // 단 이 애노테이션을 처리할 객체를 등록해야 한다. // 애노테이션을 처리할 도우미 객체를 등록한다.

<context:annotation-config/>
<context:component-scan base-package="com.eomcs.spring.ex09.step09"/>

        // @Controller // MVC(model-view-controller) 아키텍처에서 컨트롤러 객체에 대해 붙인다.

        // 개발자가 유지보수할 때 클래스의 역할을 더 정확히 이해할 수 있게 도와주기 위해 사용하는 애노테이션이다.

        // @Service // MVC 아키텍처에서 model 객체 중 서비스 역할을 수행하는 객체에 대해 붙이는 애노테이션이다. 

        // @Controller로 마찬가지로 유지보수에 도움을 줄 목적으로 추가된 애노테이션이다.

        // @Repository // MVC 아키텍처에서 model 객체 중 DAO 역할을 수행하는 객체에 대해 붙이는 애노테이션이다.

        // @Controller로 마찬가지로 유지보수에 도움을 줄 목적으로 추가된 애노테이션이다.

        // @Repository는 학원에서는 Mybatis를 사용하기 때문에 사용할 일은 없다.

        // 회사에서 DAO 자동 생성을 사용하기 전의 버전을 사용하여 코딩을 했었다면 볼 수도 있다.

        // component-scan 태그는 @Component, @Service, @Repository, @Controller 

        // 애노테이션이 붙은 객체를 자동 생성시키도록 명령한다.

        // base-package 속성 // 어느 패키지의 클래스를 등록할 것인지 지정하는 속성이다.

        // 의존 객체는 생성자에서 주입하는 것이 좋다. // 

        // 의존 객체라는 말에서 이미 그 객체없이는 작업을 수행할 수 없다는 의미이기 때문에 보통 필수 객체이다.

        // 생성자에서 필수 객체를 받게 하는 것이 유지보수에 좋다. // 의존 객체없이 해당 객체를 생성하는 일을 방지

b

Exam01 -> 객체 자동 생성 // context:annotation-config 생략

        // component-scan 태그를 추가하면 내부적으로 annotation-config 태그가 자동으로 추가된다.

<context:component-scan base-package="com.eomcs.spring.ioc.ex09"/>

        // 자동으로 추가되기 때문에 <context:annotation-config/>를 넣을 필요는 없다. // 넣어도 된다.

c

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

        <context:include-filter type="regex" 
            expression="com.eomcs.spring.ioc.ex09.b.B2"/>

        <context:exclude-filter type="regex" 
            expression="com.eomcs.spring.ioc.ex09.b.B"/>
            
        <context:exclude-filter type="annotation" 
            expression="org.springframework.stereotype.Controller"/>

        // <context:include-filter type="regex" expression=경로/>

        // 해당 경로의 객체를 자동으로 생성한다. // 각 객체마다 @Component를 지정한 효과

        // <context:exclude-filter type="regex" expression=경로/> // 해당 경로의 객체를 생성에서 제외한다.

        // <context:exclude-filter type="annotation" expression=클래스/> // 해당 클래스의 객체를 생성에서 제외한다.

 

spring #ex10

a

Exam01 -> 스프링 설정 // 클래스 이용

    ApplicationContext iocContainer = 
        new AnnotationConfigApplicationContext(AppConfig.class);

        // 해당 클래스의 정보를 넘겨준다.

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

        // AnnotationConfigApplicationContext 는 @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 car2() {
    Car c = new Car(null);
    c.setMaker("비트자동차");
    c.setModel("티코");
    c.setCc(890);
    c.setAuto(true);
    return c;
  }

        // 실무에서는 스프링 설정 용으로 사용하는 클래스에서 객체를 리턴하는 메서드를 만들 때

        //  그 메서드의 이름을 객체 이름과 같게 짓는다. 

        // 보통 어떤 값을 리턴할 때는 getXxx()라는 이름으로 메서드를 만드는데, 

        // 객체 이름으로 사용할 수 있도록 메서드를 만드는 경우도 있다.

b

Exam01 -> 스프링 설정 // @Configuration 애노테이션

ApplicationContext iocContainer = new AnnotationConfigApplicationContext("com.eomcs.spring.ioc.ex10");

        // 패키지명을 지정하면, 해당 패키지의 모든 클래스를 찾아,

        // @Component, @Service, @Controller, @Repository 애노테이션이 붙은 클래스에 대해 객체를 자동 생성한다.

        // 또한 @Configuration 애노테이션이 붙은 클래스를 찾아,

        // 그 클래스에 @Bean 애노테이션이 붙은 메서드를 호출하여 그 리턴 값을 저장한다.

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

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

}

        // @Configuration // AppConfig 클래스가 스프링 설정 정보를 갖고 있는 클래스임을 선포하는 것.

        // AnnotationConfigApplicationContext 에서 이 클래스를 찾아 적절한 작업을 수행할 것이다.

        // @Component를 붙혀도 되지만, 설정을 강조하는 의미가 있기 때문에 @Configuration을 사용하자.

        // ex10.a 처럼 class 정보를 넘겨줄 때에는 애노테이션이 필요 없지만,

        // 패키지를 넘겨줄 때에는 애노테이션을 붙혀야 한다. // 패키지중 어떤게 설정 class인지 알려주기 위함.

 

spring #ex11

Exam01 -> 스프링 설정 // 클래스 이용

        // @ComponentScan // <context:component-scan/> 와 같은 일을 한다.

        // 1. 한 개의 패키지를 지정하기 // 배열 항목이 한 개일 경우 {} 생략가능

        // @ComponentScan(basePackages = { "com.eomcs.spring.ioc.ex11.p1" })

        // 2. 여러 개의 패키지 지정하기 

        // @ComponentScan(basePackages = {"com.eomcs.spring.ioc.ex11.p1", "com.eomcs.spring.ioc.ex11.p2"}) 

        // 3. 특정 패키지나 클래스 제외하기

@ComponentScan(
    basePackages="com.eomcs.spring.ioc.ex11",
    excludeFilters=@ComponentScan.Filter(
        type=FilterType.REGEX,
        pattern="com.eomcs.spring.ioc.ex11.p2.*")
    )
<context:component-scan base-Package="com.eomcs.spring.ioc.ex11">
  <context:excluede-filter
    type="regex"
    expression="com.eomcs.spring.ioc.ex11.p2.*"/>
</context:component-scan>

        // 위 자바 애노테이션을 XML 파일에서 작성하면 이렇게 적는다.

 

spring #ex12

a

Exam01 -> Spring과 Mybatis 연동 // SqlSessionFactory를 설정으로 준비 // application-context에서 xml문으로 준비

        // Board.java // 컬럼 및 프로퍼티 설정

        // BoardDao.java와 BoardMapper.xml // DB처리를 수행할 작업 준비.

        // jdbc.properties, DB 데이터(READ.md)  //시행하기 전에 DB와 연결할 수 있게 준비

        // mybatis-config.xml // mybatis에 DB연결 정보 준비.

        // Mybatis SqlSessionFactory 준비하기 // application-context.xml

    <bean id="mybatisConfigInputStream"
          class="org.apache.ibatis.io.Resources"
          factory-method="getResourceAsStream">
      <constructor-arg 
        value="com/eomcs/spring/ioc/ex12/a/mybatis-config.xml"/>
    </bean>
InputStream mybatisConfigInputStream = Resources.getResourceAsStream(
"com/eomcs/spring/ioc/ex12/a/mybatis-config.xml");

        // SqlSessionFactory를 만들 때 사용할 설정 파일 읽기 도구를 준비 // 자바코드로 치면 이렇게 된다.

    <bean id="sqlSessionFactoryBuilder"
          class="org.apache.ibatis.session.SqlSessionFactoryBuilder"/>
  SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); 

        // SqlSessionFactory를 만들어주는 공장 객체를 준비 // 자바코드로 치면 이렇게 된다.

    <bean id="sqlSessionFactory"
          factory-bean="sqlSessionFactoryBuilder"
          factory-method="build">
      <constructor-arg ref="mybatisConfigInputStream"/>
    </bean>
SqlSesssionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(mybatisConfigInputStream);  

        // BoardDao가 사용할 SqlSessionFactory 객체를 준비 // 자바코드로 치면 이렇게 된다.

b

Exam01 -> Spring과 Mybatis 연동 // SqlSessionFactory를 객체로 준비 // SqlSessionFactoryFactoryBean.java로 준비

        // SqlSessionFactoryFactoryBean // SqlSessionFactory를 만드는 Factory 역할을 한다.

        // FactoryFactory 붙어 있어도 오타가 아닐 수 있다.

        // mybatis 개발자는 FactoryBean으로 적어서 개발자들을 헷갈리게 만들었다. // mybatis에서는 이 점 알아두자

    <bean id="sqlSessionFactory"
          class="com.eomcs.spring.ioc.ex12.b.SqlSessionFactoryFactoryBean">
      <property name="configLocation" 
                value="com/eomcs/spring/ioc/ex12/b/mybatis-config.xml"/>
    </bean>

        // application-context.xml // SqlSessionFactoryFactoryBean

        // FactoryBean이 붙어있다면, SqlSessionFactoryFactoryBean 객체가 생성되는게 아니다.

        // SqlSessionFactory 객체를 리턴하고, 담는다는걸 알아두자. // 그래서 bean id도 sqlSessionFactory이다.

public class SqlSessionFactoryFactoryBean 
implements FactoryBean<SqlSessionFactory> {

  String configLocation;

  public void setConfigLocation(String configLocation) {
    this.configLocation = configLocation;
  }

  @Override
  public SqlSessionFactory getObject() throws Exception {
    InputStream in = Resources.getResourceAsStream(configLocation);
    return new SqlSessionFactoryBuilder().build(in);
  }

  @Override
  public Class<?> getObjectType() {
    return SqlSessionFactory.class;
  }
}

        // IoC 컨테이너에 자동생성 객체를 만드는 것이므로, getObject()와 getObjectType()를 오버라이딩한다.

        // setConfigLocation() 세터를 통해, configLocation을 받는다. // configLocation은 xml파일에서 넘겨준다.

        // getObject() // 넘겨받은 configLocation으로 스트림을 만들어 해당 SqlSessionFactoryBuilder에게 전달

        // SqlSessionFactory를 만들어 return 받아 IoC 컨테이너가 보관한다.

        // getObjectType() // SqlSessionFactory의 class 정보를 리턴하여 SqlSessionFactory를 찾을 수 있게함.

c

Exam01 -> Spring과 Mybatis 연동 // mybatis에서 제공해주는 spring 연동 라이브러리 사용하기 

        // 직접 스프링 IoC 컨테이너에서 사용할 SqlSessionFactory 빌더 클래스를 만들 필요가 없다. 

        // mvnmvnrepository.com 또는 search.maven.org 접속 - 'mybatis-spring' 검색

        // org.springframework:spring-context // 버전 클릭 // Gradle Groovy DSL 복사

        // - 라이브러리 정보를 dependencies {} 블록에 추가 - 'gradle cleanEclipse' - 'gradle eclipse'

    <bean id="sqlSessionFactory"
          class="org.mybatis.spring.SqlSessionFactoryBean">

        // 보통 클래스 이름이 XxxFactoryBean이면 생성되는 객체는 Xxx이다.

        // mybatis에서 제공하는 sqlSessionFactoryBean 클래스가 생성하는 객체는 SqlSessionFactory이다.

        // Mybatis 개발자는 이름 중간에 Factory가 두 번 들어가는 것이 싫었나 보다.

      <property name="dataSource" ref="dataSource" />

        // mybatis를 스프링과 연동하면, DataSource는 스프링에서 관리하는 객체를 사용해야 한다.

        // mybatis가 만든 DataSource를 사용할 수 없다.

      <property name="mapperLocations" 
                value="classpath*:com/eomcs/spring/ioc/ex12/c/*Mapper.xml" />  

        // SQL 맵퍼 파일이 있는 경로를 설정하면, SqlSessionFactory가 그 경로에서 SQL 맵퍼 파일을 찾을 것이다.

      <property name="typeAliases" value="com.eomcs.spring.ioc.ex12.Board"/>   
    </bean>

        // Board 클래스 처럼 데이터를 담는 객체(Value Object = Domain Object)의 별명을 자동으로 등록하기

        // 패키지를 지정하면 그 패키지에 있는 모든 클래스에 대해 클래스 이름을 별명으로 자동 부여한다.

        // TypeAlias는 자바타입에 대한 이름이다. XML 설정에만 적용되며,

        // 패키지 경로 전체를 작성하는 수고를 덜어주기 위한 설정이다.

	<bean id="dataSource" 
	      class="org.apache.commons.dbcp.BasicDataSource" 
	      destroy-method="close">
	    <property name="driverClassName" value="${jdbc.driver}" />
	    <property name="url" value="${jdbc.url}" />
	    <property name="username" value="${jdbc.username}" />
	    <property name="password" value="${jdbc.password}" />
	</bean>

        // mybatis가 사용할 DataSource 객체 준비하기 // 

        // BasicDataSource 클래스가 들어 있는 apache-commons-dbcp 라이브러리를 추가해야 한다.

        // Project-Server에서는 DriverManagerDataSource를 사용했고, 여기서는 BasicDataSource를 사용한다.

        // BasicDataSource는 아파치에서 제공하는 DataSource이다. // 둘 다 사용하는 것을 알아두자.

        // 두 DataSource의 가장 중요한점은 interface DataSource를 구현한 애들이라는 점이다.

        // BasicDataSource를 가져오자.

        // mvnmvnrepository.com 또는 search.maven.org 접속 - 'commons-dbcp' 검색

        // org.springframework:spring-context // 버전 클릭 // Gradle Groovy DSL 복사

        // - 라이브러리 정보를 dependencies {} 블록에 추가 - 'gradle cleanEclipse' - 'gradle eclipse'

        //  또한 DB 커넥션 풀을 사용하려면 'spring-jdbc가 필요하다.

        // mvnmvnrepository.com 또는 search.maven.org 접속 - 'spring-jdbc' 검색

        // org.springframework:spring-context // 버전 클릭 // Gradle Groovy DSL 복사

        // - 라이브러리 정보를 dependencies {} 블록에 추가 - 'gradle cleanEclipse' - 'gradle eclipse'

    <context:property-placeholder 
        location="com/eomcs/spring/ioc/ex12/jdbc.properties"/>	

        // 스프링 설정 파일에서 사용할 .properties 파일을 로딩하는 객체 준비.

d

Exam01 -> Spring과 Mybatis 연동 // mybatis가 구현한 DAO 객체 사용하기

        // BoardDao를 Interface로 선언한다.

        // 이 인터페이스의 구현체를 mybatis가 자동으로 생성하여 Spring IoC 컨테이너에 등록할 것이다.

        // 1. 맵퍼 파일의 namespace는 인터페이스의 패키지 및 인터페이스명과 같아야 한다.

<mapper namespace="com.eomcs.spring.ioc.ex12.d.BoardDao">

        // 2. 메서드의 이름과 SQL 아이디가 같아야 한다.

  <select id="selectList" resultMap="BoardMap" parameterType="map">

        // 3. 메서드의 리턴 타입과 SQL 맵퍼 파일의 resultType 또는 resultMap이 같아야 한다.

        // insert, update, delete일 경우 리턴 값이 void 또는 int가 될 수 있다.

        // 4. DAO 인터페이스의 메서드는 파라미터를 하나만 가진다. // SQL 맵퍼는 파라미터 값을 한 개만 받기 때문

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	    <property name="basePackage" value="com.eomcs.spring.ioc.ex12.d" />

        // 방법 1 // application-context.xml // DAO 구현체를 자동으로 만들어 주는 객체를 준비

        // 개발자는 DAO를 직접 구현할 필요가 없다. // 단지 인터페이스만 선언하면 된다.

        // DAO 인터페이스가 선언된 패키지를 지정한다.

<mybatis:scan base-package="com.eomcs.springico.ex12.d"/>

        // 방법 2 // application-context2.xml // mybatis.scan을 준비한다. // DAO 구현체를 자동으로 만들어주는 객체

        // xml 파일은 mybatis가 무엇인지 모른다.

xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"

        // xml 파일 상단에 mybatis schema 이름을 알려준다. // 상단 <beans에 정의

        // schema // xml 파일의 규칙을 정의해둔 게 schema이다. // 이름을 알려줘도 해당 내용이 없어서 오류 발생

http://mybatis.org/schema/mybatis-spring
        http://mybatis.org/schema/mybatis-spring.xsd

        // xsi:schemaLocation= 에 추가 // schema 이름에 대한 내용을 알려준다.

        // http://mybatis.org/schema/mybatis-spring // schema 이름  

        // http://mybatis.org/schema/mybatis-spring.xsd // 규칙을 정의하고 있는 url

e

Exam01 -> Spring과 Mybatis 연동 // Java Config로 설정하기

@PropertySource("classpath:com/eomcs/spring/ioc/ex12/jdbc.properties")
@MapperScan("com.eomcs.spring.ioc.ex12.e")
public class AppConfig {

  @Value("${jdbc.driver}")
  String jdbcDriver;

  @Value("${jdbc.url}")
  String jdbcUrl;

  @Value("${jdbc.username}")
  String jdbcUsername;

  @Value("${jdbc.password}")
  String jdbcPassword;

  @Bean
  public DataSource dataSource() {
    BasicDataSource ds = new BasicDataSource();
    ds.setDriverClassName(jdbcDriver);
    ds.setUrl(jdbcUrl);
    ds.setUsername(jdbcUsername);
    ds.setPassword(jdbcPassword);
    return ds;
  }

  @Bean
  public SqlSessionFactory sqlSessionFactory(DataSource dataSource, 
  ApplicationContext appCtx) throws Exception {
    SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
    sqlSessionFactoryBean.setDataSource(dataSource);
    sqlSessionFactoryBean.setTypeAliases(Board.class);
    sqlSessionFactoryBean.setMapperLocations(//
        appCtx.getResources("classpath:com/eomcs/spring/ioc/ex12/e/*Mapper.xml"));
    return sqlSessionFactoryBean.getObject();
  }
}

        // Java Config 생성 // 

        // @PropertySource 애노테이션 설정 // @value 값을 가져오기 위해 Property 설정 위치를 알려준다.

        // @MapperScan 애노테이션 설정 // BoardDao 프록시를 자동생성하기 위해 인터페이스 위치 지정

        // DataSource 설정

        // Project-Server는 스프링에서 제공해주는 DB 커넥션 풀(=DataSource)을 사용했다 // DriverMangerDataSource

        // 그러나 이번에는 아파치에서 제공해주는 BasicDataSource를 사용했다. // 사용법은 동일하다.

        // sqlSessionFactoryBean.setTypeAliases(Board.class);

        // BoardMapper.xml에서 resultMap Board를 찾기 위해, 해당 경로를 넣어준다.

        // 실무에서는 XML로 설정하기도, Java Config로 설정하기도 기타 다른 방법으로도 설정한다.

        // ex12 a부터 e까지는 최소한 다 알아둬야 한다.

 

spring #ex13

a

Exam01 -> AOP 필터 // 적용 전

b

Exam01 ->  AOP 필터 // 적용 후

        // AOP // Aspect-Oriented Programming // 기존의 코드를 손대지 않고 특정 기능을 삽입하는 기술

        // 메서드 호출 앞뒤로 코드를 삽입할 수 있다. // 일종의 필터를 추가하는 기술이다.

        // AOP 적용 방법 // 

        // mvnmvnrepository.com 또는 search.maven.org 접속 - 'aspectjweaver' 검색

        // org.springframework:spring-context // 버전 클릭 // Gradle Groovy DSL 복사

        // - 라이브러리 정보를 dependencies {} 블록에 추가 - 'gradle cleanEclipse' - 'gradle eclipse'

        // 필터 클래스를 정의한다. // XML 또는 Java Code로 필터를 설정한다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    
    <context:component-scan base-package="com.eomcs.spring.ioc.ex13.b"/>
    <bean id="myAdvice" class="com.eomcs.spring.ioc.ex13.b.MyAdvice"/> 
    
    <aop:config>
        <aop:aspect id="aspect1" ref="myAdvice">
            <aop:pointcut id="pointcut1"
                expression="execution(* com.eomcs.spring.ioc.ex13.b.*.m2(..))"/>
            <aop:before pointcut-ref="pointcut1" method="advice2"/>
        </aop:aspect>
    </aop:config>
</beans>

        // 실제 XML 파일에는 beans 설정 등 다른 코드들이 있지만, 어떤게 추가되는지 보려고 일부로 지웠음.

        // xmlns:aop // 이름 설정

        // xsi:schemaLocation= // 해당 이름(aop)에 해당하는 schema 내용 추가

        // context:component-scan 설정 // component 객체 생성을 위해

        // bean 생성 // AOP 필터 객체 생성

        // <aop:config> // AOP를 적용한다는 내용이 안에 들어간다.

        // <aop:aspect: id=값 ref=값"> // 어느 pointcut에 어떤 advice를 끼워 넣을 지 설정한다.

        // 추후 밑에서 설명하겠지만, id에는 java method명이, ref에는 위에 선언한 iop필터 이름이다.

        // aop:pointcut id=값 expression="execution(리턴타입 패키지타입)" //

        // <aop:pointcut id="pointcut1" expression="execution(* com.eomcs.spring.ioc.ex13.b.*.m2(..))"/>

        // 해석 // 리턴타입은 무엇인지 상관 없고,(*) ...ex13.b 밑에 어떤 패키지 안인지 상관 없고,

        // m2를 호출하기 전의 시점을 pointcut1이라고 하겠다.

        // <aop:before pointcut-ref=값 method=값/>

        // <aop:before pointcut-ref="pointcut1" method="advice2"/>

        // 해석 // 위에 설정한 pointcut1에 advice2메소드를 실행하겠다.

        // 즉, ex13.b 밑에 어떤 경로든 m2 메소드 실행 전에 advice2가 실행이 먼저 된다.

        // AOP 용어 //

        // Advice // 메서드(join point) 호출 앞뒤에 삽입될 코드를 담고 있는 필터 객체이다. // ex) MyAdvice 클래스

        // Join Point // Advice가 들어갈 메서드이다. // ex) m2() 메서드

        // Pointcut // Advice를 삽입할 위치 정보이다. // ex) execution(리턴타입 패키지타입)

        // Target Object // Advice를 삽입할 대상 객체이다. // ex) Y, Z 클래스 // m2()를 가지고 있는 클래스

        // Aspect // 어느 pointcut에 어떤 advice를 삽입할 것인지 가리키는 정보 // ex) 설정정보

public class MyAdvice {
  public void advice1() {
    System.out.println("MyAdvice.advice1()");
  }

  public void advice2() {
    System.out.println("MyAdvice.advice2()");
  }
}

        // 위에서 계속 나온 MyAdvice와 advice1(), advice2()를 java파일로 정의를 해둔다.

        // Advice // 메서드가 실행하기 전에 충고를 한다. // AOP 개발자가 Advice로 정했다.

Exam02 -> AOP 필터 // 적용 후 // before와 pointcut 합치기

<aop:before pointcut="execution(* com.eomcs.spring.ioc.ex13.b.*.m2(..))" method="advice2"/>

        // before와 pointcut을 이렇게 합쳐서 사용할 수 도 있다.

Exam03 -> AOP 필터 // 적용 후 // 한 포인트 컷에 여러개 필터 꼽기

<aop:before pointcut="execution(* com.eomcs.spring.ioc.ex13.b.*.m2(..))" method="advice1"/>
<aop:before pointcut="execution(* com.eomcs.spring.ioc.ex13.b.*.m2(..))" method="advice2"/>

        // 한 포인트 컷에 필터는 몇개든 삽입이 가능하다.

Exam04 ->  AOP 필터 // 적용 후 // 한 포인트 컷에 여러개 필터 꼽기 // 포인트 컷 별도 정의

<aop:pointcut id="pointcut1" expression="execution(* com.eomcs.spring.ioc.ex13.b.*.m2(..))" />
<aop:before pointcut-ref="pointcut1" method="advice1"/>
<aop:before pointcut-ref="pointcut1" method="advice2"/>

        // 한 포인터 컷에 필터를 여러개 꽂게 될 경우, 포인트 컷을 별도로 정의하자.

        // pointcut-ref 기능을 이용하여 보다 편리하게 사용가능 // 단 expression 규칙이 같아야 한다.

Exam05 -> AOP 필터 // 적용 후 // 여러 aspect에서 재사용 할 수 있다.

<aop:pointcut id="pointcut1" expression="execution(* com.eomcs.spring.ioc.ex13.b.*.m2(..))" />

<aop:aspect id="aspect1" ref="myAdvice"> 
  <aop:before pointcut-ref="pointcut1" method="advice1"/>
</aop:aspect>
        
<aop:aspect id="aspect2" ref="myAdvice2"> 
  <aop:before pointcut-ref="pointcut1" method="hahaAdvice"/>
</aop:aspect>

        // 여러 aspect에서 pointcut을 사용한다면, pointcut을 aspect 밖으로 빼서 사용한다.

        // m2가 호출 될 때, MyAdvice와 MyAdvice2 각각 다른 class의 다른 method를 호출할 때 사용한다.

c

Exam01 ->  AOP 필터 // 적용 위치

<aop:before pointcut-ref="pointcut1" method="doBefore"/>
<aop:after pointcut-ref="pointcut1" method="doAfter"/>
<aop:after-returning pointcut-ref="pointcut1" method="doAfterReturning"/>
<aop:after-throwing pointcut-ref="pointcut1" method="doAfterThrowing"/>
<aop:around pointcut-ref="pointcut1" method="doAround"/>

        // before // pointcut1에 해당되는 메서드 호출 전에 실행한다.

        // after // pointcut1에 해당되는 메서드 호출 후에 실행한다. // finally

        // after-returning //  pointcut1에 해당되는 메서드 호출 후에 실행한다. // 정상 실행시 실행

        // after-throwing // pointcut1에 해당되는 메서드 호출 후 예외가 발생하면 실행한다.

        // around // pointcut1에 해당되는 메서드 호출 전 후에 실행한다.

    try {
      try {
        original.m1(a, b);
      } catch (Exception e) {
        throw e;
      } finally {
        myAdvice.doAfter();
      }
      myAdvice.doAfterReturning();
    } catch (Exception e) {
      myAdvice.doAfterThrowing();
    }

        // 자바코드로 보면 다음과 같다. // after와 afterReturning의 차이 확인하기

d

Exam01 ->  AOP 필터 // 타겟 객체의 메서드를 호출하기 전에 파라미터를 받거나 리턴 값을 받기

        <aop:aspect id="aspect1" ref="myAdvice">
            
            <aop:before 
                pointcut="execution(* bitcamp.java106.step13.ex4.X.*(..)) and args(a,b)" 
                method="doBefore"/>
            
            <aop:after-returning 
                pointcut="execution(* bitcamp.java106.step13.ex4.X.*(..))" 
                method="doAfterReturning"
                returning="returnValue"/>
                
            <aop:after-throwing 
                pointcut="execution(* bitcamp.java106.step13.ex4.X.*(..))" 
                method="doAfterThrowing"
                throwing="error"/>    
        </aop:aspect>

        // before에 args(a,b)가 추가되었다. // MyAdvice클래스 doBefore메서드에 a,b가 전달된다.

        // doBefore(a,b) // args(a,b) // doBefore(x,y) // args(x,y)

        // doBefore(b,a) // args(a,b) // 이렇게 설정하면, b는 b값에 a는 a값에 들어간다. // args 순서는 상관 없다.

        // args에서 넘겨주는 이름은 doBefore의 파라미터 이름과 같아야 한다. // 변수 이름을 찾아 값을 넣기 때문.

        // after-returning // returning="returnValue" 설정 // 메서드 정상 실행 후, 그 메서드가 리턴한 값을 받는다. 

        // after-throwin // throwing="error" 설정 // 예외 발생시, 그 예외 정보를 받는다.

e

Exam01 ->  AOP 설정 // 애노테이션 사용 // XML 설정파일을 사용

        // <aop:aspectj-autoproxy/> 추가 // AOP 관련 애노테이션을 처리해주는 객체를 자동으로 등록한다.

@Component
@Aspect
public class MyAdvice {

  @Before("execution(* com.eomcs.spring.ioc.ex13.e.X.*(..)) and args(a,b)")
  public void doBefore(int a, int b) {
    System.out.printf("MyAdvice.doBefore(): %d, %d\n", a, b);
  }

  @AfterReturning(
      pointcut="execution(* com.eomcs.spring.ioc.ex13.e.X.*(..))",
      returning="returnValue")
  public void doAfterReturning(Object returnValue) {
    System.out.printf("MyAdvice.doAfterReturning(): %d\n", returnValue);
  }

  @AfterThrowing(
      pointcut="execution(* com.eomcs.spring.ioc.ex13.e.X.*(..))",
      throwing="error")
  public void doAfterThrowing(Exception error) {
    System.out.printf("MyAdvice.doAfterThrowing(): %s\n", error.getMessage());
  }
}

        // aop를 설정할 곳에 애노테이션만 추가하면 된다. // aop 이름 설정과 schema 설정은 당연히 해야된다.

        // @Component // Advice 객체를 IoC 컨테에 자동으로 등록하기 위해 붙힌다.

        // @Aspect

        // @Before("execution(리턴타입 패키지타입)")

        // @AfterReturning(pointcut="execution(리턴타입 패키지타입)", returning="returnValue")

        // @AfterThrowing(pointcut="execution(리턴타입 패키지타입)", throwing="error")

        // 원래 XML에서는 ,를 사용하지 않지만, Java에서는 ,를 사용한다. 

        // XML에서는 method명도 명시했지만, Java에서는 해당 Method에 애노테이션을 붙히므로 생략한다.

f

Exam01 ->  AOP 설정 // 애노테이션 사용 // JavaConfig로 사용

@Configuration
@ComponentScan("com.eomcs.spring.ioc.ex13.f")
@EnableAspectJAutoProxy
public class AppConfig {
}

        // @Configuration // 이 클래스가 설정 클래스임을 선언한다. 

        // new AnnotationConfigApplicationContext(AppConfig.class)

        // iocContainer 객체를 생성할 때, AppConfig 정보를 넘겨준다면 @Configuration 생략 가능

        // @ComponentScan("com.eomcs.spring.ioc.ex13.f")

        // @Component 애노테이션이 붙은 객체 자동생성을 위한 애노테이션 추가

        // @EnableAspectJAutoProxy // AOP 관련 애노테이션을 처리해주는 객체를 자동으로 등록한다.

반응형

+ Recent posts