2013-02-28 17 views
8

Açıklamalı bir alandaki genel yöntemlerin yürütülmesine uyan bir nokta kesiti yazmak istiyorum. Bu nasıl işe yaramaz ki. Get (@Important) beklediğiniz gibi çalışır (kendi başına) ama elbette sahaya tüm erişim ile eşleşecektir. Bunu sadece genel yöntem yürütme ile sınırlamak istiyorum.Açıklamalı alandaki genel yöntem çağrılarını eşleştirmek için Aspectj Pointcut

Bu mümkün mü? Hiç derleme hatası alıyorum ama diğer taraftan çalışmak için görünmüyor ..


public class Counter { 
    private int count = 0; 

    public void add(int value) { 
    count = count + value; 
    } 
} 

public class Visitors { 
    @Important 
    Counter counter = new Counter() 

    public void increaseCounter() { 
    counter.add(1); 
    } 
} 

Çalışır:

@Pointcut(value = "get(@Important * *)") 
void testPointCut() { 
} 

Çalışmaz:

@Pointcut(value = "get(@Important * *) && execution(public * *(..))") 
void testPointCut() { 
} 

cevap

2

Ne istediğiniz için kutudan çıkmış AspectJ çözümü yoktur, çünkü herhangi bir nesnenin yöntem yürütmelerini engellerseniz, bu nesnelere işaret eden açıklamalı alanlarla bağlantı yoktur. Açıklamalı sınıfların veya açıklamalı yöntemlerin yöntem yürütmelerini engellemek daha kolay olurdu, ancak bu yapmak istediğiniz şey değil. Gördüğünüz gibi, benim yönü önemli" bir dizi tutar

import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 

@Retention(RetentionPolicy.RUNTIME) 
public @interface Important {} 
public class Counter { 
    private int count = 0; 

    public void add(int value) { 
     count = count + value; 
    } 

    @Override 
    public String toString() { 
     return super.toString() + "[count=" + count + "]"; 
    } 
} 
public class Visitors { 
    @Important 
    Counter counter = new Counter(); 

    public void increaseCounter() { 
     counter.add(1); 
    } 

    public static void main(String[] args) { 
     Visitors visitors = new Visitors(); 
     visitors.increaseCounter(); 
     visitors.counter.add(3); 
     System.out.println("visitors.counter = " + visitors.counter); 
     System.out.println("--------------------"); 

     Counter unimportantCounter = new Counter(); 
     unimportantCounter.add(11); 
     unimportantCounter.add(22); 
     System.out.println("unimportantCounter = " + unimportantCounter); 
     System.out.println("--------------------"); 

     unimportantCounter = visitors.counter; 
     unimportantCounter.add(5); 
     System.out.println("visitors.counter = " + visitors.counter); 
     System.out.println("unimportantCounter = " + unimportantCounter); 
     System.out.println("--------------------"); 

     visitors.counter = new Counter(); 
     visitors.increaseCounter(); 
     visitors.counter.add(3); 
     unimportantCounter.add(100); 
     System.out.println("visitors.counter = " + visitors.counter); 
     System.out.println("unimportantCounter = " + unimportantCounter); 
     System.out.println("--------------------"); 

     Visitors otherVisitors = new Visitors(); 
     otherVisitors.increaseCounter(); 
     otherVisitors.counter.add(50); 
     System.out.println("otherVisitors.counter = " + otherVisitors.counter); 
     System.out.println("--------------------"); 

     otherVisitors.counter = visitors.counter; 
     System.out.println("visitors.counter = " + visitors.counter); 
     System.out.println("otherVisitors.counter = " + otherVisitors.counter); 
     System.out.println("--------------------"); 

     otherVisitors.counter = new Counter(); 
     visitors.increaseCounter(); 
     otherVisitors.increaseCounter(); 
     System.out.println("visitors.counter = " + visitors.counter); 
     System.out.println("otherVisitors.counter = " + otherVisitors.counter); 
    } 
} 
import java.lang.reflect.Field; 
import java.util.HashMap; 
import java.util.HashSet; 
import java.util.Map; 
import java.util.Set; 

import org.aspectj.lang.Signature; 
import org.aspectj.lang.SoftException; 

public aspect ImportantMethodInterceptor { 
    Map<Object, Set<Object>> importantObjects = new HashMap<Object, Set<Object>>(); 

    pointcut importantSetter(Object newValue, Object target) : 
     set(@Important * *) && args(newValue) && target(target); 
    pointcut unimportantSetter(Object newValue, Object target) : 
     !set(@Important * *) && set(* *) && !withincode(*.new(..)) && args(newValue) && target(target); 
    pointcut publicMethod(Object target) : 
     execution(public * *(..)) && target(target) && !execution(public String *..toString()); 

    before(Object newValue, Object target) : importantSetter(newValue, target) { 
     Object oldValue = getFieldValue(thisJoinPoint.getSignature(), target); 
     System.out.println("Important object for target " + target + ": " + oldValue + " -> " + newValue); 
     synchronized (importantObjects) { 
      Set<Object> referrers; 
      if (oldValue != null) { 
       referrers = importantObjects.get(oldValue); 
       if (referrers != null) { 
        referrers.remove(target); 
        if (referrers.size() == 0) 
         importantObjects.remove(oldValue); 
       } 
      } 
      if (newValue != null) { 
       referrers = importantObjects.get(newValue); 
       if (referrers == null) { 
        referrers = new HashSet<Object>(); 
        importantObjects.put(newValue, referrers); 
       } 
       referrers.add(target); 
      } 
     } 
    } 

// before(Object newValue, Object target) : unimportantSetter(newValue, target) { 
//  Object oldValue = getFieldValue(thisJoinPoint.getSignature(), target); 
//  System.out.println("Unimportant object for target " + target + ": " + oldValue + " -> " + newValue); 
// } 

    before(Object target) : publicMethod(target) { 
     synchronized (importantObjects) { 
      if (importantObjects.get(target) != null) 
       System.out.println("Important method on " + target + ": " + thisJoinPointStaticPart); 
      else 
       System.out.println("Unimportant method on " + target + ": " + thisJoinPointStaticPart); 
     } 
    } 

    private Object getFieldValue(Signature signature, Object target) { 
     try { 
      Field field = signature.getDeclaringType().getDeclaredField(signature.getName()); 
      field.setAccessible(true); 
      return field.get(target); 
     } 
     catch (Exception e) { throw new SoftException(e); } 
    } 
} 

: Burada

ayrıca sınırlamalar size geçici bir çözüm gösterir biraz kod örneği olmakla nesneleri". Daha doğrusu, anahtarların "önemli nesneler" olduğu ve değerlerin yönlendirme kümesi olduğu Map'dur. Bu gereklidir çünkü teorik olarak birkaç yönlendirici (ör. Visitors nesneleri) aynı "önemli nesnelere" işaret edebilir (örneğin, belirli bir Counter). Basit bir kümede "önemli nesneleri" kaydettiğimde örnek kodumun önceki bir sürümünde, daha önce hiç başvurulmadıklarında veya her zaman bunları bile kaldırarak bile daha önce "önemli nesneleri" daha önce kaldırma seçeneğini seçtim ikinci bir yönlendirici hala "önemli bir nesneyi" işaret ediyorduysa. Harita yaklaşımı, "önemli nesne" başına birden fazla yönlendirici kaydetmemi sağlıyor. Eğer Visitors.main(String[]) çalıştırırsanız

yaptığında (çıktıyı daha bakın log istiyorsanız before ... : unimportantSetter ... tavsiye yorumsuz lütfen) şu çıktıyı göreceksiniz:

Important object for target [email protected]: null -> [email protected][count=0] 
Unimportant method on [email protected]: execution(void Visitors.increaseCounter()) 
Important method on [email protected][count=0]: execution(void Counter.add(int)) 
Important method on [email protected][count=1]: execution(void Counter.add(int)) 
visitors.counter = [email protected][count=4] 
-------------------- 
Unimportant method on [email protected][count=0]: execution(void Counter.add(int)) 
Unimportant method on [email protected][count=11]: execution(void Counter.add(int)) 
unimportantCounter = [email protected][count=33] 
-------------------- 
Important method on [email protected][count=4]: execution(void Counter.add(int)) 
visitors.counter = [email protected][count=9] 
unimportantCounter = [email protected][count=9] 
-------------------- 
Important object for target [email protected]: [email protected][count=9] -> [email protected][count=0] 
Unimportant method on [email protected]: execution(void Visitors.increaseCounter()) 
Important method on [email protected][count=0]: execution(void Counter.add(int)) 
Important method on [email protected][count=1]: execution(void Counter.add(int)) 
Unimportant method on [email protected][count=9]: execution(void Counter.add(int)) 
visitors.counter = [email protected][count=4] 
unimportantCounter = [email protected][count=109] 
-------------------- 
Important object for target [email protected]: null -> [email protected][count=0] 
Unimportant method on [email protected]: execution(void Visitors.increaseCounter()) 
Important method on [email protected][count=0]: execution(void Counter.add(int)) 
Important method on [email protected][count=1]: execution(void Counter.add(int)) 
otherVisitors.counter = [email protected][count=51] 
-------------------- 
Important object for target [email protected]: [email protected][count=51] -> [email protected][count=4] 
visitors.counter = [email protected][count=4] 
otherVisitors.counter = [email protected][count=4] 
-------------------- 
Important object for target [email protected]: [email protected][count=4] -> [email protected][count=0] 
Unimportant method on [email protected]: execution(void Visitors.increaseCounter()) 
Important method on [email protected][count=4]: execution(void Counter.add(int)) 
Unimportant method on [email protected]: execution(void Visitors.increaseCounter()) 
Important method on [email protected][count=0]: execution(void Counter.add(int)) 
visitors.counter = [email protected][count=5] 
otherVisitors.counter = [email protected][count=1] 

dikkatlice günlük çıkışına main kodu karşılaştırmak Lütfen hangi düzenli ve özel durumları test ettiğimi görmek için.

  • Ben önemli alanlar int gibi ilkel türleri vardır ya teorik olarak "önemli nesneleri" olarak birden çok kez ortaya çıkabilir String ler ise ne olacağı test etmedim:

    Dediğim gibi

    , yaklaşım sınırlamaları vardır çünkü ilgisiz birkaç önemli üye eşit nesneler yaratır. Ayrıca otomatik (un) boksla ilgili ne olduğunu test etmedim, lütfen kendiniz deneyin. Görünüm kodu bir şekilde karmaşıktır ve muhtemelen şaşırtıcı derecede hızlı değildir.
  • Henüz düşünmediğim başka sorunların olmayacağını garanti edemem.

Ancak, sınır koşullarını ve kullanım durumlarını kontrol ediyorsanız, ihtiyacınız olanı elde etmek için bilinçli bir karar verebilir ve kodu olduğu gibi kullanabilirsiniz. Kod muhtemelen iyileştirme potansiyeline sahip, sadece merak ettim ve bir konsept kanıtı kırmak istedim.

+1

Şüphelendiğimi onayladığınız için, kullanıma hazır AJ ile istediğimi yapmak mümkün değil. AJ için çok yeni olmama rağmen, POC'nizde ne yapmaya çalıştığınızı görebiliyorum. Çok ilginç ve eğitici! Teşekkür ederiz! – JustOneMoreQuestion

0

Bunu, withinCode pointcut kullanmak istiyorum:

@Pointcut(value = "get(@Important * *) && withinCode(public * *(..))") 
void testPointCut() { 
} 

AspectJ programming guide göz at.

+1

Bu, açıklamalı alana tüm erişimi yakalar. Sadece açıklamalı alandaki genel yöntemlerin yürütülmesini eşleştirmek istiyorum. – JustOneMoreQuestion

İlgili konular