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 객체를 만드는 것처럼 보인다.
// 하지만 CarFactory가 FactoryBean을 구현한 객체라면 그렇지 않다. // 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 관련 애노테이션을 처리해주는 객체를 자동으로 등록한다.