Spring Framework 3.X 오문정강사 (muffle@hanmail.net) 2013. 1. Spring3- Oh Moon Jeong - 1-1
레이어 vs. 티어 레이어 논리적분할, 단방향 티어 -- 물리적분할, 양방향 Spring3- Oh Moon Jeong - 2-2
Java EE Java 2 Platform, Enterprise Edition Java EE 6 specifies technologies to support multitier enterprise applications Spring3- Oh Moon Jeong - 3-3
JAVAEE 응용어플리케이션 with EJB 비즈니스티어확장을위한분산객체 (distributed object) 기술을적용 (+) 비즈니스티어확장을통한가용성향상 (-) 기술복잡도가높아이해하기어려움 (-) 개발생산성 (-) 성능 (-) 유지보수성 (-) 테스트 EJB 컨테이너필요 (-) 컨테이너이식성 벤더고유서비스 (-) 개체지향개발-컨테이너API 제약 Spring3- Oh Moon Jeong - 4-4
JAVAEE 응용어플리케이션 without EJB 비즈니스컨테이너서비스는인정분산객체 (distributed object) 기술은오버스팩웹티어와비즈니스티어를분할하지않고웹티어내에통합함 (+) 배우기쉬움 (+) 개발생산성 (+) 성능 (+) 유지보수성 (+) 테스트용이 (+) 컨테이너이식성-Servlet컨테이너 (+) 개체지향개발 (-) 비즈니스티어분산홖경미지원 (-) LightwegihtContainer표준이없음 Spring3- Oh Moon Jeong - 5-5
POJO Plain Old Java Object Java Language 이외에어떤제약도받지않는개체 스프링의자바빈이란용어는 POJO 와같은말이다. POJO 가아닌사례 Spring3- Oh Moon Jeong - 6-6
요약 POJO 기반 J2EE 응용어플리케이션 Without EJB 프레임워크기반응용어플리케이션 Spring3- Oh Moon Jeong - 7-7
SPRING FRAMEWORK Spring3- Oh Moon Jeong - 8-8
SpringFramework 의특징 스프링은 어플리케이션프레임워크 로불리며, 웹어플리케이션은물론콘솔어플리케이션, GUI어플리케이션등어떤어플리케이션에도적용가능한프레임워크이다. 다양한 API와의연동지원을통한JAVA EE 구현가능하다. POJO지원 특정규약 ( 특정클래스로부터상속해서만들어야하는규약 ) 에종속되지않는다. 특정환경 ( 특정서버및기술 ) 에종속되지않는다. 스프링은 EJB와같은복잡한순서를거치지않아도간단하게이용할수있기때문에 Lightweight 컨테이너라고도부른다. 스프링은 Dependency Injection(DI) 과 Aspect Oriented Programming(AOP) 을가장중점적인기술로사용한다. Spring3- Oh Moon Jeong - 9-9
스프링구성모듈 Spring3- Oh Moon Jeong - 10-10
스프링설치 spring홈페이지 - http://spring.io spring 소스 : https://github.com/springsource/spring-framework maven 중앙저장소 : http://mavenrepository.com spring-framework-3.0.1.release-a-with-docs.zip Spring3- Oh Moon Jeong - 11-11
(dependency injection) D I Spring3- Oh Moon Jeong - 12-12
객체지향설계원칙 High Coherence, Low Coupling class CD 음식점 - 공통모듈상속 shop::bakery + Bakery() + sale(string) : Food + tostring() : String «사용» «interface» FoodMaker + make() : Food shop::shoptest + main(string[]) : void «사용» DonutMaker CoffeeMaker Food + make() : Donut + make() : Coffee - name: String shop::cafe + Cafe() + sale(string) : Food + tostring() : String «생성» shop::donut + Donut() shop::coffee + Coffee() shop::cake + Cake() Spring3- Oh Moon Jeong - 13-13
상속 Low Coupling? shop::bakery public class Bakery{ public Bakery(){} // 케익을만들어야한다면? + Bakery() + sale(string) : Food + tostring() : String «사용» «interface» FoodMaker + make() : Food public Food sale(string type){ if(" 도넛 ".equals(type)){ FoodMaker dm = new DonutMaker( ); Donut d = dm.make(); id «사용» DonutMaker CoffeeMaker return d; }else if(" 커피 Food".equals(type)){ shop::cafe + Cafe() + sale(string) : Food + tostring() : String + make() : Donut + make() : Coffee «생성» - name: String FoodMaker cm = new CoffeeMaker( ); Coffee coffee = cm.make(); return coffee; shop::donut + Donut() shop::coffee } } + Coffee() shop::cake + Cake() public String tostring(){ return " 빵집입니다."; Spring3- Oh Moon Jeong - 14-14 }
Inversion of Control ( 이하 IoC) 란? Component dependency resolution, configuration 및 lifecycle 을해결하기 위한 Design Pattern DIP (Dependency Inversion Principle) 또는 Hollywood Principle (Don t call us we ll call you) 라는용어로도사용 특정작업을수행하기위해필요한다른컴포넌트들을직접생성하거나획득하기보다는이러한의존성들을외부에정의하고컨테이너에의해공급받는방법으로동작 Spring3- Oh Moon Jeong - 15-15
IoC IoC 의장점 클래스 / 컴포넌트의재사용성증가 단위테스트용이 Assemble과 Configure를통한시스템구축용이 IoC 와 Dependency Injection 간의관계 Spring3- Oh Moon Jeong - 16-16
Dependency Injection 예시 객체사이의의존관계를객체자체에서가아닌외부설정을이용하여주입을함으로써각객체간의의존관계를맺는것을말한다. 대표적인방법으로생성자를통한주입, 설정메소드를통한주입이있다. 조건 클래스모델이나코드에는런타임시점의의존관계가드러나지않는다. 그러기위해서는인터페이스에만의존하고있어야한다. (FoodMaker를구현한클래스가바뀌거나메서드내용이바뀌어도 Bakery에영향을주지않는다 ) 런타임시점의의존관계는컨테이너나팩토리같은제3의존재가결정한다. 의존관계는사용할오브젝트에대한레퍼런스를외부에서제공 ( 주입 ) 해줌으로써만들 어진다. Spring3- Oh Moon Jeong - 17-17
Dependency Injection class CD 음식점 Cafe Shop - foodmaker: FoodMaker + Cafe(FoodMaker) + sale() : Food + tostring() : String «사용» «interface» FoodMaker + make() : Food DonutMaker + make() : Food Bakery Shop «사용» DependencyInj ection + main(string[]) : void - foodmaker: FoodMaker + Bakery(FoodMaker) + sale() : Food + tostring() : String «생성» CoffeeMaker + make() : Food CakeMaker + make() : Food Factory + bakery() : Bakery + cafe() : Cafe + foodmaker() : FoodMaker Food # name: String + tostring() : String Coffee + Coffee() Donut + Donut() Cake + Cake() Spring3- Oh Moon Jeong - 18-18
런타임시의의존관계주입과사용의존관계 object OD 음식점 «interface» :FoodMaker :Bakery ::Bakery - foodmaker: FoodMaker «의존관계주입» «사용의존관계» :CoffeeMaker ::CoffeeMaker + make() : Food :CakeMaker «생성» :Factory Spring3- Oh Moon Jeong - 19-19
Spring Container DI 을적용하려면각객체들을생성및관리할조립기가필요하다. 개발자가직접만들수도있지만, 조립할객체가증가하고의존관계가복잡해질수록 조립기를만드는일또한어렵다. DI 패턴을지원해주는프레임워크를사용하는것을권장 Spring3- Oh Moon Jeong - 20-20
Spring Container 어플리케이션컨텍스트 = IoC Container = Bean Factory = Spring Spring3- Oh Moon Jeong - 21-21
Spring Container 스프링에서는스프링이제어권을가지고직접만들고관계를부여하는오브젝트단위의컴포넌트를 Bean이라고한다. 동시에스프링빈은스프링컨테이너가생성과관계설정, 사용등을제어해주는제어의역전이적용된오브젝트를말한다. 빈팩토리 (Bean Factory) 스프링에서는빈의생성과관계설정같은제어를담당하는 IoC오브젝트를라고부른다. 기본인터페이스명은 BeanFactory이다. 어플리케이션컨텍스트 (ApplicationContext ) 빈팩토리라부를때는주로빈생성과제어의관점에서이야기하는것이고, 라고할때는스프링이제공하는애플리케이션지원기능을모두포함한경우를말한다. 기본인터페이스명은 ApplicationContext이며 BeanFactory의하위인터페이스이다. Context 생성시모든Singleton Bean을미리 loading하여bean이필요할때즉시사용할수있도록보장한다. Spring3- Oh Moon Jeong - 22-22
Spring Container Spring3- Oh Moon Jeong - 23-23
Bean 객체설정방법 자바코드설정정보 XML 설정정보 빈설정파일 @Configuration <beans> 빈이름 @Bean methodname() <bean id= methodname 빈의클래스 return new BeanClass class= a.b.beanclass /> -- bean 기본속성 -- name : 주입받을곳에서호출할이름 id : name과같음, 단중복되면안됨. "/" 나 "," 같은특수문자포함할수없다. @Configuration class : 주입할클래스 public class Factory { } @Bean public Bakery bakery(){ return new Bakery(foodMaker()); } @Bean public FoodMaker foodmaker(){ } return new CoffeeMaker(); <bean id="bakery" class="shop.xml.bakery"> <constructor-arg name="foodmaker" ref="foodmaker"> </constructor-arg> </bean> <bean id="foodmaker" class="shop.xml.coffeemaker"> </bean> Spring3- Oh Moon Jeong - 24-24
Bean 객체사용법 ClassPathXmlApplicationContext : 클래스경로에있는xml 파일로부터로딩 ex) ApplicationContext context = new ClassPathXmlApplicatoinContext("c:/config.xml"); FileSystemXmlApplicationContext : 파일시스템에있는xml 파일로부터로딩 ex) ApplicationContext context = new FileSystemXmlApplicatoinContext("c:/config.xml"); GenericXmlApplicationContext : 클래스패스의루트에있는 xml 파일로부터로딩 ex) GenericXmlApplicationContext context = new GenericXmlApplicationContext( config.xml ); XmlWebApplicationContext : 웹어플리케이션에포함되어있는 xml 파일로부터로딩 Spring3- Oh Moon Jeong - 25-25
Bean 객체사용법 Dependency LookUp 으로빈객체사용 public class DependencyInjection{ public static void main(string []args){ AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Factory.class); Bakery b1 = ctx.getbean("bakery", Bakery.class); Bakery b2 = ctx.getbean("bakery", Bakery.class); System.out.println(b1 == b2); Food f = b1.sale(); System.out.println(f); } } Spring3- Oh Moon Jeong - 26-26
DI 의존관계설정방법 생성자방식 XML 설정파일에서생성자주입요소는 <constructor-arg> Setter 메서드방식 XML 설정파일에서 setter 주입요소는 <property> 생성자와 Setter 메서드에서공통으로쓰이는속성 단, <property> 요소는 ref속성과 value속성에만갖는다. 속성 설명 index 생성자의몇번째인수에값을넘길것인가를지정한다. type 생성자의어떤데이터타입인인수에값을넘길것인지지정한다. ref 자식요소 <ref bean= 빈이름 /> 대신사용할수있다 value 자식요소 <value> 값 </value> 대신사용할수있다. Spring3- Oh Moon Jeong - 27-27
<constructor-arg> <bean id="bakery" class="shop.xml.bakery"> <constructor-arg ><ref bean="foodmaker"/> </constructor-arg> </bean> id 가 foodmaker 인빈객체를생성자에전달 <bean id="foodmaker" class="shop.xml.coffeemaker"> public class Bakery{ </bean> private FoodMaker foodmaker; public Bakery(){} <ref> 태그대신 ref속성사용가능 public Bakery(FoodMaker foodmaker){ this.foodmaker = foodmaker; <constructor-arg ref="foodmaker"/> } public Food sale(){ return foodmaker.make( ); 전달받은파라미터가 2개이상인경우 } } <constructor-arg value="10"/> <constructor-arg ref="sender"/> value 의기본타입은 String 타입이다. 타입지정에는 type 속성설정 <constructor-arg><value>10</value></constructor-arg> <constructor-arg><value type="long">10</value></constructor-arg> Spring3- Oh Moon Jeong - 28-28
<property> <bean id="bakery" class="shop.xml.bakery"> <property name="foodmaker"><ref bean="foodmaker"/></property> </bean> <bean id="foodmaker" </bean> 참고 )null값처리 id 가 foodmaker 인빈객체를 setfoodmaker() 에전달 class="shop.xml.coffeemaker"> public class Bakery{ private FoodMaker foodmaker; public Food sale(){ return foodmaker.make( ); } public void setfoodmaker(foodmaker foodmaker) { this.foodmaker = foodmaker; } } <constructor-arg> 나 <property> 요소에서비어있는 <value> 요소를작성하면 String타입필드에는빈문자열 ( ) 가설정된다.( 숫자타입필드일경우에는예외가발생한다.) 빈문자열이아니라명시적으로 null 값을설정하려면 <value> 대신 <null> 요소를사용한다. <constructor-arg> <null/> </constructor-arg> Spring3- Oh Moon Jeong - 29-29
Collection 타입의객체설정주입 <property> 또는 <constructor-arg> 의하위태그로 Collection타입의값을설정하는태그들 태그 Collection종류 설명 <list> java.util.list List 계열컬렉션값목록전달 <set> java.util.set Set 계열컬렉션값목록전달 <map> java.util.map Map계열컬렉션에key-value의값목록전달 <props> java.util.properties Properties 에 key(string)-value(string) 의값목록전달 Spring3- Oh Moon Jeong - 30-30
Collection 타입의객체설정주입 <list> List 계열컬렉션이나배열에값들을넣기. <ref bean= bean_id /> : bean 객체를 list 에추가 <value [type= type ]> 값 </value> : 문자열 (String), Primitive 값을 list 에추가 <map> public void setmylist(list list){ } <bean id= otherbean class= vo.otherbean /> <bean id= mybean class= vo.myvo > <property name= mylist > <list><value>10</value> ->String 으로저장됨 <value type= java.lang.integer >20</value>->Integer 로저장됨 <ref bean= otherbean /> </list> </property> </bean> public void setmymap(map map){ } <bean id= otherbean class= vo.otherbean /> <bean id= mybean class= vo.myvo > <property name= mymap > <map> <entry key= id value= abc /> <entry key= other value-ref= otherbean /> </map> </property> Spring3- Oh Moon Jeong - 31-31 </bean>
autowire="byname" 의존관계자동설정 값의미 no Autowiring을하지않는다. byname Bean의프로퍼티에대한 Setter메서드의이름과같은이름의 id 를갖는 Bean객체를설정해준다. 설정파일 setter주입 <bean id="driver" class="autoby package autobyname; Name.Driver" public class Driver { autowire="byname"> private Car c; </bean> public void setcar(car c){ this.c = c; <bean id="car" } class="autobyname.civic"/> public void driving(){ </beans> c.run(); }} package autobyname; public interface Car { void run(); } package autobyname; public class Civic implements Car { public void run() { System.out.println("CIVIC이달린다."); }} Spring3- Oh Moon Jeong - 32-32
autowire="bytype" 의존관계자동설정 bytype Bean 의프로퍼티에대한 Setter 메서드의인수타입을사용해 B ean 객체를설정해준다. 설정파일 <bean id="driver" class="autobytype.driver" autowire="bytype"> </bean> <bean id="car" class="autobytype.civic"/> setter주입 package autobytype; public class Driver { private Car c; public void setaaa( Car c ){ this.c = c; } public void driving(){ c.run(); } } 또는소스파일에어노테이션을설정해서자원접근수단간소화설정파일 setter주입 <context:annotation-config/> public class Driver { @Autowired private Car c; <bean id="driver" class="autoconfig.driver"/> <bean id="car" class="autoconfig.civic"/> public void driving(){ c.run(); }} Spring3- Oh Moon Jeong - 33-33
autowire="constructor" 의존관계자동설정 constructor 생성자파라미터타입과같은타입을갖는빈객체를생성자에전달한다. 설정파일 <bean id="driver" class="autoconstructor.driver" autowire="constructor"> </bean> <bean id="car" class="autoconstructor.civic"/> 생성자주입 package autoconstructor; public class Driver { private Car c; public Driver(Car c) { this.c = c; } public void driving(){ c.run(); } } Spring3- Oh Moon Jeong - 34-34
실습 오브젝트관계에서생성할 Outputter빈은 FileOutputter타입의빈을생성한다. MessageBean빈으로는 MessageBeanImpl타입의빈을생성한다. MessageBeanImpl의빈설정은생성자injection으로 name을설정하고, setter injection으로 greeting과 outputter를설정한다. FileOutputter의 filepath는 a.txt로설정한다.(setter / 생성자주입어느것도관계없음 ) sayhello( ) 에서메시지를만들어서 [e.g)name값님 greeting값!] output( 메시지 ) 를호출한다. output( ) 에서 a.txt파일에메시지를출력한다. Spring3- Oh Moon Jeong - 35-35
실습테스트소스 package message.output; import org.springframework.context.applicationcontext; import org.springframework.context.support.filesystemxmlapplicationcontext; public class MessageTest { public static void main(string[] args) { ApplicationContext factory = new FileSystemXmlApplicationContext("src/message/output/beans.xml"); MessageBean bean =factory.getbean("messagebean", MessageBean.class); bean.sayhello( ); } } Spring3- Oh Moon Jeong - 36-36
BEAN LIFE CYCLE Spring3- Oh Moon Jeong - 37-37
Bean Scope Spring3- Oh Moon Jeong - 38-38
Bean Scope 서로다른 Scope 빈에대한의존처리 생명주기가더긴빈의의존객체로설정되면의존객체의 Scope은주입된객체의 Scope과같아진다. e.g ) Singleton빈에서 Prototype빈을사용하면 Prototype빈도 Singleton Scope을갖는다. Singleton 빈 사용 Prototype 빈 올바른범위를적용하려면 <aop:scoped-proxy/> 태그를사용 <bean id="p" class="~" scope="prototype"> <aop:scoped-proxy/> </bean> <bean id="s" class="xxx"> <property name="p" ref="p"/> </bean> Spring3- Oh Moon Jeong - 39-39
Bean Life Cycle Spring3- Oh Moon Jeong - 40-40
Bean Life Cycle bean 의 init-method 속성 설정된메서드명의메서드가빈객체생성후한번실행 <bean id="messagebean" class="lifecycle.messagebeanimpl" init-method="init"> bean 의 destroy-method 속성 설정된메서드명의메서드가빈객체가힙에서삭제되기전에실행 bean 의 lazy-init 속성 ApplicationContext 를이용하면 ApplicationContext 가초기화되는시점에모든 Bean 을생성해놓고이용한다. 하지만필요한시점에객체를생성하기원하다면 lazy-init 속성을지정한다. <bean id= messagetest class= MessageBean lazy-init= true /> bean 의 depends-on 속성 XML 에설정한순서대로 Bean 객체가생성되는것이 default 이다. 하지만 depends-on 속성으로강제순서를지정할수있다. 해당 bean 보다먼저생성해야하는 bean 을값으로준다.<bean id="userservice" class="a.service" depends-on= userdao"/> <bean id= userdao class= UserDAO /> bean 의 factory-method 속성 private 생성자를갖는빈을참조할메서드지정 Spring3- Oh Moon Jeong - 41-41
어노테이션기반설정 Spring3- Oh Moon Jeong - 42-42
어노테이션 설정파일에 <context:annotation-config> 등록 @Required 반드시의존주입되어야하는프로퍼티용 setter메서드에사용한다. @Required public void setnumber(int number){ } <bean id="r" c="a.b.foo"> <property name="number" value="1"> @Autowired 설정된생성자 / 필드 / 메서드는객체생성시자동호출됨. 프로퍼티타입으로빈찾음. 동일타입의빈이두개이상이면예외발생한다. 해당빈을찾지못하면예외발생됨. 어노테이션적용필수여부지정해서해당빈을없으면자동설정안하도록한다. @Autowired(required=false)public void seta(a a){ } Spring3- Oh Moon Jeong - 43-43
어노테이션 @Qualifier 동일타입의빈들중에서특정빈을사용하도록설정가능. @Autowired @Qualifier("main") private Recorder recorder; <bean id="re1" class="a.b.recorder"><qualifier value="main"> <bean id="re2" class="a.b.recorder"> @Resource 프로퍼티이름으로빈을찾음 @Resource private DataSource ds; @PostConstruct, @PreDestroy init-method 속성과 destroy_method 속성과같은역할 Spring3- Oh Moon Jeong - 44-44
어노테이션 @Component XML에 <bean> 을설정하지않아도자동검색되어빈으로등록될클래스에선언한다. 단, xml에 <context:component-scan base-package=" 자동검색할패키지명 "/> 을지정한다. 빈의 name을지정하려면어노테이션속성값을지정한다. @Component("aController") 빈의 scope을지정하려면 @Scope어노테이션을추가한다. @Component@Scope("prototype") @Configuration 스프링3에서는 XML대신자바코드로스프링컨테이너에빈객체를제공할수있다. 빈객체설정용클래스에선언한다. @Bean @Configuration클래스에서새로운빈객체를제공할때사용된다. 메서드이름이아닌다른이름을빈객체의 name으로사용하려면어노테이션의 name 속성을사용한다 @Bean(name="cDAO") public CustomerDAO customerdao(){ } Spring3- Oh Moon Jeong - 45-45
실습개요 스프링데이터소스용 API인 org.springframework.jdbc.datasource.simpledriverdatasource를주입해서매번db와의연결중복을피한다. SimpleDriverDataSource는 org.springframework.jdbc-3.0.1.release.jar에있으므로 build path에추가해야한다. Spring3- Oh Moon Jeong - 46-46
실습테스트소스 package datasource; : public class CustomerDAOTest{ public static void main(string []args){ // 실습1 Lookup방법 ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("dsApplicationContext.xml", CustomerDAOTest.class); // 실습2 Lookup방법 /*AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(DAOFactory.class); */ CustomerDAO dao = ctx.getbean("customerdao", CustomerDAO.class); try { Customer c = dao.findbyid("id0"); } catch (Exception e) { e.printstacktrace(); } } } Spring3- Oh Moon Jeong - 47-47
실습 1 - Autowired 를이용한 CustomerDAOImpl 과설정파일만들기 :CustomerDao Impl 실습내용 XML 설정파일을완성하고, CustomerDAOImpl 에 datasource 를 autowire 한다 DataSource 용설정내용은아래와같다. 파일명 : (dsapplication.xml) <bean id="datasource" class="org.springframework.jdbc.datasource.simpledriverdatasource"> <property name="driverclass" value=""/> <property name="url" value=""/> <property name="username" value=""/> <property name="password" value=""/> </bean> Spring3- Oh Moon Jeong - 48-48
실습 2 - @Controller 어노테이션를이용하는 Factory 클래스만들기 Autowire 실습에서사용한 XML 설정파일대신어노테이션을활용한 Factory 클 래스를사용한다. 클래스이름 : DAOFactory object OD 데이터소스 :CustomerDao :CustomerDAO Impl «interface» :DataSource «의존관계주입» «사용의존관계» :SimpleDataSource :DAOFactory «생성» Spring3- Oh Moon Jeong - 49-49
Aspect Oriented Programming AOP Spring3- Oh Moon Jeong - 50-50
Aspect Oriented Programming 여러업무의공통기능을클래스단위로모으고모듈로부터분리함으로써재사용성과보수성을높이는것이 OOP이다. 그러나그기능을사용하기위한코드까지는각모듈로부터분리할수없었다. 그렇기때문에분리한기능을이용하기위해서는코드가각모듈에횡단으로산재 (Cross -cutting Concern) 하게된다. 핵심관심 (core concerns) 시스템의핵심가치와목적이그대로드러난관심영역.. 비즈니스로직 횡단관심 (crosscutting concern) 아래와같은쉽게모듈화되지않는부분 -로그작성(logging), -보안/ 인증 (security/authentication), -트랜잭션(transaction), -리소스풀링 (resource pooling), -에러검사(error checking), -정책적용(policy), -멀티쓰레드안전관리 (multithread), -데이터퍼시스턴스 (persistence) 등 Spring3- Oh Moon Jeong - 51-51
Aspect Oriented Programming Aspect Oriented Programming 핵심관심사항과횡단관심사항 ( 공통모듈 ) 을기준으로프로그래밍함으로써공통모듈을손쉽게적용할수있게해준다. AOP에서는횡단관점까지분리하여각모듈로부터관점에관한코드를완전히제거하는것을목표로한다. Spring3- Oh Moon Jeong - 52-52
AOP 용어 Weaving : Advice 를 Pointcut 에삽입하는것 프로그램실행순서 Advisor pointcut A WHEN + WHAT ( 공통코드 ) 공통관심기능을언제핵심로직에적용할지를정의한것 Advice X Advice 를적용가능한지점을말한다. 핵심로직 joinpoint Advisor pointcut B WHERE 여러개의조인포인트를하나로결합한것 Advice 와 Pointcut 을하나로묶어취급한빈 Advice Y Spring3- Oh Moon Jeong - 53-53
Weaving 방식 Weaving Advice 를 Pointcut 에삽입하는것 컴파일시에 Weaving AspectJ에서사용하는방식 컴파일할때알맞은위치에공통코드를삽입 클래스로딩시에 Weaving (LoadTimeWeaving) AspectJ에서사용하는방식 로딩한클래스의바이너리정보를변경하여알맞은위치에공통코드를삽입한새로운바이너리코드를사용한다. 원본클래스파일은변경하지않는다. 런타임시에 Weaving ( 동적 AOP) 프록시를생성하여핵심로직을구현한객체에접근하게된다. Spring3- Oh Moon Jeong - 54-54
클래스다이어그램 <<interface>> MessageBean +sayhello(name:string) Spring AOP Logging 처리 MessageBeanImpl +sayhello(name:string) Spring3- Oh Moon Jeong - 55-55
Proxy 기반 AOP 구현 필요라이브러리 org.springframwork.aop-3.x-release.jar com.springsource.org.aopalliance-1.0.0.jar AOP 구현절차 1. Advice 클래스작성하기. 설정파일에 Advide설정한다. 2. 설정파일에 PointCut을설정한다. 3. 설정파일에 Advice와 PointCut을묶어놓은 Advisor를설정한다. 4. 설정파일에 ProxyFactoryBean클래스를이용하여대상객체에 Advisor를적용한다. 5. getbean() 메소드로빈객체를가져와사용한다. Spring3- Oh Moon Jeong - 56-56
Proxy 기반 AOP <<interface>> MessageBean +sayhello(name:string) <bean id="messagebean" Proxy +sayhello(name:string) <<interface>> MethodInterceptor +invoke( ) Target ( 핵심기능 ) MessageBeanImpl +sayhello(name:string) JoinPoint <bean id="proxy"> 프록시에서쓰일 Target 빈주입 Advisor 빈주입 LogginAdvice ( 부가기능 ) +invoke( ) <bean id="logginadvice"> Advisor <bean id="helloadvisor" ~> 사용할 Advice 빈주입 Pointcut 용메서드설정 Spring3- Oh Moon Jeong - 57-57
Proxy 패턴 다이나믹프록시와프록시팩토리빈 프록시클래스없이도프록시오브젝트를런타임시에만들어주는 JDK다이나믹프록시기술을적용할수있다. 하지만동일한기능의프록시를여러오브젝트에적용할경우오브젝트단위로중복이일어나는문제가있다. JDK다이나믹프록시와같은프록시기술을추상화한스프링의프록시팩토리빈을이용해서다이나믹프로시생성방법에 DI를도입했다. 스프링의 ProxyFactoryBean은프록시를생성해서빈오브젝트로등록하게해주는팩토리빈이다. Spring3- Oh Moon Jeong - 58-58
Proxy 기반 AOP 구현절차 1. Advice 클래스작성하기 (aop.loggingadvic) advice 타입인터페이스설명 Before advice After returning advice org.springframework.ao p. MethodBeforeAdvice org.springframework.ao p. AfterReturningAdvice joinpoint 전에수행되는 advice. 하지만 joinpoint 를위한수행흐름처리 (execution flow proceeding) 를막기위한능력 ( 만약예외를던지지않는다면 ) 을가지지는않는다. joinpoint 이일반적으로예를들어메소드가예외를던지는것없이반환된다면완성된후에수행되는 advice. After throwing advice Around advice org.springframework.ao p.throwsadvice org.aopalliance.intercept.methodinterceptor 메소드가예외를던져서빠져나갈때수행되는 advice 메소드호출과같은 joinpoint 주위 (surround) 의 advice. 이것은가장강력한종류의 advice 이다. Around advice 는메소드호출전후에사용자정의행위를수행할수있다. joinpoint 를처리하거나자기자신의반환값을반환함으로써짧게수행하거나예외를던지는것인지에대해책임을진다. Spring3- Oh Moon Jeong - 59-59
Proxy 기반 AOP 구현절차 설정파일명 : e.g src/sample1/proxyaop.xml 1. 설정파일에 Advice 빈설정한다. <bean id="loggingadvice" class="sample1.loggingadvice" /> 2. 설정파일에 Advisor (Advice 참조정보와 PointCut) 를설정한다. <bean id="helloadvisor" class="org.springframework.aop.support.defaultpointcutadvisor"> <property name="advice"> <ref local="loggingadvice" /> </property> <property name="pointcut"> <bean class="org.springframework.aop.support.jdkregexpmethodpointcut"> <property name="pattern"> <!-- 메서드이름중 'sayhello' 가포함된메소드의호출을 PointCut 으로지정하게된다.--> <value>.*sayhello.*</value> </property> </bean> </property> </bean> Spring3- Oh Moon Jeong - 60-60
Proxy 기반 AOP 구현절차 4. 설정파일에 ProxyFactoryBean 클래스를이용하여대상객체에 Advisor 를 적용한다. <bean id="targetbean" class="aop.messagebeanimpl"> <property name="name"> <value>spring</value> </property> </bean> <!-- 프록시클래스를매번개발자가구현하기어려워, JD 다이나믹프록시기술기반의 " 스프링프록시팩토리빈 " 을이용한다. 프록시를생성해서빈객체로등록해주는팩토리빈이다. --> <bean id="proxy" class="org.springframework.aop.framework.proxyfactorybean"> <property name="target"> <ref local="targetbean" /> </property> <property name="interceptornames"> <!-- 적용할 Advice/Advisor 를지정한다. --> <list> <value>helloadvisor</value> </list> </property> Spring3- Oh Moon Jeong - 61-61
Proxy 기반 AOP 구현절차 5. getbean() 메소드로빈객체를가져와사용한다. package sample1; import org.springframework.context.support.filesystemxmlapplicationcontext; public class AopTest { public static void main(string[] args) { FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext("src/sample1/proxyaop.xml"); //MessageBean인터페이스를구현한 //MessageBeanImpl( 핵심관점용빈 : 타깃 ), XXX클래스 ( 부가관점용빈 : 프록시 ) 가있다. // 클라이언트는프록시를 lookup MessageBean bean = ctx.getbean("proxy", MessageBean.class); } // 클라이언트가프록시의 sayhello() 를요청하면 // 포인트컷으로설정된타깃의 sayhello() 메서드호출전후에 // 어드바이스 :sample1.loggingadvice를수행한다. bean.sayhello(); } Spring3- Oh Moon Jeong - 62-62
AspectJ 기반 AOP 구현 필요라이브러리 com.springsource.org.aspect-1.6.6-release.jar aspectjrt.jar aspectjweaver.jar AspectJ 포인트컷표현식은포인트컷지시자를이용해작성한다. 포인트컷지시자중가장대표적으로사용되는지사자가 execution( ) 이다. [ ] 는생략가능, 는 OR 조건이다. 포인트컷설명 execution Bean의조건에맞는메서드나생성자의실행을 Pointcut으로한다. within Bean이조건에설정한타입이라면메서드의실행을 Pointcut으로한다. this Bean이조건에설정한타입에대입할수있는인스턴스라면, 메서드실행을 Point cut으로한다. target 대상이되는객체가조건에설정된타입에대입할수있는인스턴스라면, 메서드의실행을 Pointcut으로한다. args 메서드의인수가조건에설정한타입에대입할수있는인스턴스라면, 메서드실행을 Pointcut으로한다. Spring3- Oh Moon Jeong - 63-63
AspectJ포인트컷표현식 패턴문자 * : 1개의모든값을표현 ( 파라미터로쓰일경우 1개의파라미터, execution ( package로쓰일경우 1개의하위패키지 ).. : 0개이상 [ 접근제한자패턴 ] 리턴값타입패턴 - 반드시하나의타입을지정해야한다. 또는 * 를써서모든타입을다선택하겠다고해도된다. [ 패키지와클래스이름에대한타입패턴 ] -사용할때는패키지. 클래스형태로. 을두어연결해야한다 * 를이용할 수있다... 를사용하면한번에여러개의패키지를선택할수있다. 메서드이름패턴 -모든메서드를다선택하겠다면 * 를넣으면된다. ( 파라미터타입패턴.., ) 파라미터의타입패턴을순서대로넣을수있다. 파라미터가없는메서드를지정하려면 ( ) 로적는다파라미터의타입과개수에상관없이모두다허용하는패턴을만드려면.. 을넣으면된다. 을사용해서뒷부분의파라미터조건만생략할수있다 [ throws 예외패턴 ] ) Spring3- Oh Moon Jeong - 64-64
AspectJ 포인트컷표현식 within within( 패키지패턴. 클래스패턴 ) e.g) within(test.spring.service.memberservice), within(test.spring..memberservlice) bean bean(bean이름패턴 ) e.g) bean(memberservice), bean(*service) Spring3- Oh Moon Jeong - 65-65
AspectJ 포인트컷표현식의메서드선정예제 ex) a.b.targetinterface +hello( ) +hello(string) +plus(int, int) +minus(int, int) a.b.target a.b.target void void hello() hello(string) 1 execution(* hello(.. ) ) o o 2 execution(* hello( ) ) o 3 execution(* hello(string) o int plus( int,int) int minus(int,int ) throws RuntimeExcept ion void method( ) a.b.bean void method( ) throws Runtime Exceptio n 4 execution(* meth*(..) ) o o 5 execution(* *(int, int) ) o o 6 execution(* *( ) ) o o o 7 execution(* a.b.target.*(..)) o o o o o 8 execution(* a.b.*.*(..)) o o o o o o 9 execution(* a.b..*.*(..)) o o o o o O 10 execution(* a..*.*(..)) o o o o o O 11 execution(* com..*.*(..)) 12 execution(* *..Target.*(..)) o o o o O 13 execution(* *..Tar*.*(..)) o o o o O 14 execution(* *..*get.*(..)) O o o o o 15 execution(* *..B*.*(..)) O 16 execution(* *..TargetInterface.*(..)) o o o O 17 execution(* *(..) throws Runtime*) O O 18 execution(int *(..)) o O 19 execution(void *(..)) o o o O Spring3- Oh Moon Jeong - 66-66
AspectJ 기반 AOP Advice 종류 Before Advice 대상객체의메소드가실행되기전에실행됨 return type : 상관없다. argument : 없거나JoinPoint객체를받는다. <aop:before method="logbefore" pointcut-ref="logpointcut" /> public void logbefore(joinpoint jp){ } Spring3- Oh Moon Jeong - 67-67
AspectJ 기반 AOP Advice 종류 After Returing Advice 대상객체의메소드실행이정상적으로끝난뒤실행됨 return type : 상관없다. argument : 없거나 JoinPoint 객체를받는다. 없거나 JoinPoint 객체를받는다. JoinPoint 는항상첫 argument 로사용 된다. 대상메소드에서리턴되는값을 argument 로받을수있다. type : Object 또는대상메소드에서 return 하는 value 의 type <aop:after-returning pointcut-ref= publicmethod method="returnlogging" returning= retvalue /> public void returnlogging(object retvalue){ } 87 Spring3- Oh Moon Jeong - 68-68
AspectJ 기반 AOP Advice 종류 After Throwing Advice 대상객체의메소드실행중예외가발생한경우실행됨 return type : 상관없으나void로한다. argument : 없거나 JoinPoint객체를받는다. JoinPoint는항상첫argument로사용된다. 대상메소드에서전달되는예외객체를 argument로받을수있다. <aop:after-throwing pointcut-ref= publicmethod method="throwinglogging" throwing="ex"/> public void throwinglogging(joinpoint jp, MyException ex){ } Spring3- Oh Moon Jeong - 69-69
AspectJ 기반 AOP Advice 종류 After Advice 대상객체의메소드실행이종료된뒤오류발생여부와상관없이무조건실행된다. return type : 상관없다. argument : 없거나JoinPoint객체를받는다. <aop:afterpointcut-ref= publicmethod method= afterlogging /> public void afterlogging(){ } Spring3- Oh Moon Jeong - 70-70
AspectJ 기반 AOP Advice 종류 Around Advice 위의네가지Advice를다구현할수있는Advice. return type : Object argument JoinPoint를반드시첫argument로지정한다. <aop:around pointcut-ref= publicmethod method= aroundlogging /> public Object aroundlogging(proceedingjoinpointjoinpoint) throws Throwable{ // 대상객체의메소드호출전해야할전처리코드 Object retvalue = joinpoint.proceed(); // 대상객체의메소드호출 // 대상객체처리이후해야할후처리코드 } return retvalue; // 호출한곳으로리턴값넘긴다. 넘기기전수정가능 Spring3- Oh Moon Jeong - 71-71
JoinPoint 대상객체에대한정보를가지고있는객체로 Spring container 로부터받는다. org.aspectj.lang패키지에있음 반드시Advice 메소드의첫argument로와야한다. 메소드들 Signature: 호출되는대상객체에대한구문정보를가진객체 Object gettarget() : 대상객체를리턴 Object[] getargs() : 파라미터로넘겨진값들을배열로리턴. 넘어온값이없으면빈배열개체가return 됨. Signature getsignature() : 호출되는메소드의정보 String getname() : 대상메소드명리턴 String toshorstring() : 대상메소드명리턴 String tolongstring() : 대상메서드전체syntax를리턴 String getdeclaringtypename() : 대상메소드가포함된type을return. (package명.type명) Spring3- Oh Moon Jeong - 72-72
AspectJ 기반 AOP 구현절차 1. Advice 클래스작성하기 (aspectj.loggingadvice) 2. 설정파일에 Advice 빈설정한다. ( 설정파일명 : e.g src/aspectj/aspectjaop.xml ) <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" 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-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <!-- advice 담당 --> <bean id="loggingadvice" class="aspectj.loggingadvice" /> Spring3- Oh Moon Jeong - 73-73
AOP 설정태그 <aop:config> : aop설정의root 태그. Aspect 설정들의묶음 <aop:aspect> : Aspect 설정 하나의Aspect 설정, Aspect가여러개일경우 <aop:aspect> 태그가여러개온다. 한개의Aspect (advice + pointcut) 을설정 속성 ref : 공통관심사항을설정한Bean(Advice 빈 ) 참조 id: 식별자. 다른Aspect 태그와구별하기위한식별자 자식태그 <aop:pointcut> : pointcut지정 advice관련태그가올수있다. Spring3- Oh Moon Jeong - 74-74
AOP 설정태그 <aop:pointcut> : Advice 에서참조할 pointcut 설정 Pointcut( 공통기능이적용될곳 ) 을지정하는태그 <aop:config> 나 <aop:aspect> 의자식태그 AspectJ표현식을통해 pointcut지정 속성 : id : 식별자로advice 태그에서사용됨 expression : pointcut지정 <aop:pointcut id= publicmethod expression= execution(public * org.myspring..*.*(..)) /> Advice Weaving 설정태그들 A. <aop:before> -메소드실행전실행될Advice B. <aop:after-returning> -메소드정상실행후실행될Advice C.<aop:after-throwing> -메소드에서예외발생시실행될Advice D.<aop:after> -메소드정상또는예외발생상관없이실행될Advice finally E.<aop:around> -모든시점에서적용시킬수있는Advice 구현 Spring3- Oh Moon Jeong - 75-75
설정파일샘플 <aop:config> <!-- advice참조 --> <aop:aspect id="logaspece" ref="loggingadvice"> <!-- pointcut지정 --> <aop:pointcut expression="execution(* sayhello() )" id="logpointcut"/> <!-- weaving 방법 --> <aop:before method="logbefore" pointcut-ref="logpointcut" /> <aop:after-returning method="logafterreturning" pointcut-ref="logpointcut" /> <aop:after method="logafter" pointcut-ref="logpointcut"/> <aop:around method="logaround" pointcut-ref="logpointcut" </aop:aspect> </aop:config> <bean id="targetbean" class="aspectj.messagebeanimpl"> <property name="name"><value>spring</value></property> </bean> Spring3- Oh Moon Jeong - 76-76
AspectJ 기반 AOP 구현절차 3. getbean() 메소드로빈객체를가져와사용한다. public class AspectjTest { public static void main(string[] args) { FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext("src/aspectj/aspectjaop.xml"); MessageBean bean = ctx.getbean("targetbean", MessageBean.class); bean.sayhello(); } } Spring3- Oh Moon Jeong - 77-77
@Aspect 어노테이션을이용한 AOP @Aspect 어노테이션을이용하여Aspect 클래스에직접Advice 및Pointcut등을직접설정 설정파일에 <aop:aspectj-autoproxy/> 를추가해야함 Aspect class를 <bean> 으로등록 어노테이션 (Annotation) @Aspect : Aspect 클래스선언 @Before( pointcut ) @AfterReturning(pointcut=, returning= ) @AfterThrowing(pointcut=, throwing= ) @After( pointcut ) @Around( pointcut ) Around를제외한나머지메소드들은첫argument로 JoinPoint를가질수있다. Around메소드는 argument로 ProceedingJoinPoint를가질수있다. Spring3- Oh Moon Jeong - 78-78
@Aspect 어노테이션을이용한 AOP 구현절차 1. Advice 클래스작성하기 @Aspect public class LoggingAdvice { @Pointcut("execution(* sayhello() )") public void pointcut(){ } // 포인트컷을적용한메서드. Advice 관련어노테이션에서해당메서드이름으로포인트컷을사용할수있게된다. @Before("pointcut()") public Object logbefore(joinpoint jp) throws Throwable{ } @Around("execution(* sayhello() )") public Object logaround(proceedingjoinpoint pjp) throws Throwable { } Spring3- Oh Moon Jeong - 79-79
@Aspect 어노테이션을이용한 AOP 구현절차 2. 설정파일에 aspectj-autoproxy 요소를설정한다. ( 설정파일명 : e.g src/aspectj/aspectjannotation.xml )) <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <aop:aspectj-autoproxy /> <bean id="loggingadvice" class="aspectj.annotation.loggingadvice" /> <bean id="targetbean" class="aspectj.annotation.messagebeanimpl"> <property name="name"> <value>spring</value> </bean> </property> Spring3- Oh Moon Jeong - 80-80
스프링 JDBC Spring3- Oh Moon Jeong - 81-81
부가기능과핵심기능 add( ) PreparedStatement pstmt = 추가작업 pstmt.executeupdate( ) delete( ) PreparedStatement pstmt = 삭제작업 pstmt.executeupdate( ) 기능 변하는부분 변하지않는부분 Spring3- Oh Moon Jeong - 82-82
Template Method Pattern <<abstract>>customerdao add( ) PreparedStatement pstmt = makestatement( ); pstmt.executeupdate( ) delete( ) PreparedStatement pstmt = makestatement( ); pstmt.executeupdate( ) abstract makestatement( ) : PreparedStatement CustomerDAOAdd makestatement( ) PreparedStatement pstmt = con.preparestatement( sql ); // 추가작업 pstmt.setstring(1, id) ; pstmt.setstring(2, name); pstmt.setstring(3, password); return pstmt; CustomerDAODelete makestatement( ) PreparedStatement pstmt = con.preparestatement( sql ); // 삭제작업 pstmt.setstring(1, id) ; return pstmt; Spring3- Oh Moon Jeong - 83-83
Strategy Pattern client Strategy 제공 변하지않는부분을말함자주변하는부분을만들어줄외부기능을말함 Context Context 정보제공 Strategy strategy 선택, 생성 Concrete Strategy A Concrete Strategy B Spring3- Oh Moon Jeong - 84-84
Strategy Pattern class Class Model 2. Context CustomerDAO 3 Strategy «interface» StatementStrategy + makestatement(connection) : PreparedStatement + jdbccontextwithstatementstrategy(statementstratagy) : void Connection con=null; PreparedStatement pstmt =null; try { con= datasource.getconnection(); DeleteStatement + makestatement(connection) : PreparedStatement pstmt = stmt.makestatement(con); pstmt.executeupdate(); }catch(sqlexception sqle){ throw sqle; }finally{ if(pstmt!= null) pstmt.close(); if(con!= null) con.close(); } + add(customer) : void StatementStratgy st = new AddStatement(c); jdbccontextwithstatementstrategy(st); Context 정보제공 - c: Customer AddStatement + AddStatement(Customer) + makestatement(connection) : PreparedStatement String sql = "INSERT INTO customer" + " (ID, PASSWORD, NAME, GENDER, ZIP, REGDATE, ADDRESS) " + " VALUES (?,?,?,?,?, SYSDATE,?)"; 1. 클라이언트가 strategy 선택 PreparedStatement pstmt = con.preparestatement(sql); pstmt.setstring(1, c.getid()); pstmt.setstring(2, c.getpassword()); pstmt.setstring(3, c.getname()); pstmt.setstring(4, c.getgender()); pstmt.setstring(5, c.getzip()); pstmt.setstring(6, c.getaddress()); Spring3- Oh Moon Jeong - 85-85
Context 와 DI 변하지않는 Context부분 (jdbccontextwithstatementstrategy) 은다른클라이언트 (XXXDAO) 들에게도사용가능하다. 따라서 Context를클라이언트 (CustomerDAO) 에서분리해본다. 이렇게분리된 Context를템플릿이라고할수있다. Spring3- Oh Moon Jeong - 86-86
Context 를템플릿클래스로분리, 변경 Spring3- Oh Moon Jeong - 87-87
DI 설정 <bean id="customerdao" class="com.my.dao.customerdao"> <property name="datasource" ref="datasource" /> </bean> <bean id="datasource" class="org.springframework.jdbc.datasource.simpledriverdatasource"> <property name="driverclass" value="oracle.jdbc.driver.oracledriver"/> <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:xe"/> <property name="username" value="hr"/> <property name="password" value="hr"/> </bean> Spring3- Oh Moon Jeong - 88-88
구현 Strategy 를클라이언트의 Anonymous Class 로변경 public void add(final Customer c) throws SQLException{ jdbccontext.workwithstatementstrategy( new StatementStrategy( ){ public PreparedStatement makestatement(connection con) throws SQLException{ String sql = "INSERT INTO customer" + " " (ID, PASSWORD, NAME, GENDER, ZIP, REGDATE, ADDRESS) " + " VALUES (?,?,?,?,?, SYSDATE,?)"; PreparedStatement pstmt = con.preparestatement(sql); pstmt.setstring(1, c.getid()); pstmt.setstring(2, c.getpassword()); pstmt.setstring(3, c.getname()); pstmt.setstring(4, c.getgender()); pstmt.setstring(5, c.getzip()); pstmt.setstring(6, c.getaddress()); return pstmt; } } ); } Spring3- Oh Moon Jeong - 89-89
Template Callback 패턴을 2. Template public void add(final Customer c) throws 호출 SQLException{ jdbccontext.workwithstatementstrategy( new StatementStrategy( ){ public PreparedStatement makestatement(connection con) throws SQLException{ String sql = "INSERT INTO customer" + " " (ID, PASSWORD, NAME, GENDER, ZIP, REGDATE, ADDRESS) " + " VALUES (?,?,?,?,?, SYSDATE,?)"; PreparedStatement pstmt = con.preparestatement(sql); } pstmt.setstring(1, c.getid()); pstmt.setstring(2, c.getpassword()); pstmt.setstring(3, c.getname()); pstmt.setstring(4, c.getgender()); pstmt.setstring(5, c.getzip()); pstmt.setstring(6, c.getaddress()); return pstmt; public class JdbcContext { private DataSource datasource; public void setdatasource(datasource datasource) { this.datasource = datasource; } // 템플릿 public void workwithstatementstrategy( StatementStrategy stmt) throws SQLException{ 3. 참조정보생성 Connection con=null; PreparedStatement pstmt =null; try { con= datasource.getconnection(); pstmt = stmt.makestatement(con); pstmt.executeupdate(); }catch(sqlexception sqle){ 4. Callback호출 throw sqle; 7. 작업수행 }finally{ if(pstmt!= null) pstmt.close(); if(con!= null) con.close(); } } } Spring3- Oh Moon Jeong - 90-90 } ); 1. Callback 생성 5. 클라이언트 final 변수참조 6. 작업수행후반환
콜백부분의변하는구문과변하지않는구문분리이전 public void add(final Customer c) throws SQLException{ jdbccontext.workwithstatementstrategy( 변하지않는부분 new StatementStrategy( ){ public PreparedStatement makestatement(connection con) throws SQLException{ 변하는부분 String sql = "INSERT INTO customer" + " " (ID, PASSWORD, NAME, GENDER, ZIP, REGDATE, ADDRESS) " + " VALUES (?,?,?,?,?, SYSDATE,?)"; PreparedStatement pstmt = con.preparestatement(sql); pstmt.setstring(1, c.getid()); pstmt.setstring(2, c.getpassword()); pstmt.setstring(3, c.getname()); pstmt.setstring(4, c.getgender()); pstmt.setstring(5, c.getzip()); pstmt.setstring(6, c.getaddress()); Spring3- Oh Moon Jeong - 91-91 return pstmt;
콜백부분의구문분리이후 public class CustomerDAO {.. public void add(final Customer c) throws SQLException{ String sql ="INSERT INTO customer" + " (ID, PASSWORD, NAME, GENDER, ZIP, REGDATE, ADDRESS) " + " VALUES (?,?,?,?,?, SYSDATE,?)"; jdbccontext.executesql( sql, c.getid(), c.getpassword(), c.getname(), c.getgender(), c.getzip(),c.getaddress()); } -------------------------------------------------------------------------------------------------------------- public class JdbcContext {. private void executesql(final String sql, final Object... args) throws SQLException { jdbccontext.workwithstatementstrategy(new StatementStrategy(){ public PreparedStatement makestatement(connection con) throws SQLException{ PreparedStatement pstmt = con.preparestatement(sql); for(int i=0; i<args.length; i++){ pstmt.setobject(i+1, args[i]); } return pstmt; } }); } Spring3- Oh Moon Jeong - 92-92 }
스프링 JDBC API JdbcTemplate 스프링은 JDBC를이용하는 DAO에서사용할수있도록준비된다양한템플릿을제공한다. 거의모든종류의 JDBC코드에사용가능한템플릿과콜백을제공한다. SimpleJdbcTemplate JdbcTemplate과 NamedParameterJdbcTemplate에서가장많이사용되는기능을통합하고 JAVA5이상의장점을최대한활용할수있게만든 API이다. JDBC의모든기능을최대한활용할수있는유연성을갖고있다. SimpleJdbcInsert, SimpleJdbcCall DB가제공해주는메타정보를활용해서최소한의코드만으로단순한 JDBC코드를작성하게해준다 Spring3- Oh Moon Jeong - 93-93
스프링의 JdbcTemplate update( ) String sql = "INSERT INTO customer(id, PASSWORD, NAME) VALUES (?,?,?) "; jdbctemplate.update( sql, c.getid(), c.getpassword(), c.getname() ); queryforobject( ) String sql = "SELECT * FROM customer WHERE id=?"; String idvalue = "id0"; jdbctemplate.queryforobject( sql, new Object[]{ idvalue }, new RowMapper<Customer>() { public Customer maprow(resultset rs, int rownum) throws SQLException{ Customer c = new Customer(); c.setid(rs.getstring("id")); c.setpassword(rs.getstring("password")); c.setname(rs.getstring("name")); return c; } } ); Spring3- Oh Moon Jeong - 94-94
스프링의 JdbcTemplate query queryforint String sql = "SELECT * FROM customer ORDER BY id"; jdbctemplate.query( sql, new RowMapper<Customer>( ){ public Customer maprow(resultset rs, int rownum) throws SQLException { Customer c = new Customer(); c.setid(rs.getstring("id")); c.setpassword(rs.getstring("password")); c.setname(rs.getstring("name")); return c; } } ); String sql = "SELECT COUNT(*) FROM customer"; return this.jdbctemplate.queryforint(sql); Spring3- Oh Moon Jeong - 95-95
스프링 JDBC API 스프링 JDBC 가해주는작업 Connection열기, 닫기 Statement준비와닫기 Statement실행 ResultSet반복 예외처리와변환 : JDBC작업중발생하는모든예외는스프링JDBC의예외변환기가처리해준다. CheckedException인 SQLException을 RuntimeException인 DataAccessException타입으로변환해준다. 런타임예외로전환할뿐아니라 DB별에러코드를참고해서일관된의미를가진 DataAccessException 계층구조내의예외로변환해준다. 트랜잭션처리 : 스프링JDBC는트랜잭션동기화기법을이용해선언적트랜잭션기능과맞물려돌아간다. 트랜잭션을시작한후에스프링 JDBC의작업을요청하면진행중인트랜잭션에참여한다. 트랜잭션이없는채로호출될경우에는새로운트랜잭션을만들어서사용하고작업을마치면트랜잭션을종료한다. Spring3- Oh Moon Jeong - 96-96
SpringJDBC 용 Exception DataAccessException NonTransient DataAccessException DataIntegrityViolation Exception DataRetrievalFailure Exception PermissionDenied DataAccessException InvalidDataAccessResour ceusageexception DuplicateKey Exception BadSqlGrammar Exception TypeMismatch DataAccessException Spring3- Oh Moon Jeong - 97-97
SPRING MVC Spring3- Oh Moon Jeong - 98-98
Spring MVC 구성주요컴포넌트 DispatcherServlet - Front Controller Controller - 클라이언트요청처리를수행하는 Controller HandlerMapping - 클라이언트의요청을처리할 Controller를찾는작업처리 View - 응답하는로직을처리 ViewResolver - 응답할 View를찾는작업을처리 ModelAndView - 응답할 View와 View에게전달할값을저장하는용도의객체 Spring3- Oh Moon Jeong - 99-99
Spring MVC 를이용한어플리케이션작성순서 1. web.xml에 DispacherServlet등록및ㅌ등록 2. 설정파일에 HandlerMapping 설정 3. 컨트롤러구현및 Spring 설정파일에등록 4. 컨트롤러와 JSP의연결위해 View Resolver설정 5. JSP코드작성 Spring3- Oh Moon Jeong - 100-100
web.xml 에 DispatcherServlet 설정 <servlet> <servlet-name>web1</servlet-name> <servlet-class>org.springframework.web.servlet.dispatcherservlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>web1</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> Spring3- Oh Moon Jeong - 101-101
web.xml 의캐릭터인코딩처리를위한필터설정 <filter> <filter-name>encodingfilter</filter-name> <filter-class>org.springframework.web.filter.characterencodingfilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>euc-kr</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingfilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> Spring3- Oh Moon Jeong - 102-102
스프링설정파일 Spring Container는설정파일의내용을읽어 WebApplicationContext객체를생성 설정파일내용 MVC 구성요소 (HandlerMapping, Controller, ViewResolver, View) 설정 bean, aop를설정 설정파일명기본작성규칙 "<servlet-name>-servlet.xml" WEB-INF\ 아래에추가한다. Spring3- Oh Moon Jeong - 103-103
스프링설정파일 다른이름의설정파일또는여러설정파일이필요할경우 <servlet> 의하위태그인 <init-param> 에 contextconfiglocation이름으로등록 경로는Application Root부터절대경로로표시 여러개의경우, 또는공백으로구분 <servlet> <servlet-name>web1</servlet-name> <servlet-class>org.springframework.web.servlet.dispatcherservlet</servlet-class> <load-on-startup>1</load-on-startup> <init-param> <param-name>contextconfiglocation</param-name> <param-value>/web-inf/server-service.xml /WEB-INF/dao-service.xml </param-value> </init-param> </servlet> Spring3- Oh Moon Jeong - 104-104
스프링설정파일 공통 Spring 설정파일등록 공통스프링설정파일들을로드하기위해리스너 (ContextLoaderListener) 설정 공통스프링설정파일명은 applicationcontext.xml 이다. <listener> <listener-class> org.springframework.web.context.contextloaderlistener </listener-class> </listener> 공통설정파일이여러개인경우 <context-param> <param-name>contextconfiglocation</param-name> <param-value>/web-inf/service-service.xml /WEB-INF/dao-data.xml </param-value> </context-param> Spring3- Oh Moon Jeong - 105-105
HandlerMapping RequestURL과컨트롤러를매핑시켜준다. 다양한 HandlerMapping 클래스를 Springframework가제공 Spring 설정파일에 <bean> 으로등록해서설정한다. HandlerMapping 인터페이스를구현한클래스들 종류 BeanNameUrlHandlerMapping 빈으로등록여부 DEFAULT SimpleUrlHandlerMapping ControllerBeanNameHandlerMapping ControllerClassNameHandlerMapping DefaultAnnotationHandlerMapping DEFAULT 매핑방법 Ant 경로패턴? : 1 개의문자와매칭 * : 0 개의문자와매칭 ** : 0 개이상의디렉터리와매칭 Spring3- Oh Moon Jeong - 106-106
HandlerMapping BeanNameUrlHandlerMapping 빈이름을이용해매핑해주는핸들러매핑전략이다. url과일치하는빈이름을갖는빈을컨트롤러로사용한다. 디폴트핸들러매핑이기때문에 BeanNameUrlHandlerMapping을빈으로등록하지않아도된다. <bean class="org.springframework.web.servlet.handler.beannameurlhandlermapping" /> <bean name="/test.do" class="web1.testcontroller"/> 빈아이디를이용못함 id에는 / 추가못함 <!-- <bean id="/test.do" class="web1.testcontroller"/> --> public class TestController implements Controller{ } Spring3- Oh Moon Jeong - 107-107
HandlerMapping SimpleUrlHandlerMapping BeanNameUrlHandlerMapping 은빈이름에매핑정보를넣기때문에매핑정보를관리하기 불편하다는단점이있다. URL 과컨트롤러의매핑정보를한곳에모아놓을수있는핸들러매핑이다. 매핑정보는 SimpleUrlHandlerMapping 빈의프로퍼티에넣어준다. 디폴트핸들러매핑이아니기때문에프로퍼티에매핑정보를직접넣어빈을등록해야사 용할수있다. <bean id= handlermapping class= org.springframework.web.servlet.handler.simpleurlhandlermapping > <property name= mapping > <props> <prop key="/content/**/*.do">indexcontroller</prop> <prop key="greeting/hello.do">detailcontroller</prop> </props> </property> </bean> <bean name="indexcontroller" /> <bean name="detailcontroller" /> Spring3- Oh Moon Jeong - 108-108
HandlerMapping ControllerBeanNameHandlerMapping 빈의아이디나빈이름을이용해매핑해주는핸들러매핑전략이다. ControllerBeanNameHandlerMapping 이자동으로빈아이디에 / 를붙여주기때문에빈 의아이디로도매핑할 URL 을지정할수있다. 다음과같이컨트롤러빈이선언되어있다면, hello 빈을 /hello.do URL 에매핑해준다. <bean id= hello.do class= controller.acontroller > 디폴트핸들러매핑이아니기때문에 ControllerBeanNameHandlerMapping 을빈으로등 록해줘야적용된다. <bean class= org.springframework.web.servlet.mvc.support.controllerbeannameurlhandlermapping> 빈이름앞뒤에붙일수있는 prefix 와 suffix 를지정할수있다. <property name= urlprefix value= /app/sub/ /> </bean> /app/sub/hello.do URL 에매핑 @Component( hello.do ) public class MyController implements Controller{ } Spring3- Oh Moon Jeong - 109-109
HandlerMapping ControllerClassNameHandlerMapping 빈이름대신클래스이름을 URL에매핑해주는핸들러매핑클래스다. 기본적으로클래스이름을모두 URL로사용하지만 Controller로끝날때는 Controller를뺀나머지이름을 URL에매핑해준다. 다음과같은컨트롤러클래스는 /hello URL에매핑된다. public class HelloController implements Controller{ } 디폴트핸들러매핑이아니기때문에 ControllerClassNameHandlerMapping 을빈으로등 록해줘야적용된다. <bean class= org.springframework.web.servlet.mvc.support.controllerclassnameurlhandlermapping /> Spring3- Oh Moon Jeong - 110-110
HandlerMapping DefaultAnnotationHandlerMapping 디폴트핸들러매핑이므로기본설정을바꾸지않는한빈으로등록할필요가없다. @Controller 클래스에대한매핑을처리한다. Spring3- Oh Moon Jeong - 111-111
Controller 비즈니스로직을호출하여처리결과 ModelAndView인스턴스를반환한다 Controller 작성법 Controller 인터페이스를구현한클래스를이용하는방법 public class IndexController implements Controller{ public ModelAndView handlerequest(httpservletrequest request, HttpServletResponse response) throws Exception { } } @Controller 어노테이션을이용한방법 컨트롤러의역할을담당하는메서드의파라메터개수와타입, 리턴타입등을자유롭게결정할수있다. 여기에 @RequestMapping을비롯한다양한어노테이션을메서드나파라미터에적용해서컨트롤러로직에대한추가정보를제공할수도있다. Spring3- Oh Moon Jeong - 112-112
Controller @Controller 어노테이션작성절차 1. @Controller 어노테이션 : 컨트롤러클래스에적용한다 2. @RequestMapping 어노테이션 : 클라이언트의요청을처리할메서드에적용한다. @Controller public class HelloController { @RequestMapping("welcome.do") public ModelAndView hello(){ System.out.println("welcome.do 용 controller 입니다!"); ModelAndView mav = new ModelAndView(); mav.setviewname("/web-inf/view/hello.jsp"); Map<String, String> model = new HashMap<String, String>(); model.put("greeting", "WELCOME! OhMoonJeong's SPRING MVC"); mav.addallobjects(model); return mav; } } 3. 설정파일에컨트롤러클래스를빈으로등록한다. <context:annotation-config></context:annotation-config> <bean id="hellocontroller" class="web1.hellocontroller"></bean> Spring3- Oh Moon Jeong - 113-113
Controller @Controller 컨트롤러용클래스에지정한다. 컨트롤러메서드에선언하는어노테이션 @RequestMapping @ModelAttribute @InitBinder Spring3- Oh Moon Jeong - 114-114
Controller 의메서드파라미터의종류 파라미터 설명 HttpServletRequest HttpServletResponse HttpSession Locale java.util.locale 타입. DispatcherServlet 의 LocaleResolver 가결정한 Locale 객체를받는다. InputStream, Reader OutputStream,Writer HttpServletRequest 의 getinputstream() 을통해받을수있는콘텐트스트림 HttpServletResponse 의 getoutputstream() 을통해받을수있는콘텐트스트림 @PathVariable @RequestMapping 의 URL 에 { } 로들어가는패스변수를받는다. 요청파라미터를 URL 의쿼리스트링으로보내는대신 URL 패스로풀어쓰는방식에유용. 예를들어 /user/view?id=10 보다 /user/view/10 이이해가쉽고보기좋다. @ReqiestMapping( /user/view/{id} ) public String view(@pathvariable( id ) int id){ } 로처리가능 Spring3- Oh Moon Jeong - 115-115
Controller 의메서드파라미터의종류 Http 요청파라미터를메서드파라미터에넣어주는애노테이션 public String view(@requestparam( id ) int id, @RequestParam( name ) String name){ } @RequestParam @RequestParam 애노테이션을사용했다면해당파라미터가반드시있어야한다. 없으면 HTTP400 오류발생. 파라미터를필수가아닌선택제공하려면 required 속성을 false 로지정할수있다 public void view( @RequestParam(value= id, request=false, defaultvalue= -1 ) int id){ } 요청파라미터의이름과메서드파라미터의이름이일치하면 @RequestParam 의이름은생략가능한다. public String view(@requetsparam int id) { } @CookieValue 요청과함께전달된쿠키값을메서드파라미터에넣어준다. 애노테이션의기본값에쿠키의이름을지정한다. public void check(@cookievalue ( auth ) String auth) { } public void check( @CookieValue (value= auth, required false, defaultvalue= NONE ) String auth) { } Spring3- Oh Moon Jeong - 116-116
Controller 의메서드파라미터의종류 모델정보를담을때사용하는객체 ( 컬렉션 ) 가전달된다. Map, Model, ModelMap Model 과 ModelMap 은 addattribute() 메서드를제공하고, Map 은 put() 를제공한다. public void hello(modelmap model){ User user = new User(1, Spring ); // 모델 model.addattribute(user); // addattribute( user, user) 와같음 } Spring3- Oh Moon Jeong - 117-117
Controller 의메서드파라미터의종류 메서드파라미터에도부여할수있고메서드레벨에적용할수도있음 1. command 객체초기화 @RequestParam 으로여러 HTTP 파라미터를개별적으로가져오는것보다, 그값을모두갖고있는하나의객체로한번에받을수있도록한다. @RequestMapping( /user/search ) public String search(@modelattribute UserSerch usersearch){ } @ModelAttribute 2. 별도의메서드로 Model에추가될객체를생성 @Controller public class ModelAttributeController { @ModelAttribute ("namearray") public String[] getname(){ System.out.println("getName()"); return new String[ ]{" 추신수 ", " 류현진 ", " 이대호 "}; } @RequestMapping("/modelAttribute/main.do") public String main(){ System.out.println("main()"); return "main"; //main뷰에 namearray모델이함께전달됨. } @RequestMapping("/modelAttribute/play.do") public String play(){ System.out.println("play()"); return "play"; //play뷰에 namearray모델이함께전달됨. } Spring3- Oh Moon Jeong - 118-118
Controller 의메서드파라미터의종류 SessionStatus @RequestBody 현재세션을다룰수있는객체를제공해준다. 세션안에저장된객체를제거해줄때사용. sessionstatus.setcomplete( ) ; HTTP 요청의 body 부분을그대로전달한다. XML 이나 JSP 기반의메시지를사용하는요청에서유용. public void message(@requestbody String body){ } @Value 값을파라미터에부여한다. 주로시스템프로퍼티를가져와파라미터에대입가능하다. public String hello(@value( #{SystemProperties[ os.name ]} ) String name) { } Spring3- Oh Moon Jeong - 119-119
Controller 의메서드리턴타입의종류 리턴타입 ModelAndView Model Map 설명 String 뷰이름을리턴한다. 뷰정보및모델정보를담고있는 ModelAndView 객체 뷰에전달할객체정보를담고있는 Model 을리턴한다. 이때뷰이름은요청 URL 로부터결정된다. 뷰에전달할객체정보를담고있는 Map 을리턴한다. 이때뷰이름은요청 URL 로부터결정된다. View 객체 View 객체를직접리턴, 해당 View 객체를이용해서뷰를생성한다. void @ResponseBody 어노테이션적용 메서드가 ServletResponse 나 HttpServletResponse 타입의파라미터를갖는경우메서드가직접응답을처리한다고가정한다. 그렇지않을경우요청 URL 로부터결정된뷰를보여준다. 파라미터에서 @ResponseBody 어노테이션이적용된경우, 리턴객체를 HTTP 응답으로전송한다. Spring3- Oh Moon Jeong - 120-120
Controller @RequestMapping 컨트롤러클래스나메서드에직접부여하고이를이용해서매핑한다. 메서드단위로 URL을매핑할수있어서컨트롤러의개수를줄일수있다. URL뿐아니라 GET/POST와같은 HTTP메서드, 심지어는파라미터와 HTTP헤더정보까지매핑에활용할수있다 특정파라미터가지정됐을때만따로분리하는식의컨트롤러매핑이가능하다 매핑정보가지저분해지고관리하기힘들어진다 디폴트핸들러매핑이므로기본설정을바꾸지않는한빈으로등록할필요가없다 @RequestMapping( value="/login.do", method=requestmethod.get ) public String form() { return "loginform"; } @RequestMapping(value="/login.do", method=requestmethod.post) public ModelAndView submit( @RequestParam("id") String id, @RequestParam String password) { } Spring3- Oh Moon Jeong - 121-121
Controller 컨트롤러클래스자동스캔 <context:component-scan base-package="web1"> Spring3- Oh Moon Jeong - 122-122
ModelAndView Controller처리결과후응답할 view와 view에전달할값을저장. 생성자 ModelAndView(String viewname) : 응답할view설정 ModelAndView(String viewname, Map values) : 응답할view와view로전달할값들을저장한Map 객체 ModelAndView(String viewname, String name, Object value) : 응답할view이름, view로넘길객체의name-value 주요메소드 setviewname(string view) : 응답할view이름을설정 addobject(string name, Object value) : view에전달할값을설정, requestscope에설정됨 addallobjects(map values) : view에전달할값을map에name-value로저장하여한번에설정 Redirect 방식전송 : view 이름에 redirect: 접두어붙인다. ex)mv.setviewname( redirect:/welcome.html ); Spring3- Oh Moon Jeong - 123-123
ViewResolver Controller가넘긴 view이름을통해알맞은view를찾는역할 1. Controller는 ModelAndView객체에응답할 view이름을넣어 return. 2. DispatchServlet은 ViewResolver에게응답할view를요청한다. 3. ViewResolver는 View이름을이용해알맞은 view객체를찾아 DispatcherServlet에게전달. Spring 설정파일에등록한다. Spring3- Oh Moon Jeong - 124-124
ViewResolver ViewResolver 의종류 InternalResourceViewResolver JSP나HTML등의내부자원을이용해뷰생성 InternalResourceView를기본뷰로사용 BeanNameViewResolver 뷰의이름과동일한이름을가지는빈을 View 로사용 사용자정의 View 객체를사용하는경우주로사용 XmlViewResolver BeanNameViewResolver 와동일하나뷰객체를 Xml 파일에설정해놓는것이차이. Bean 등록시 location 프러퍼티에 xml 파일을지정 Spring3- Oh Moon Jeong - 125-125
InternalResourceViewResolver 설정 <bean id="viewresolver" class="org.springframework.web.servlet.view.internalresourceviewresolver"> <property name="prefix" value="/web-inf/view/"></property> <property name="suffix" value=".jsp"></property> </bean> ModelAndView mav = new ModelAndView(); mav.setviewname("/web-inf/view/hello.jsp"); ModelAndView mav = new ModelAndView(); mav.setviewname("hello"); Spring3- Oh Moon Jeong - 126-126
View JSP를이용한뷰구현 JSP에서사용가능한 custom tag <spring:message> <form:errors> Spring3- Oh Moon Jeong - 127-127
Message 처리 MessageSource 를이용한메시지국제화처리 메시지파일의종류 message.properties : 기본메시지파일. 시스템의언어및지역에맞는프로퍼티파일이 존재하지않을경우에사용한다. message_en.properties : 영어메시지파일 message_ko.properties : 한글메시지파일 greeting=welcome. login.success=login success login.fail.id=id {0} is not exist login.fail.password=invalid password greeting= 환영합니다. login.success= 로그인성공 login.fail.id= 아이디 {0} 가존재하지않습니다 login.fail.password= 비밀번호가일치하지않습니다 message_en_uk.properites : 영국을위한영어메시지파일 메시지파일은클래스저장경로와같다. Spring3- Oh Moon Jeong - 128-128