Presentation is loading. Please wait.

Presentation is loading. Please wait.

1/43 고급자바프로그래밍 (ADVANCED JAVA PROGRAMMING) 강원대학교 컴퓨터학부 2012 년 가을학기 담당교수 정충교 1.

Similar presentations


Presentation on theme: "1/43 고급자바프로그래밍 (ADVANCED JAVA PROGRAMMING) 강원대학교 컴퓨터학부 2012 년 가을학기 담당교수 정충교 1."— Presentation transcript:

1 1/43 고급자바프로그래밍 (ADVANCED JAVA PROGRAMMING) 강원대학교 컴퓨터학부 2012 년 가을학기 담당교수 정충교 1

2 2/43 6 장 AOP 1 2

3 3/43 3 6.1 트랙스액션 코드의 분리 interface UserService { void add(User user); void upgradeLevels(); }

4 4/43 UserServiceTx public void upgradeLevels() { TransactionStatus status = this.transactionManager.getTransaction(new DefaultTransactionDefinition()); try { userService.upgradeLevels(); this.transactionManager.commit(status); } catch (RuntimeException e) { this.transactionManager.rollback(status); throw e; } 4

5 5/43 UserService public void upgradeLevels() { List users = userDao.getAll(); for (User user : users) { if (canUpgradeLevel(user)) { upgradeLevel(user); } 5

6 6/43 6

7 7/43 고립된 단위 테스트 7

8 8/43 static class MockUserDao implements UserDao { private List users; private List updated = new ArrayList(); private MockUserDao(List users) { this.users = users; } public List getUpdated() { return this.updated; } public List getAll() { return this.users; } public void update(User user) { updated.add(user); } public void add(User user) { throw new UnsupportedOperationException(); } public void deleteAll() { throw new UnsupportedOperationException(); } public User get(String id) { throw new UnsupportedOperationException(); } public int getCount() { throw new UnsupportedOperationException(); } } 8

9 9/43 다이내믹 프록시와 팩토리빈 (Dynamic Proxy, Factory Bean) 9

10 10/43 전략패턴 10

11 11/43 부가기능과 핵심기능의 분리 11

12 12/43 핵심기능 인터페이스 적용 12

13 13/43 프록시와 타겟 13 타겟의 대리인 역할

14 14/43 데코레이션 패턴 14 런타임에 동적으로 부가기능 삽입

15 15/43 프록시 패턴 프록시가 타겟에 대한 접근 방법을 제어할 때 타겟 오브젝트 생성 시점 지연 원격 오브젝트 이용 타겟에 대한 접근 권한 제한 15

16 16/43 간단한 프록시 예 interface Hello { String sayHello(String name); String sayHi(String name); String sayThankYou(String name); } 16 static class HelloTarget implements Hello { public String sayHello(String name) { return "Hello " + name; } public String sayHi(String name) { return "Hi " + name; } public String sayThankYou(String name) { return "Thank You " + name; }

17 17/43 interface Hello { String sayHello(String name); String sayHi(String name); String sayThankYou(String name); } 17 class HelloUppercase implements Hello { Hello hello; public HelloUppercase(Hello hello) { this.hello = hello; } public String sayHello(String name) { return hello.sayHello(name).toUpperCase(); } public String sayHi(String name) { return hello.sayHi(name).toUpperCase(); } public String sayThankYou(String name) { return hello.sayThankYou(name).toUpperCase(); }

18 18/43 interface Hello { String sayHello(String name); String sayHi(String name); String sayThankYou(String name); } 18 @Test public void simpleProxy() { Hello hello = new HelloTarget(); assertThat(hello.sayHello("Toby"), is("Hello Toby")); assertThat(hello.sayHi("Toby"), is("Hi Toby")); assertThat(hello.sayThankYou("Toby"), is("Thank You Toby")); Hello proxiedHello = new HelloUppercase(new HelloTarget()); assertThat(proxiedHello.sayHello("Toby"), is("HELLO TOBY")); assertThat(proxiedHello.sayHi("Toby"), is("HI TOBY")); assertThat(proxiedHello.sayThankYou("Toby"), is("THANK YOU TOBY")); }

19 19/43 19 class HelloUppercase implements Hello { Hello hello; public HelloUppercase(Hello hello) { this.hello = hello; } public String sayHello(String name) { return hello.sayHello(name).toUpperCase(); } public String sayHi(String name) { return hello.sayHi(name).toUpperCase(); } public String sayThankYou(String name) { return hello.sayThankYou(name).toUpperCase(); } 인터페이스의 모든 메소드를 구현해야 함 똑같은 부가 기능이 모든 메소드에 중복됨

20 20/43 리플렉션 (Reflection) 자바의 모든 클래스는 자체 구성 정보를 담은 Class 타입 오브젝트를 하나씩 가지고 있다. 클래스이름.class getClass() – 클래스의 오브젝트를 가지고 있는 경우 클래스 이름, 슈퍼클래스, 인터페이스, 필드 이름과 타입, 메소드 이름과 파라미터와 리턴타입, 오브젝트의 필드 값, 메소드 호출 20

21 21/43 public class Reflection { @Test public void invokeMethod() throws Exception { String name = "Spring"; // length assertThat(name.length(), is(6)); Method lengthMethod = String.class.getMethod("length"); assertThat((Integer)lengthMethod.invoke(name), is(6)); // toUpperCase assertThat(name.charAt(0), is('S')); Method charAtMethod = String.class.getMethod("charAt", int.class); assertThat((Character)charAtMethod.invoke(name, 0), is('S')); } @Test public void createObject() throws Exception { Date now = (Date) Class.forName("java.util.Date").newInstance(); } 21

22 22/43 리플렉션을 이용한 다이내믹 프록시 다이내믹 프록시는 런타임에 프록시팩토리에 의해 생성 다이내믹 프록시 오브젝트는 타킷의 인터페이스 타입 클라이언트는 타겟 인터페이스를 통해 다이내믹프록시 사용 22

23 23/43 리플렉션을 이용한 다이내믹 프록시 23

24 24/43 class UppercaseHandler implements InvocationHandler { Object target; private UppercaseHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object ret = method.invoke(target, args); if (ret instanceof String && method.getName().startsWith("say")) { return ((String)ret).toUpperCase(); } else { return ret; } 24

25 25/43 class UppercaseHandler implements InvocationHandler { Object target; private UppercaseHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object ret = method.invoke(target, args); if (ret instanceof String && method.getName().startsWith("say")) { return ((String)ret).toUpperCase(); } else { return ret; } 25 Hello proxiedHello = (Hello)Proxy.newProxyInstance( getClass().getClassLoader(), new Class[] { Hello.class}, new UppercaseHandler(new HelloTarget()));

26 26/43 class UppercaseHandler implements InvocationHandler { Object target; private UppercaseHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object ret = method.invoke(target, args); if (ret instanceof String && method.getName().startsWith("say")) { return ((String)ret).toUpperCase(); } else { return ret; } 26 Hello proxiedHello = (Hello)Proxy.newProxyInstance( getClass().getClassLoader(), new Class[] { Hello.class}, new UppercaseHandler(new HelloTarget()));

27 27/43 다이내믹 프록시를 이용한 트랜랙색션 부가기능 27 인터페이스의 모든 메소드를 구현해야 함 똑같은 부가 기능이 모든 메소드에 중복됨

28 28/43 public class TransactionHandler implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().startsWith(pattern)) { return invokeInTransaction(method, args); } else { return method.invoke(target, args); } private Object invokeInTransaction(Method method, Object[] args) throws Throwable { TransactionStatus status = this.transactionManager. getTransaction(new faultTransactionDefinition()); try { Object ret = method.invoke(target, args); this.transactionManager.commit(status); return ret; } catch (InvocationTargetException e) { this.transactionManager.rollback(status); throw e.getTargetException(); } 28

29 29/43 @Test public void upgradeAllOrNothing() throws Exception { TransactionHandler txHandler = new TransactionHandler(); txHandler.setTarget(testUserService); txHandler.setPattern("upgradeLevels"); UserService txUserService = (UserService)Proxy.newProxyInstance( getClass().getClassLoader(), new Class[] {UserService.class}, txHandler); … } 29

30 30/43 다이내믹 프록시를 위한 팩토리빈 팩토리빈을 사용하면 다이내믹 프록시를 스프링빈으로 등 록할 수 있다. FactoryBean 를 스프링빈으로 등록해 놓으면 이것이 T 타입 오브젝트를 만들어 역시 스프링빈을 등록해 준다. 30 org.springframework.beans.factory ; Interface FactoryBean { T getObject() ; Class getObjectType() ; booleanisSingleton() ; }

31 31/43 BeanFactory 사용 예 package springbook.learningtest.spring.factorybean; public class Message { String text; private Message(String text) { this.text = text; } public String getText() { return text; } public static Message newMessage(String text) { return new Message(text); } 31

32 32/43 public class MessageFactoryBean implements FactoryBean { String text; public void setText(String text) { this.text = text; } public Message getObject() throws Exception { return Message.newMessage(this.text); } public Class getObjectType() { return Message.class; } public boolean isSingleton() { return false; } 32

33 33/43 33 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class FactoryBeanTest { @Autowired ApplicationContext context; @Test public void getMessageFromFactoryBean() { Object message = context.getBean("message"); assertThat(message, is(Message.class)); assertThat(((Message)message).getText(), is("Factory Bean")); } @Test public void getFactoryBean() throws Exception { Object factory = context.getBean("&message"); assertThat(factory, is(MessageFactoryBean.class)); }

34 34/43 팩토리빈을 이용하여 트랜잭션 다이내믹 프록시를 스프링빈으 로 등록 34 왜 다이나믹 프록시를 스프링빈으로 만들려 하나 ?

35 35/43 public class TxProxyFactoryBean implements FactoryBean { … public Object getObject() throws Exception { TransactionHandler txHandler = new TransactionHandler(); txHandler.setTarget(target); txHandler.setTransactionManager(transactionManager); txHandler.setPattern(pattern); return Proxy.newProxyInstance( getClass().getClassLoader(), new Class[] { serviceInterface }, txHandler); } … } 35

36 36/43 36

37 37/43 다이나믹 프록시를 사용하면 프록시 패턴 혹은 데커레이션 패턴이 갖는 아래 두 가지 문제 해결 팩토리빈을 사용하면 다이나믹 프록시를 스프링빈으로 등 록시키고 다른 오브젝트에 DI 할 수 있다. 37 인터페이스의 모든 메소드를 구현해야 함 똑같은 부가 기능이 모든 메소드에 중복됨

38 38/43 한번 만든 TxProxyFactoryBean 은 다른 서비스 에도 그대로 적용할 수 있다. 38 리스트 6-38, 6-39, 6-40 coreService 라는 아이디를 가진 빈을 DI 받아 사용하는 클라이언트는 코드 변경 없이도 프록시가 제공하는 트랜잭션 기능이 적용된 coreService 를 이용 할 수 있다.

39 39/43 팩토리빈의 한계 여러 개의 클래스에 공통의 부가기능 지원하기 위해서는 여러 개의 팩토리빈을 설정해야 함 하나의 타깃에 여러 가지 부가기능을 지원하기 위해서는 여러 개의 팩토리빈을 설정해야 함 39

40 40/43 6.4 스프링의 팩토리빈 (ProxyFactoryBean) JDK 다이나믹 프록시 40 스프링 다이나믹 프록시 FactoryBean 타깃과 연결되어 있지 않음

41 41/43 41 스프링 다이나믹 프록시 어드바이저 = 포인트컷 ( 메소드 선정 ) + 어드바이스 ( 부가기능 )

42 42/43 Advice 와 pointcut 은 공용 42

43 43/43 끝 43


Download ppt "1/43 고급자바프로그래밍 (ADVANCED JAVA PROGRAMMING) 강원대학교 컴퓨터학부 2012 년 가을학기 담당교수 정충교 1."

Similar presentations


Ads by Google