Aspect Oriented Programming (AOP) σε Spring

Σε αυτό το άρθρο θα δούμε πως μπορούμε να χρησιμοποιήσουμε τα Annotations του AspectJ μαζί με Spring AOP για να αναχαιτίσουμε μεθόδους και να τρέξουμε κώδικα που χρειαζόμαστε πριν ή μετά την αναχαιτισμένη μέθοδο. Αυτή η τεχνική μας επιτρέπει να εκτελούμε διαδικασίες όπως Logging, Transactions και Profiling χωρίς να χρειαστεί να αλλάξουμε τον υπάρχων κώδικα.

Προαπαιτούμενα

1. pom.xml Εισάγουμε στο pom.xml τα παρακάτω:

[code language=”xml”]

org.springframework
spring-aop
${spring.version}


org.aspectj
aspectjrt
1.6.11


org.aspectj
aspectjweaver
1.6.11

[/code]


2. root-context.xml

Προσθέτουμε την ακόλουθη γραμμή ώστε ο αυτόματος proxy να μπορεί να ανακαλύψει τα beans που χειρίζεται το Spring. Επίσης δηλώνουμε το Bean το οποίο θα χρησιμοποιεί τα Annotations του AspectJ για να αναχαιτίσει μεθόδους που έχουμε ήδη στον κώδικα.

[code language=”xml” highlight=”1″]



[/code]

3. servlet-context.xml Θα πρέπει επίσης να προσθέσουμε την ίδια γραμμή στο servlet-context.xml εάν επιθυμούμε να αναχαιτίσουμε Controllers του Spring.

[code language=”xml” highlight=”2″]


[/code]

Υπάρχων κώδικας

Ας υποθέσουμε ότι έχουμε ένα απλό service του οποίου τις μεθόδους θέλουμε να αναχαιτίσουμε

[code language=”java”]
package com.gr.zenika.aopexample.services;
@Service
public class MyService {
public void doSomething(){
System.out.println(“doSomething() is running “);
}
public String doSomethingAndReturn(){
System.out.println(“doSomethingAndReturn() is running “);
return “something”;
}
}
[/code]

Aspect

Έπειτα δημιουργούμε την κλάση AopConfig που δηλώσαμε ως bean παραπάνω. Σε αυτή την κλάση θα δώσουμε το Annotation @Aspect. Επειδή η κλάση αυτή είναι δηλωμένη στο root-context.xml ώς bean αυτό σημαίνει ότι μπορεί να την διαχειριστεί το Spring και κάνουμε @Autowired ότι χρειαζόμαστε

[code language=”java” highlight=”1″]
@Aspect
public class AOPConfig {
private static Logger logger = LoggerFactory.getLogger(AOPConfig.class);

}
[/code]

Ας εμπλουτίσουμε την κλάση με τα διάφορα Annotations του AspectJ ανάλογα με το τι θέλουμε να κάνουμε και με ποιον τρόπο θέλουμε να αναχαιτίσουμε τις μεθόδους.

@Before
Για την περίπτωση που θέλουμε να τρέξουμε μία διαδικασία πριν από την μέθοδο.

[code language=”java”]
@Before(“execution(* com.gr.zenika.aopexample.services.MyService.doSomething(..))”)
public void interceptBefore(JoinPoint point) {
logger.debug(“AOP: method {} was called”, point.getSignature().getName());
}
[/code]

Αν τρέξουμε το project και καλέσουμε την μέθοδο doSomething() θα δούμε ότι στην κονσόλα θα τυπωθεί

[code language=”java”]
AOP: method interceptBefore was called
doSomething() is running
[/code]

που σημαίνει ότι η μέθοδος doSomething() αναχαιτήστικε και πριν από αυτή έτρεξε η interceptBefore. Κατ’ αντιστοιχία λειτουργούν και οι υπόλοιπες περιπτώσεις.

@After
Για την περίπτωση που θέλουμε να τρέξουμε μία διαδικασία μετά από την εκτέλεση μίας μεθόδου. Πολύ χρήσιμο σε περίπτωση Logging.

[code language=”java”]
@After(“execution(* com.gr.zenika.aopexample.services.MyService.doSomething(..))”)
public void interceptAfter(JoinPoint point) {
logger.debug(“AOP: method {} was called”, point.getSignature().getName());
}
[/code]

Output:

[code language=”java”]
doSomething() is running
AOP: method interceptAfter was called
[/code]

@AfterReturning
Σε περίπτωση που θέλουμε να χρησιμοποιήσουμε το αποτέλεσμα που επιστρέφει μία μέθοδος

[code language=”java”]

@AfterReturning(pointcut = “execution(* com.gr.zenika.aopexample.services.MyService.doSomethingAndReturn(..))”,
returning = “result”)
public void interceptReturn(JoinPoint point, Object result) {
logger.debug(“AOP: method {} was called”, point.getSignature().getName());

logger.debug(“AOP: and returned-> ” + result);
}
[/code]

Output:

[code language=”java”]
doSomethingAndReturn() is running
AOP: method interceptReturn was called
AOP: and returned-> something
[/code]

@Around
Σε περίπτωση που θέλουμε να τρέξουμε κομμάτια κώδικα πριν και μετά ακριβώς από μία μέθοδο. Πολύ χρήσιμο σε περίπτωση που θέλουμε να κάνουμε κάποιου είδος profiling όπως μπορούμε να δούμε στο παράδειγμα παρακάτω:

[code language=”java”]

@Around(“execution(* com.gr.zenika.aopexample.services.MyService.doSomethingAndReturn(..))”)
public Object interceptAround(ProceedingJoinPoint pjp) throws Throwable {

logger.debug(“AOP: method {} was called”, pjp.getSignature().getName());
long start = System.currentTimeMillis();
Object result = pjp.proceed();
long elapsedTime = System.currentTimeMillis() – start;
logger.debug(“AOP: execution time: ” + elapsedTime + ” milliseconds.”);

return result;
}
[/code]

Output:

[code language=”java”]
AOP: method interceptAround was called
doSomethingAndReturn() is running
AOP: execution time: 7 milliseconds.
[/code]

Προσοχή:Mε το Annotation @Around θα πρέπει οπωσδήποτε η μέθοδός μας να επιστρέφει ένα Object το οποίο το γεμίζουμε όταν καλούμε την pjp.proceed(). Αν δεν το κάνουμε αυτό η μέθοδος doSomethingAndReturn θα επιστρέψει null!

Passionate Archer, Runner, Linux lover and JAVA Geek! That's about everything! He has worked for many years as an Software Architect designing and developing enterprize projects, e-banking and high availability portals with extensive experience in the public, european and private sectors. Having speaker in several confrences he never misses opportunities to interact with the OSS community. In his leisure time he either runs or shoots a lot of arrows!

2 thoughts on “Aspect Oriented Programming (AOP) σε Spring

  1. Lucia

    It’s hard to find your articles in google.
    I found it on 19 spot, you should build quality backlinks , it will help you to rank to google
    top 10. I know how to help you, just search in google – k2 seo tips

  2. Florida

    I see a lot of interesting articles on your blog. You have to spend a lot
    of time writing, i know how to save you a
    lot of time, there is a tool that creates unique, SEO friendly articles in couple of seconds,
    just type in google – k2 unlimited content

Comments are closed.