Dependency Injection and
Aspect Oriented Programming
Steve Erdman
Senior Developer, Wharton Computing
steve.erdman77@gmail.com
What is a dependency?
Container of functionality defined outside the
current code used by that code to achieve its
central...
Jeeves and Wooster
public class WoosterAlone {
private RedAstonMartin theCar;
public WoosterAlone(){
theCar = new RedAstonMartin();
}
public ...
public class WoosterWithGarage {
private Garage garage;
public WoosterWithGarage(Garage garage){
this.garage = garage;
}
p...
public class WoosterAssisted {
private Car theCar;
public WoosterAssisted(Car theCar){
this.theCar = theCar;
}
public void...
Why is the better?
• Decouples your code
• Reduces/Removes glue
• Large number of occasions where Wooster
needs the car
• ...
Decoupling code
• Objects should only be responsible for
themselves (Single Responsibility Principle)
• Design to interfac...
Glue
• The code that joins your objects together
• Gluing should not be part of an object’s
responsibilities
• All other t...
Inversion of control
• Pull from registry
• Dependency Injection
Dependency Injection process
• Register your objects (“beans”)
– System determines dependencies
• Wire in dependencies
• I...
Dependencies
• Property setter to interface
– Can use constructor, but won’t get into that
• Wiring
– Wired explicitly dur...
Registering Beans
<bean id=“theCar" name=“RedLightning BestCar” class=“RedAstonMartin“ />
<bean id=“trip” class=“WoosterAs...
Wiring by pulling
@Value(“#{theCar.licensePlateNumber}”)
private String garageTicket;
Autowiring
<bean id=“theCar" name=“RedLightning BestCar” class=“RedAstonMartin“ />
<bean id=“trip” class=“WoosterAssisted”...
Annotation Autowiring
public class WoosterAssisted {
@Autowired
private Car theCar;
private void setTheCar(Car theCar){
th...
Annotation Autowiring by Name
public class WoosterAssisted {
@Resource(name=“RedLightning”)
private Car theCar;
private vo...
Autowiring Lists
@AutoWired
private Car[] cars;
private void setCars(Car[] cars){
this.cars = cars;
}
Component Scanning
<context:component-scan />
• Registers all the beans it can find
• Glue is completely hidden
• Can set ...
Environment sets
• Can set beans based on environment
• e.g.
– Local environment -> embedded database
– Testing -> Mocked ...
Bean scopes
• Singleton (default)
• Prototype (new instance every time)
• Request (new instance every request)
• Session (...
Basic Messaging
public class BasicHelloMain {
public static void main(String[] args) {
System.out.println("Hello World!");...
Separate Pieces of Functionality
• Message content
• Message renderer
• Connecting content to renderer
Separate Messaging
public class SimpleMessageProvider {
public String getMessage() {
return "Hello World!";
}
}
Separate Messaging
public class StandardOutMessageRenderer {
private SimpleMessageProvider provider;
public StandardOutMes...
Separate Messaging
public class HelloWorldMain {
public static void main(String[] args) {
StandardOutMessageRenderer rende...
Central Managed
public interface MessageProvider {
public String getMessage();
}
public interface MessageRenderer {
public...
Central Managed
public class SimpleMessageProvider implements MessageProvider {
public String getMessage() {
return "Hello...
Central Managed
public class StandardOutMessageRenderer implements MessageRenderer {
private MessageProvider provider;
pub...
Central Managed
public class HelloWorldMain {
public static void main(String[] args) {
MessageProvider provider = new Simp...
Dependency Injected
@Service("simpleMessageProvider")
public class SimpleMessageProvider implements MessageProvider {
publ...
Dependency Injected
@Service
public class StandardOutMessageRenderer implements MessageRenderer {
private MessageProvider ...
Dependency Injected
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmln...
Dependency Injected
public class HelloWorldMain {
public static void main(String[] args) {
GenericXmlApplicationContext ct...
Dependency Injected
@Service("injectedMessageProvider")
public class InjectedMessageProvider implements MessageProvider {
...
Dependency Injected
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmln...
Aspect Oriented Programming
Dependency Injection - injects registered
dependency objects into established Interface
properties
Aspect Oriented Program...
What is not a dependency?
Functionality included in the flow of a request
that is not part of the central purpose of the
c...
Back to Jeeves and Wooster
Wooster wants to
• Keep track of all the things he does, for his
autobiography
• Keep track of the lies he tells his Aunt ...
This involves
• Keep track of all the things he does, for his
autobiography - Logging
• Keep track of the lies he tells hi...
@Logged
public class WoosterActions {
@Cached
public String generateLieForAuntAgatha(String situation, Date occurrence){
....
Aspect components
• Join Point – a place in code that can be the
target for an aspect
• Point Cut – The query that selects...
Join Point, Point Cuts, WTH???
• Very much like CSS/jQuery selectors
• A Join Point is anywhere that can be joined
– In se...
Why is there a formal name for Join
Points?
• Join points give us access to the runtime
values when advice is being run
– ...
AspectJ Point Cut syntax
<match type>(<access> <return type>
<class>.<method>(<method parameters>))
e.g.
– execution(publi...
Composite Point Cuts
• && = AND
• || = OR
• ! = NOT
Advice types
• Before
• After
• After Returning
• After Throwing
• Around
Before Advice
@Before(“joinMethod”)
public void doBefore(JoinPoint joinPoint){
beforeAction();
}
public void joinMethod(){...
After Advice
@After(“joinMethod”)
public void doBefore(JoinPoint joinPoint){
afterAction();
}
public void joinMethod(){
in...
Around Advice
@Around(“joinMethod”)
public void doBefore(ProceedingJoinPoint joinPoint){
beforeAction();
joinPoint.proceed...
Around Advice (continued)
public void joinMethod(){
beforeAction();
insideAction();
afterAction();
}
Inter Type Definitions (ITD)
• Adds code at compile time to matching Join
Points
• Enables the Mixin behavior of many advi...
@Logged
public class WoosterActions {
@Cached
public String generateLieForAuntAgatha(String situation, Date occurrence){
l...
Logging Aspect
@Aspect
public class LoggingAspect {
private Log4JLogger log = new Log4JLogger("Jeeves");
@Before("@within(...
Caching Aspect
@Aspect
public class CachingAspect {
@Autowired
private Cache cache;
@Around("@annotation(Cacheable)")
publ...
Generate Lies
@Cached
public String generateLieForAuntAgatha(String situation, Date occurrence){
return lieGeneratingCode(...
Add Logging Aspect
@Cached
public String generateLieForAuntAgatha(String situation, Date occurrence){
log.info(joinPoint.g...
Add Cached Aspect
@Cached
public String generateLieForAuntAgatha(String situation, Date occurrence){
log.info(joinPoint.ge...
Transactional Aspect
@Aspect
public class TransactionalAspect {
@Autowired
private TransactionService transactionService;
...
Transferring Money
@Transactional
public void transferMoney(int amount, Account accountFrom, Account accountTo){
withdrawF...
Add Transaction Aspect
@Transactional
public void transferMoney(int amount, Account accountFrom, Account accountTo){
log.i...
Secured Aspect
@Aspect
public class SecuredAspect {
@Autowired
private SecurityService securityService;
@Before("* *.*(@an...
Enter Club
public enterClub(@Secured(“Wooster Approved”) Club club){
enterClubCode(club);
}
Add Secured Aspect
public enterClub(@Secured(“Wooster Approved”) Club club){
log.info(joinPoint.getSignature().toString())...
Translation Aspect
@Aspect
public class TranslationAspect {
@Autowired
private TranslationService translationService;
@Aro...
Talking to foreign jobbie
@TranslateIncoming
public void talkTo(Person listener, String message){
talkToCode(listener, mes...
Add Translate Aspect
@TranslateIncoming
public void talkTo(String message, Person listener){
log.info(joinPoint.getSignatu...
Steve Erdman
Senior Developer, Wharton Computing
steve.erdman77@gmail.com
Dependency Injection and Aspect Oriented Programming presentation
Dependency Injection and Aspect Oriented Programming presentation
Dependency Injection and Aspect Oriented Programming presentation
Upcoming SlideShare
Loading in …5
×

Dependency Injection and Aspect Oriented Programming presentation

303 views
232 views

Published on

The slides from my presentation giving an overview of the concepts and some implementation of Dependency Injection and Aspect Oriented Programming.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
303
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
5
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Dependency Injection and Aspect Oriented Programming presentation

  1. 1. Dependency Injection and Aspect Oriented Programming
  2. 2. Steve Erdman Senior Developer, Wharton Computing steve.erdman77@gmail.com
  3. 3. What is a dependency? Container of functionality defined outside the current code used by that code to achieve its central purpose
  4. 4. Jeeves and Wooster
  5. 5. public class WoosterAlone { private RedAstonMartin theCar; public WoosterAlone(){ theCar = new RedAstonMartin(); } public void trip(){ theCar.drive(); } }
  6. 6. public class WoosterWithGarage { private Garage garage; public WoosterWithGarage(Garage garage){ this.garage = garage; } public void trip(){ garage.claimCar("Best Car").drive(); } }
  7. 7. public class WoosterAssisted { private Car theCar; public WoosterAssisted(Car theCar){ this.theCar = theCar; } public void trip(){ theCar.drive(); } }
  8. 8. Why is the better? • Decouples your code • Reduces/Removes glue • Large number of occasions where Wooster needs the car • Red Aston Martin in the shop – Black Jaguar instead • Roads are icy – take all weather car instead
  9. 9. Decoupling code • Objects should only be responsible for themselves (Single Responsibility Principle) • Design to interfaces • Modularity – Easy to debug – Easy to test – Easy to replace – Easy to iterate
  10. 10. Glue • The code that joins your objects together • Gluing should not be part of an object’s responsibilities • All other things being equal, the less amount of glue, the better
  11. 11. Inversion of control • Pull from registry • Dependency Injection
  12. 12. Dependency Injection process • Register your objects (“beans”) – System determines dependencies • Wire in dependencies • Instantiate your beans
  13. 13. Dependencies • Property setter to interface – Can use constructor, but won’t get into that • Wiring – Wired explicitly during bean registry – Pulled from other bean/properties – Autowired • By name • By type – Controlled Autowiring
  14. 14. Registering Beans <bean id=“theCar" name=“RedLightning BestCar” class=“RedAstonMartin“ /> <bean id=“trip” class=“WoosterAssisted”> <property name=“theCar”> <ref bean=“theCar” /> </property> </bean>
  15. 15. Wiring by pulling @Value(“#{theCar.licensePlateNumber}”) private String garageTicket;
  16. 16. Autowiring <bean id=“theCar" name=“RedLightning BestCar” class=“RedAstonMartin“ /> <bean id=“trip” class=“WoosterAssisted” autowire=“byType” /> OR <bean id=“trip” class=“WoosterAssisted” autowire=“byName” />
  17. 17. Annotation Autowiring public class WoosterAssisted { @Autowired private Car theCar; private void setTheCar(Car theCar){ this.theCar = theCar; } public WoosterAssisted(){ } public void trip(){ theCar.drive(); } }
  18. 18. Annotation Autowiring by Name public class WoosterAssisted { @Resource(name=“RedLightning”) private Car theCar; private void setTheCar(Car theCar){ this.theCar = theCar; } public WoosterAssisted(){ } public void trip(){ theCar.drive(); } }
  19. 19. Autowiring Lists @AutoWired private Car[] cars; private void setCars(Car[] cars){ this.cars = cars; }
  20. 20. Component Scanning <context:component-scan /> • Registers all the beans it can find • Glue is completely hidden • Can set starting package • Can add include and exclude filters
  21. 21. Environment sets • Can set beans based on environment • e.g. – Local environment -> embedded database – Testing -> Mocked data connection – Dev environment -> dev SQL Server – Dev + NoSQL -> dev Cassandra Server – Prod -> prod SQL Server
  22. 22. Bean scopes • Singleton (default) • Prototype (new instance every time) • Request (new instance every request) • Session (new instance every session) • Thread (new instance every thread)
  23. 23. Basic Messaging public class BasicHelloMain { public static void main(String[] args) { System.out.println("Hello World!"); } }
  24. 24. Separate Pieces of Functionality • Message content • Message renderer • Connecting content to renderer
  25. 25. Separate Messaging public class SimpleMessageProvider { public String getMessage() { return "Hello World!"; } }
  26. 26. Separate Messaging public class StandardOutMessageRenderer { private SimpleMessageProvider provider; public StandardOutMessageRenderer(){ setMessageProvider(new SimpleMessageProvider()); } public void setMessageProvider(SimpleMessageProvider provider) { this.provider = provider; } public SimpleMessageProvider getMessageProvider() { return provider; } public void render() { System.out.println(getMessageProvider().getMessage()); } }
  27. 27. Separate Messaging public class HelloWorldMain { public static void main(String[] args) { StandardOutMessageRenderer renderer = new StandardOutMessageRenderer(); renderer.render(); } }
  28. 28. Central Managed public interface MessageProvider { public String getMessage(); } public interface MessageRenderer { public void render(); public void setMessageProvider(MessageProvider provider); public MessageProvider getMessageProvider(); }
  29. 29. Central Managed public class SimpleMessageProvider implements MessageProvider { public String getMessage() { return "Hello World!"; } } public class RegistryMessageProvider implements MessageProvider { public String getMessage() { return registry.lookup(“message.greeting"); } }
  30. 30. Central Managed public class StandardOutMessageRenderer implements MessageRenderer { private MessageProvider provider; public void setMessageProvider(MessageProvider provider) { this.provider = provider; } public MessageProvider getMessageProvider() { return provider; } public void render() { if (getMessageProvider()==null){ throw new RuntimeException("Missing MessageProvider"); } System.out.println(getMessageProvider().getMessage()); } }
  31. 31. Central Managed public class HelloWorldMain { public static void main(String[] args) { MessageProvider provider = new SimpleMessageProvider(); MessageProvider provider = new RegistryMessageProvider(); MessageRenderer renderer = new StandardOutMessageRenderer(); renderer.setMessageProvider(provider); renderer.render(); } }
  32. 32. Dependency Injected @Service("simpleMessageProvider") public class SimpleMessageProvider implements MessageProvider { public String getMessage() { return "Hello World!"; } }
  33. 33. Dependency Injected @Service public class StandardOutMessageRenderer implements MessageRenderer { private MessageProvider provider; public void setMessageProvider(MessageProvider provider) { this.provider = provider; } public MessageProvider getMessageProvider() { return provider; } public void render() { if (getMessageProvider()==null){ throw new RuntimeException("Missing MessageProvider"); } System.out.println(getMessageProvider().getMessage()); } }
  34. 34. Dependency Injected <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> <context:annotation-config /> <context:component-scan base-package="edu.upenn.wharton.messaging.ioc.di.annotation" /> </beans>
  35. 35. Dependency Injected public class HelloWorldMain { public static void main(String[] args) { GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(); ctx.load("classpath:di-central-app-context.xml"); ctx.refresh(); MessageRenderer renderer = ctx.getBean("messageRenderer"); renderer.render(); } }
  36. 36. Dependency Injected @Service("injectedMessageProvider") public class InjectedMessageProvider implements MessageProvider { private String message; public void setMessage(String message){ this.message = message; } public String getMessage() { return message; } }
  37. 37. Dependency Injected <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> <context:annotation-config /> <bean id="messageProvider" class="edu.upenn.wharton.messaging.ioc.di.annotation.InjectedMessageProvider"> <property name="message"> <value>Hello World!</value> </property> </bean> <context:component-scan base-package="edu.upenn.wharton.messaging.ioc.di.annotation" include-classes="*Renderer" /> </beans>
  38. 38. Aspect Oriented Programming
  39. 39. Dependency Injection - injects registered dependency objects into established Interface properties Aspect Oriented Programming - injects entirely new functionality
  40. 40. What is not a dependency? Functionality included in the flow of a request that is not part of the central purpose of the current object. Good example of this is cross cutting concerns, such as logging or security
  41. 41. Back to Jeeves and Wooster
  42. 42. Wooster wants to • Keep track of all the things he does, for his autobiography • Keep track of the lies he tells his Aunt Agatha • Keep his financial accounts in order • Not intrude where he is not wanted • Speak to foreign chaps without having to learn their lingo
  43. 43. This involves • Keep track of all the things he does, for his autobiography - Logging • Keep track of the lies he tells his Aunt Agatha - Caching • Keep his financial accounts in order - Transactions • Not intrude where he is not wanted - Security • Speak to foreign chaps without having to learn their lingo -Translation
  44. 44. @Logged public class WoosterActions { @Cached public String generateLieForAuntAgatha(String situation, Date occurrence){ ... } @Transactional public void transferMoney(int amount, Account accountFrom, Account accountTo){ ... } public enterClub(@Secured(“Wooster Approved”) Club club){ ... } @Translate public void talkTo(String message, Person listener){ ... } @Translate public String listenTo(Person talker){ ... } }
  45. 45. Aspect components • Join Point – a place in code that can be the target for an aspect • Point Cut – The query that selects the join points that will the be targets for the aspect • Advice – The code that will be run at the selected Join Points
  46. 46. Join Point, Point Cuts, WTH??? • Very much like CSS/jQuery selectors • A Join Point is anywhere that can be joined – In selectors, this is any DOM element • Selectors match on things like DOM hierarchy, element type, id, attributes, etc. • Point cuts match on things like Class, Package, or Method names, Method signature, Annotations, etc.
  47. 47. Why is there a formal name for Join Points? • Join points give us access to the runtime values when advice is being run – Current class – Method name – Argument names and values – Annotations – etc.
  48. 48. AspectJ Point Cut syntax <match type>(<access> <return type> <class>.<method>(<method parameters>)) e.g. – execution(public String Wooster.*(..)) – execution(* @Logging*.*(..)) Don’t focus on this. I’m using fake syntax in my examples.
  49. 49. Composite Point Cuts • && = AND • || = OR • ! = NOT
  50. 50. Advice types • Before • After • After Returning • After Throwing • Around
  51. 51. Before Advice @Before(“joinMethod”) public void doBefore(JoinPoint joinPoint){ beforeAction(); } public void joinMethod(){ insideAction(); } public void joinMethod(){ beforeAction(); insideAction(); }
  52. 52. After Advice @After(“joinMethod”) public void doBefore(JoinPoint joinPoint){ afterAction(); } public void joinMethod(){ insideAction(); } public void joinMethod(){ insideAction(); afterAction(); }
  53. 53. Around Advice @Around(“joinMethod”) public void doBefore(ProceedingJoinPoint joinPoint){ beforeAction(); joinPoint.proceed(); afterAction(); } public void joinMethod(){ insideAction(); }
  54. 54. Around Advice (continued) public void joinMethod(){ beforeAction(); insideAction(); afterAction(); }
  55. 55. Inter Type Definitions (ITD) • Adds code at compile time to matching Join Points • Enables the Mixin behavior of many advices • Can set up a dependency injection
  56. 56. @Logged public class WoosterActions { @Cached public String generateLieForAuntAgatha(String situation, Date occurrence){ lieGeneratingCode(situation, occurrence); } @Transactional public void transferMoney(int amount, Account accountFrom, Account accountTo){ transferFromAccount(accountFrom, amount); transferToAccount(accountTo, amount); } public enterClub(@Secured(“Wooster Approved”) Club club){ enterClubCode(club); } @TranslateIncoming public void talkTo(String message, Person listener){ talkToCode(message, listener); } @TranslateReturn public String listenTo(Person talker){ return listenToCode(talker); } }
  57. 57. Logging Aspect @Aspect public class LoggingAspect { private Log4JLogger log = new Log4JLogger("Jeeves"); @Before("@within(Logging) && execution(public * *.*(..)") public void logExecution(JoinPoint joinPoint){ log.info(joinPoint.getSignature().toString()); } }
  58. 58. Caching Aspect @Aspect public class CachingAspect { @Autowired private Cache cache; @Around("@annotation(Cacheable)") public Object checkCache(ProceedingJoinPoint joinPoint) throws Throwable{ Object result = cache.get(joinPoint.getTarget().hashCode()); if (result != null){ return result; } result = joinPoint.proceed(); cache.put(joinPoint.getTarget().hashCode(), result); return result; } }
  59. 59. Generate Lies @Cached public String generateLieForAuntAgatha(String situation, Date occurrence){ return lieGeneratingCode(situation, occurrence); }
  60. 60. Add Logging Aspect @Cached public String generateLieForAuntAgatha(String situation, Date occurrence){ log.info(joinPoint.getSignature().toString()); return lieGeneratingCode(); }
  61. 61. Add Cached Aspect @Cached public String generateLieForAuntAgatha(String situation, Date occurrence){ log.info(joinPoint.getSignature().toString()); Object result = cache.get(joinPoint.getTarget().hashCode()); if (result != null){ return result; } result = lieGeneratingCode(); cache.put(joinPoint.getTarget().hashCode(), result); return result; }
  62. 62. Transactional Aspect @Aspect public class TransactionalAspect { @Autowired private TransactionService transactionService; @Around("@annotation(Transactional)") public Object doTransaction(ProceedingJoinPoint joinPoint){ transactionService.startTransaction(); try{ Object result = joinPoint.proceed(); transactionService.commitTransaction(); return result; } catch (Throwable e) { transactionService.rollbackTransaction(); throw e; } } }
  63. 63. Transferring Money @Transactional public void transferMoney(int amount, Account accountFrom, Account accountTo){ withdrawFromAccount(accountFrom, amount); depositToAccount(accountTo, amount); }
  64. 64. Add Transaction Aspect @Transactional public void transferMoney(int amount, Account accountFrom, Account accountTo){ log.info(joinPoint.getSignature().toString()); transactionService.startTransaction(); try{ withdrawFromAccount(accountFrom, amount); depositToAccount(accountTo, amount); transactionService.commitTransaction(); return result; } catch (Throwable e) { transactionService.rollbackTransaction(); throw e; } }
  65. 65. Secured Aspect @Aspect public class SecuredAspect { @Autowired private SecurityService securityService; @Before("* *.*(@annotation(Secured) Club club)") public void checkSecured(JoinPoint joinPoint){ Annotation[][] annotations = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterAnnotations(); if (!securityService.checkAccess(joinPoint.getArgs()[0], annotations[0][0])){ throw new SecurityException(); } } }
  66. 66. Enter Club public enterClub(@Secured(“Wooster Approved”) Club club){ enterClubCode(club); }
  67. 67. Add Secured Aspect public enterClub(@Secured(“Wooster Approved”) Club club){ log.info(joinPoint.getSignature().toString()); Annotation[][] annotations = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterAnnotations(); if (!securityService.checkAccess(joinPoint.getArgs()[0], annotations[0][0])){ throw new SecurityException(); } enterClubCode(club); }
  68. 68. Translation Aspect @Aspect public class TranslationAspect { @Autowired private TranslationService translationService; @Around("@annotation(TranslateIncoming)") public void translateIncoming(ProceedingJoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); args[0] = translationService.translateMessage((String) args[0]); joinPoint.proceed(args); } @AfterReturning(value = "@annotation(TranslateReturn)", returning = "message") public String translateReturn(Object message){ return translationService.translateMessage((String) message); } }
  69. 69. Talking to foreign jobbie @TranslateIncoming public void talkTo(Person listener, String message){ talkToCode(listener, message); } @TranslateReturn public String listenTo(Person talker){ return listenToCode(talker); }
  70. 70. Add Translate Aspect @TranslateIncoming public void talkTo(String message, Person listener){ log.info(joinPoint.getSignature().toString()); Object[] args = joinPoint.getArgs(); args[0] = translationService.translateMessage((String) args[0]); talkToCode(args[0], args[1]); } @TranslateReturn public String listenTo(Person talker){ log.info(joinPoint.getSignature().toString()); message = listenToCode(talker); return translationService.translateMessage(message); }
  71. 71. Steve Erdman Senior Developer, Wharton Computing steve.erdman77@gmail.com

×