1. 程式人生 > 實用技巧 >Scrapy分散式爬蟲,分散式佇列和布隆過濾器,一分鐘搞定?

Scrapy分散式爬蟲,分散式佇列和布隆過濾器,一分鐘搞定?

Annotation(註解)的作用

1.Annotation具有"讓編譯器進行編譯檢查的作用"。
2. 在反射中使用 Annotation。
3.根據 Annotation 生成幫助文件。
4.能夠幫忙檢視檢視程式碼。

定義註解

先看下面一段程式碼:

/*
    定義一個註解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {}

註解的定義和介面的定義看起來很像,與任何其他介面一樣,註解也會被編譯成class檔案。1個Annotation(註解)和1個RetentionPolicy 關聯和1~n 個 ElementType 關聯。

定義註解時,會需要一些元註解,如:

@interface:
使用 @interface 定義註解時,意味著它實現了 java.lang.annotation.Annotation 介面,即該註解就是一個Annotation。定義 Annotation 時,@interface 是必須的。

@Target:
用來定義你的註解將應用於什麼地方:欄位(FIELD),方法(METHOD),類/介面/列舉(TYPE),構造器(CONSTRUCTOR),區域性變數(LOCAL_VARIABLE),包(PACKAGE)等等。

@Retention:
用來定義註解在那一級別可用:在原始碼中(SOURCE)註解將被編譯器丟掉,類檔案中(CLASS)註解將被JVM丟掉,執行時(RUNTIME)在執行期也保留註解,因此可以通過反射機制讀取註解資訊。

@Documented:
它的作用是說明該註解能出現在 javadoc中。

@Inherited:
它所標註的Annotation將具有繼承性。

在註解中,一般會包含一些元素以表示某些值。當分析處理註解時,程式或工具可以利用這些值。註解的元素看起來就像介面的方法。唯一的區別是你可以為其指定預設值。
沒有元素的註解成為標記註解。例如上面的@Test

下面再看一個簡單的註解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
    /*
        以下的 id,description都是註解的元素,它們看起來像是介面的方法一樣。
        它們之間唯一的區別:
        我們可以為註解的元素指定預設值。就像description那樣。
     */
    public int id();
    public String description() default "no description";
}

下面的類中,有三個方法被註解為用例:

public class PasswordUtils {

    @UseCase(id = 47, description = "Password must contain at least one numeric")
    public boolean validatePassword(String password){
        return password.matches("\\w*\\d*\\w*");
    }
    @UseCase(id =48)
    public String encryptPassword(String password){
        return new StringBuilder(password).reverse().toString();
    }

    @UseCase(id = 49, description = "New passwords can`t equal previously used ones")
    public boolean checkForPassword(List<String> prePassword, String password){
       return !prePassword.contains(password);
    }
    
}

編寫註解處理器

如果沒有讀取註解的工具,那麼註解也就不會比註釋好用。所以在使用註解的過程中,建立和使用註解處理器是很重要的。
Java SE5提供了兩種方式來幫助程式設計師構造這類工具:
1.Java SE5擴充套件了反射機制的API。
2.提供了一個外部工具apt。

通過反射機制構造處理器

下面是個簡單的註解處理器,用它來讀取PasswordUtils類:

public class UseCaseTracker {
    public static void trackUseCase(List<Integer> useCase, Class cl){

        for(Method m : cl.getDeclaredMethods())
        {
            UseCase uc = m.getAnnotation(UseCase.class);//返回指定型別的註解物件
            if (uc != null)
            {
                System.out.println("Found Use Case:" + uc.id() + " " + uc.description());
                useCase.remove(new Integer(uc.id()));
            }
        }

        for(int i : useCase)
        {
            System.out.println("Warning: Missing use case-" + i);
        }
    }

    public static void main(String[] args) {
        List<Integer> useCase = new ArrayList<Integer>();
        Collections.addAll(useCase, 47,48,49,50);
        trackUseCase(useCase, PasswordUtils.class);
    }
}

通過getDeclaredMethods()獲得本類的所有方法,包括私有的(private、protected、預設以及public)。然後呼叫getAnnotation()方法,獲得每個方法上的註解物件。每一個註解都設定了id值。我們可以通過此id值找出已存在的用例,以及缺失的用例。

註解元素

註解元素的可用型別如下:
1.所有的基本型別
2.String
3.Class
4.enmu
5.Annotation(註解也可以作為註解元素,即註解可以巢狀)
6.以上型別的陣列(即註解元素也可以是以上型別的集合)

預設值限制

編譯器對註解元素的預設值檢查的極為嚴格,元素不能有不確定的值。要麼具有預設值,要麼在使用註解時提供值。
對於非基本型別的元素,不能用null作為預設值。這個約束不能很好的反應一個元素的存在或缺失狀態,因為編譯器要求每個元素都存在。
為了解決這個問題,我們約定俗成用空字串或者負數來表示這個元素不存在。