@Target(ElementType.METHOD)@Retention(RetentionPolicy.SOURCE)public @interface Override {} @interface:聲明這是一個註解
@Retention:聲明註解的策略,可參見RetentionPolicy。SOURCE
public enum RetentionPolicy { ###儲存在原始碼中,會被編譯器拋棄 SOURCE, ###編譯時間生效,會對代碼最後產生的class有一定影響,在運行時則不保留。此值為預設值 CLASS, ###編譯時間生效,會對代碼最後產生的class有一定影響,在運行時保留,通常通過反射讀取。 RUNTIME}@Target:聲明註解可以被放在什麼樣的元素上面,詳見ElementType
如果需要加入一個叫做age的變數,則代碼如下:
@Target(ElementType.METHOD)@Retention(RetentionPolicy.SOURCE)public @interface Override { int age();}
寫個RetentionPolicy=CLASS的註解,通過javac來試一下註解@Retention(RetentionPolicy.CLASS)@Target(ElementType.TYPE)public @interface Assignment { String assignee();} 註解process
@SupportedSourceVersion(SourceVersion.RELEASE_6)@SupportedAnnotationTypes("Assignment")public class AssignmentProcess extends AbstractProcessor { private TypeElement assignmentElement; public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); Elements elementUtils = processingEnv.getElementUtils(); assignmentElement = elementUtils.getTypeElement("Assignment"); } public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(assignmentElement); for (Element element : elements) { System.out.println(element); } return true; }} @Assignment(assignee = "123")public class Demo1 {}執行:
javac -processor AssignmentProcess Demo1.javaDemo1
按道理來說一切正常,不過悲劇的是把註解的retention改成source還是可以執行的,按照前面的理解,source的應該在編譯器中讀不到的
@Retention(RetentionPolicy.SOURCE)
對Assignment的retention進行修改,看編譯後Demo1的class檔案挺正常的樣子@Retention(RetentionPolicy.SOURCE)
public class Demo1 extends java.lang.Object SourceFile: "Demo1.java"
@Retention(RetentionPolicy.CLASS)
public class Demo1 extends java.lang.Object SourceFile: "Demo1.java" RuntimeInvisibleAnnotations: length = 0xB 00 01 00 0B 00 01 00 0C 73 00 0D
@Retention(RetentionPolicy.RUNTIME)
public class Demo1 extends java.lang.Object SourceFile: "Demo1.java" RuntimeVisibleAnnotations: length = 0xB 00 01 00 0B 00 01 00 0C 73 00 0D
問題木找到,待研究。寫個RetentionPolicy=RUNTIME的註解試一下注釋
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface RoleCheck { String role();} handle,內部通過反射取得注釋資訊,驗證是否可以調用該方法public class AccessInvocationHandler implements InvocationHandler { final Object accessObj; public AccessInvocationHandler(Object accessObj){ this.accessObj = accessObj; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { RoleCheck annotation = method.getAnnotation(RoleCheck.class); // 通過反射API擷取註解 if (annotation != null) { String role = annotation.role(); if (!StringUtil.equals(role, CurrentRoleUtil.getCurrentRole())) { throw new AccessControlException("The user is not allowed to invoke this method."); } return method.invoke(accessObj, args); } else { throw new AccessControlException("The user is not allowed to invoke this method."); } }}類比cache等工具,擷取當前執行的role
public class CurrentRoleUtil { private static int cur = 0; public static String getCurrentRole(){ if(cur%2==0){ ++cur; return "guanfei"; } ++cur; return "hake"; }}通過代理調用
public static void main(String[] args) { HelloWorld hello = new HelloWorldImpl(); InvocationHandler handler = new AccessInvocationHandler(hello); HelloWorld proxy = (HelloWorld)Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler); proxy.sayHello(); proxy.sayHello(); }執行結果
Hello World!Exception in thread "main" java.security.AccessControlException: The user is not allowed to invoke this method.at AccessInvocationHandler.invoke(AccessInvocationHandler.java:20)at $Proxy0.sayHello(Unknown Source)at Test.main(Test.java:11)
如果把注釋的@Retention(RetentionPolicy.CLASS)
Exception in thread "main" java.security.AccessControlException: The user is not allowed to invoke this method.at AccessInvocationHandler.invoke(AccessInvocationHandler.java:24)at $Proxy0.sayHello(Unknown Source)at Test.main(Test.java:9)
通過反射不能取到該注釋