1 Temmuz 2015 Çarşamba

Spring AOP

Aspect ve Around Nedir?
Metoda girmeden önce ve girdikten sonra çağırılan kod parçasına around denilir.

Eğer Aspect kullanamıyorsak ve elle bir şey yazmak gerekiyorsa çözüm olarak ExecuteAround Idiom ile kullanılabilir.


AOP Kullanımı
Spring ile AOP kullanmak için iki yöntem var. Birincisi Spring'in kendi AOP paketleri, diğeri ise AspectJ derleyicisi. Spring'in kendi AOP paketlerini kullanınca - altta ya JDK Dynamic Proxy ya da CGLIB kullanıyor - şöyle bir dezavantaj var ki aslında sitede yazmasına rağmen pek dikkat çekmiyor.
"Due to the proxy-based nature of Spring's AOP framework, protected methods are by definition not intercepted, neither for JDK proxies (where this isn't applicable) nor for CGLIB proxies (where this is technically possible but not recommendable for AOP purposes). As a consequence, any given pointcut will be matched against public methods only!
If your interception needs include protected/private methods or even constructors, consider the use of Spring-driven native AspectJ weaving instead of Spring's proxy-based AOP framework. This constitutes a different mode of AOP usage with different characteristics, so be sure to make yourself familiar with weaving first before making a decision."
Yani buradan aldığım şekilde de görüldüğü gibi Spring AOP ile sadece public metotları kesme yöntemi bulunuyor.
İlk şekilde normal çağrı sırasını görebiliriz.
Daha sonra bu çağrıya bir aspect eklemek istersek proxy yöntemi kullanıldığı için sadece public metotları yakalayabiliyoruz.
Calling a Spring Bean's Method with Different Transaction Attributes? sorusuna verilen cevapta da Spring AOP ile sadece dışarıdan ilk çağırılan metod için transaction açılacağı, metodun içinde çağırılan diğer public metodlar içinse transaction açılmadığı için hiç bir etkisinin olmayacağı yazılı.


JDK Dynamic Proxy
Spring mümkün olduğunca JDK Dynamic Proxy yeteneğini kullanmaya çalışıyor. Bu yeteneği kullanmanın ön koşulu proxy üretilecek sınıfın bir arayüzden türemesiBuradaki soruda arayüzde bulunmaya metodların problem çıkarabileceği anlatılmış. Dolayısıyla JDK Dynamic Proxy yeteneğinin @Transactional ile birlikte kullanılabilmesi için burada görülebildiği @Transactional ile işaretli her metodun arayüzde de bulunması gerekiyor.

Proxy sınıfını kullanmak isteseydik şöyle yapardık. Önce bir arayüz tanımlardık.
public interface Foo {
    public boolean getIsEnabled();
    public void setIsEnabled(boolean enable);
    public void bar();
    public void baz();
    public void bat();

    /*
    Convenience method that can be added in Java 8
    to make the calling code a bit more intuitive.

    public static Foo newFoo() {
        FooBuilder fooBuilder = new FooBuilder();
        return fooBuilder.buildFoo();
    }
    */
}
Daha sonra bir builder sınıfı kodlamamız gerekir. Builder içinde hem arayüzü gerçekleştirren Impl sınıfı hem de bir InvocationHandler kullanmamız gerekir.
public class FooBuilder {
    public Foo buildFoo() {
        return (Foo)Proxy.newProxyInstance(
            this.getClass().getClassLoader(),
            new Class[] { Foo.class },
            new FooInvocationHandler(new FooImpl()));
    } 
}
InvocationHandler metodlar çağrılmadan önce çalıştırılan bir metoda sahip
class FooInvocationHandler implements InvocationHandler {
  private FooImpl foo;

  public FooInvocationHandler(FooImpl foo) {
    this.foo = foo;
  }

  @Override
  public Object invoke(Object proxy,Method method,Object[] args)throws Throwable{
    if (method.getDeclaringClass() == Foo.class &&
       !method.getName().equals("getIsEnabled") &&
       !method.getName().equals("setIsEnabled")) {

       if (!this.foo.getIsEnabled()) {
         return null;
       }
    }

    return method.invoke(this.foo, args);
  }
}










Hiç yorum yok:

Yorum Gönder