2015-04-16 13 views
5

Tôi đang gặp một chút rắc rối khi tìm cách tạo một đường cắt sẽ hoạt động trên các hạt có thông số chú thích cụ thể. Mục đích cuối cùng của tôi là xác nhận giá trị của tham số trước khi nó được xử lý, nhưng trong thời điểm này tôi chỉ cần tạo ra các điểm cắt.Cách viết một đường cắt khía cạnh dựa trên thông số có chú thích

Hãy xem xét các chú thích sau

@Retention(RetentionPolicy.RUNTIME) 
@Target({ ElementType.PARAMETER }) 
public @interface MyAnnotation {} 

sau đó tôi muốn áp dụng điều này để một số phương pháp như:

public void method1(@MyAnnotation long i) {} 
public void method2(String someThing, @MyAnnotation long i) {} 
public void method3(String someThing, @MyAnnotation long i, byte value) {} 

Vì vậy

  • Tôi không quan tâm mà lớp (hoặc gói) các phương pháp có trong
  • Vị trí của chú thích đối số ed sẽ thay đổi.
  • Tôi biết rằng giá trị chú thích sẽ chỉ áp dụng đối với một loại hình cụ thể

thực hiện pointcut tôi cần phải được một cái gì đó dọc theo dòng:

@Before(value = "* *(..) && args(verifyMe)") 
public void verifyInvestigationId(long verifyMe) {} 

Tôi nhận được một chút bối rối về chính xác giá trị của @Before cần phải thực hiện và cách gắn trong chú thích và loại của nó. Tại thời điểm này có lẽ không đáng liệt kê những thứ tôi đã thử!

Cập nhật: Dựa trên những lời khuyên tôi đã nhìn thấy trong http://stackoverflow.com/questions/3565718/pointcut-matching-methods-with-annotated-parameters/3567170#3567170 (và sửa chữa một vài hiểu lầm và thêm không gian tôi bỏ qua) tôi đã có tới điểm mà các công việc sau:

@Before("execution(public * *(.., @full.path.to.MyAnnotation (*), ..))") 
public void beforeMethod(JoinPoint joinPoint) { 
    System.out.println("At least one of the parameters are annotated with @MyAnnotation"); 
} 

này là gần như những gì tôi cần - tất cả những gì cần làm là vượt qua giá trị của tham số chú thích như một tham số để phương pháp. Tôi có thể không hoàn toàn làm việc ra cú pháp để có được mùa xuân để làm điều này (câu trả lời liên kết không hiển thị này).

+0

thể trùng lặp của [pointcut phương pháp phù hợp với các thông số chú thích] (http://stackoverflow.com/questions/2766844/pointcut-matching-methods-with-annotated-parameters) – sheltem

+0

@sheltem, Cảm ơn đã chỉ cho tôi điều này. Thật không may, đây là một trong những điều tôi đã thử, nhưng thất bại. Các nhật ký chứa lỗi: Dấu cắt không được định dạng đúng: mong đợi 'mẫu tên' ở vị trí ký tự 56 thực thi (công khai * * (.., @ aspect.VerifyMe (*), ..)) – Stormcloud

+0

BTW: có hai các ngôi sao tách biệt bởi một khoảng trắng sau từ 'công khai' - stackoverflow đã diễn dịch chúng như nghiêng! – Stormcloud

Trả lời

5

Rất giống với my answer heresheltem đã chỉ ra, giải pháp trông như thế này (trong cú pháp chú thích theo phong cách thời điểm này vì trong Spring AOP bạn không thể sử dụng cú pháp AspectJ mẹ đẻ):

chú thích gốc tấm áp phích của:

package annotations; 

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

@Retention(RetentionPolicy.RUNTIME) 
@Target({ ElementType.PARAMETER }) 
public @interface MyAnnotation {} 

điều khiển ứng dụng:

Tôi sử dụng ứng dụng trình điều khiển để kiểm tra giải pháp AspectJ của mình. Vào mùa xuân, lớp cũng như khía cạnh cần phải là các bean/thành phần Spring để làm việc này.

package de.scrum_master.app; 

import java.util.ArrayList; 
import java.util.HashSet; 
import java.util.List; 
import java.util.Set; 

import annotations.MyAnnotation; 

public class Application { 
    public void method1(@MyAnnotation int i) {} 
    public void method2(String id, @MyAnnotation float f) {} 
    public void method3(int i, @MyAnnotation List<String> strings, @MyAnnotation String s) {} 
    public void method4(int i, @MyAnnotation Set<Integer> numbers, float f, boolean b) {} 
    public void method5(boolean b, String s, @MyAnnotation String s2, float f, int i) {} 
    public void notIntercepted(boolean b, String s, String s2, float f, int i) {} 

    public static void main(String[] args) { 
     List<String> strings = new ArrayList<String>(); 
     strings.add("foo"); 
     strings.add("bar"); 
     Set<Integer> numbers = new HashSet<Integer>(); 
     numbers.add(11); 
     numbers.add(22); 
     numbers.add(33); 

     Application app = new Application(); 
     app.method1(1); 
     app.method2("foo", 1f); 
     app.method3(1, strings, "foo"); 
     app.method4(1, numbers, 1f, true); 
     app.method5(false, "foo", "bar", 1f, 1); 
     app.notIntercepted(false, "foo", "bar", 1f, 1); 
    } 
} 

Aspect:

package de.scrum_master.aspect; 

import java.lang.annotation.Annotation; 

import org.aspectj.lang.JoinPoint; 
import org.aspectj.lang.SoftException; 
import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Before; 
import org.aspectj.lang.reflect.MethodSignature; 

import annotations.MyAnnotation; 

@Aspect 
public class ArgCatcherAspect { 
    @Before("execution(public * *(.., @MyAnnotation (*), ..))") 
    public void interceptMethodsWithAnnotatedParameters(JoinPoint thisJoinPoint) { 
     System.out.println(thisJoinPoint); 
     MethodSignature signature = (MethodSignature) thisJoinPoint.getSignature(); 
     String methodName = signature.getMethod().getName(); 
     Class<?>[] parameterTypes = signature.getMethod().getParameterTypes(); 
     Annotation[][] annotations; 
     try { 
      annotations = thisJoinPoint.getTarget().getClass(). 
       getMethod(methodName, parameterTypes).getParameterAnnotations(); 
     } catch (Exception e) { 
      throw new SoftException(e); 
     } 
     int i = 0; 
     for (Object arg : thisJoinPoint.getArgs()) { 
      for (Annotation annotation : annotations[i]) { 
       if (annotation.annotationType() == MyAnnotation.class) 
        System.out.println(" " + annotation + " -> " + arg); 
        // Verify 'arg' here or do whatever 
      } 
      i++; 
     } 
    } 
} 

điều khiển đăng nhập:

execution(void de.scrum_master.app.Application.method1(int)) 
    @annotations.MyAnnotation() -> 1 
execution(void de.scrum_master.app.Application.method2(String, float)) 
    @annotations.MyAnnotation() -> 1.0 
execution(void de.scrum_master.app.Application.method3(int, List, String)) 
    @annotations.MyAnnotation() -> [foo, bar] 
    @annotations.MyAnnotation() -> foo 
execution(void de.scrum_master.app.Application.method4(int, Set, float, boolean)) 
    @annotations.MyAnnotation() -> [33, 22, 11] 
execution(void de.scrum_master.app.Application.method5(boolean, String, String, float, int)) 
    @annotations.MyAnnotation() -> bar 
+0

Rất kỹ lưỡng, câu trả lời tốt. –

0

Đây là những gì tôi đã kết thúc tại sau khi quan trọng về với nó (nhập khẩu bỏ qua):

@Aspect 
public class VerifyAspect { 

    @Before("execution(* *(.., @annotations.MyAnnotation (*), ..)) && args(.., verifyMe)") 
    public void verifyInvestigationId(final Object verifyMe) { 
     System.out.println("Aspect verifying: " + verifyMe); 
    } 
} 

Không cần bất cứ điều gì mùa xuân cụ thể, như AspectJ đã cung cấp cho bạn với các thông số nếu muốn.

+0

Nice (và chắc chắn gần hơn bất cứ điều gì tôi đã quản lý để có được làm việc!), Nhưng điều này có một giới hạn rằng các đối số thông qua là "verifyMe" luôn luôn là đối số thực tế thông qua phương pháp cắt điểm. Có cách nào để nói điều gì đó dọc theo dòng "gửi cho tôi các đối số (s) với chú thích được chỉ định" không? – Stormcloud

+0

Bạn nói đúng, điều này có thể không cung cấp cho bạn thông số được chú thích trong mọi trường hợp. Hmm ... quay lại bảng vẽ! – sheltem

+0

Mặc dù là một giải pháp đặc biệt, bạn có thể cho phép AspectJ cung cấp cho bạn JoinPoint và đi qua các tham số của nó thông qua sự phản chiếu để tìm những chú thích có chú thích của bạn. Không phải là rất thanh lịch, nhưng nên làm việc cho một sự khởi đầu. – sheltem

Các vấn đề liên quan