1 / 43

고급자바프로그래밍 (Advanced Java Programming)

고급자바프로그래밍 (Advanced Java Programming). 강원대학교 컴퓨터학부 2012 년 가을학기 담당교수 정충교. 6 장 AOP 1. 6.1 트랙스액션 코드의 분리. interface UserService { void add(User user); void upgradeLevels (); }. UserServiceTx. public void upgradeLevels () { TransactionStatus status = this.transactionManager

mareo
Télécharger la présentation

고급자바프로그래밍 (Advanced Java Programming)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


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

  2. 6장 AOP 1

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

  4. 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; } }

  5. UserService publicvoidupgradeLevels() { List<User> users = userDao.getAll(); for(User user : users) { if(canUpgradeLevel(user)) { upgradeLevel(user); } } }

  6. <beanid="userService"class="springbook.user.service.UserServiceTx"><beanid="userService"class="springbook.user.service.UserServiceTx"> <propertyname="transactionManager"ref="transactionManager"/> <propertyname="userService"ref="userServiceImpl"/> </bean> <beanid="userServiceImpl"class="springbook.user.service.UserServiceImpl"> <propertyname="userDao"ref="userDao"/> <propertyname="mailSender"ref="mailSender"/> </bean>

  7. 고립된 단위 테스트

  8. static class MockUserDao implements UserDao { private List<User> users; private List<User> updated = new ArrayList(); private MockUserDao(List<User> users) { this.users = users; } public List<User> getUpdated() { return this.updated; } public List<User> 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 intgetCount() { throw new UnsupportedOperationException(); } }

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

  10. 전략패턴

  11. 부가기능과핵심기능의 분리

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

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

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

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

  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; } } 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(); } } interface Hello { String sayHello(String name); String sayHi(String name); String sayThankYou(String name); }

  18. interface Hello { String sayHello(String name); String sayHi(String name); String sayThankYou(String name); } @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. 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. 리플렉션(Reflection) • 자바의 모든 클래스는 자체 구성 정보를 담은 Class 타입 오브젝트를 하나씩 가지고 있다. • 클래스이름.class • getClass() – 클래스의 오브젝트를 가지고 있는 경우 • 클래스 이름, 슈퍼클래스, 인터페이스, 필드이름과 타입, 메소드 이름과파라미터와리턴타입, 오브젝트의 필드 값, 메소드 호출

  21. 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(); } }

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

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

  24. 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. 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; } } } Hello proxiedHello = (Hello)Proxy.newProxyInstance( getClass().getClassLoader(), new Class[] { Hello.class}, new UppercaseHandler(new HelloTarget()));

  26. 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; } } } Hello proxiedHello = (Hello)Proxy.newProxyInstance( getClass().getClassLoader(), new Class[] { Hello.class}, new UppercaseHandler(new HelloTarget()));

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

  28. public class TransactionHandlerimplements 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(); } } }

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

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

  31. 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); } }

  32. public class MessageFactoryBean implements FactoryBean<Message> { String text; public void setText(String text) { this.text = text; } public Message getObject() throws Exception { return Message.newMessage(this.text); } public Class<? extends Message> getObjectType() { return Message.class; } public booleanisSingleton() { return false; } }

  33. <bean id="message" class="springbook.learningtest.spring.factorybean.MessageFactoryBean"> <property name="text" value="Factory Bean" /> </bean> @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. 팩토리빈을 이용하여 트랜잭션 다이내믹 프록시를스프링빈으로 등록 왜 다이나믹프록시를스프링빈으로 만들려 하나?

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

  36. <bean id="userService" class="springbook.user.service.TxProxyFactoryBean"> <property name="target" ref="userServiceImpl" /> <property name="transactionManager" ref="transactionManager" /> <property name="pattern" value="upgradeLevels" /> <property name="serviceInterface"value="springbook.user.service.UserService" /> </bean>

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

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

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

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

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

  42. Advice와 pointcut은 공용

More Related