注解的寫法和接口很類似,都采用了關鍵字interface,而且都不能有實現代碼,常量定義默認都是pulbic static final類型的.
他們的主要不同點是:注解在interface前加上@字符,而且不能繼承,不能實現,這經常會給我們的開發帶來一些障礙.
分析一個ACL(Access Contorl List ,訪問控制列表)設計案例..看看如何避免這些障礙.
ACL中有三個重要的元素:
1.資源,有哪些信息是要被控制起來的.
2.權限級別,不同的訪問者在規划在不同的級別中.
3.控制器(也叫鑒權人),控制不同的級別訪問不同的資源.
鑒權人是整個ACL的實際核心,我們從最主要的鑒權人開始,看代碼:
//鑒權者接口 interface Identifier { //無權訪問時的禮貌語 String REFUSE_WORD = "您無權訪問"; // 鑒權 public boolean identify(); }
這是一個鑒權人的接口,定義了一個常量和一個鑒權方法,接下來應該實現該鑒權方法,但問題是我們的權限級別和鑒權方法之間是緊耦合的,若分拆成兩個類顯得有點啰嗦,怎么辦?我們可以直接定義一個枚舉來實現.
//常用鑒權者 enum CommonIdentifier implements Identifier { //權限級別 Reader, Author, Admin; //實現鑒權 public boolean identify() { return false; } }
定義了一個通用鑒權者,使用的是枚舉類型,並且實現了鑒權者接口,現在就剩下資源定義了,這很容易定義,資源就是我們寫的類,方法等,之后再通過配置來決定哪些類,方法允許什么級別的訪問,這里的問題是:怎么把資源和權限級別關聯起來呢?
使用XML配置文件?是個方法,但是對於我們的示例程序來說顯得太過繁重,使用注解會更簡潔些.需要首先定義出權限級別的注解,代碼如下:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @interface Access { //確定什么級別可以訪問 CommonIdentifier level() default CommonIdentifier.Admin; }
該注解是標注在類上面的,並且會保留到運行期,我們定義一個資源類,代碼如下:
//商業邏輯,默認訪問權限是Admin @Access(level = CommonIdentifier.Author) class Foo { }
Foo類只能是作者級別的人的訪問,場景定義完畢,看如何模擬ACL的實現...看代碼:
1 import java.lang.annotation.ElementType; 2 import java.lang.annotation.Retention; 3 import java.lang.annotation.RetentionPolicy; 4 import java.lang.annotation.Target; 5 6 public class Client { 7 public static void main(String[] args) { 8 //初始化商業邏輯 9 Foo b = new Foo(); 10 //獲取注解 11 Access access = b.getClass().getAnnotation(Access.class); 12 //沒有Access注解或者鑒權失敗 13 if (access == null || !access.level().identify()) { 14 //沒有Access注解或者鑒權失敗 15 System.out.println(access.level().REFUSE_WORD); 16 } 17 18 } 19 20 } 21 22 //商業邏輯,默認訪問權限是Admin 23 @Access(level = CommonIdentifier.Author) 24 class Foo { 25 26 } 27 28 //鑒權者接口 29 interface Identifier { 30 //無權訪問時的禮貌語 31 String REFUSE_WORD = "您無權訪問"; 32 // 鑒權 33 public boolean identify(); 34 } 35 36 //常用鑒權者 37 enum CommonIdentifier implements Identifier { 38 //權限級別 39 Reader, Author, Admin; 40 41 //實現鑒權 42 public boolean identify() { 43 return false; 44 } 45 } 46 47 @Retention(RetentionPolicy.RUNTIME) 48 @Target(ElementType.TYPE) 49 @interface Access { 50 //確定什么級別可以訪問 51 CommonIdentifier level() default CommonIdentifier.Admin; 52 }
打印輸出:
您無權訪問
這段代碼,簡單,易讀,而且是通過ClassLoader類來解釋該注解的,那會使開發更加簡潔,所有的開發人員只要增加注解即可以解決訪問控制問題.
//======================================================================
1 import java.lang.annotation.ElementType; 2 import java.lang.annotation.Retention; 3 import java.lang.annotation.RetentionPolicy; 4 import java.lang.annotation.Target; 5 6 public class Client { 7 public static void main(String[] args) { 8 MyAnno an1 = Foo.class.getAnnotation(MyAnno.class); 9 MyAnno an2 = Impl.class.getAnnotation(MyAnno.class); 10 System.out.println(an1);//@cn.summerchill.test.MyAnno(desc=@cn.summerchill.test.MyAnno2(a=a1a)) 11 System.out.println(an2);//@cn.summerchill.test.MyAnno(desc=@cn.summerchill.test.MyAnno2(a=aa)) 12 System.out.println(an1.hashCode());//391187329 13 System.out.println(an2.hashCode());//391149008 14 System.out.println(an1.equals(an2));//false 15 System.out.println(an1 == an2);//false 16 } 17 } 18 19 20 @MyAnno(desc =@MyAnno2(a="a1a")) 21 class Foo { 22 public void doSomething(){ 23 24 } 25 } 26 @MyAnno(desc =@MyAnno2(a="aa")) 27 class Impl { 28 29 public void doSomething() { 30 } 31 } 32 33 34 @Retention(RetentionPolicy.RUNTIME) 35 @Target(ElementType.TYPE) 36 @interface MyAnno { 37 MyAnno2 desc(); 38 } 39 40 @interface MyAnno2{ 41 String a() default ""; 42 }