java 注解annotation的使用以及反射如何獲取注解
一、注解基本知識(shí)
1、元注解
元注解是指注解的注解。包括 @Retention @Target @Document @Inherited四種。
1. Annotation型定義為@interface, 所有的Annotation會(huì)自動(dòng)繼承java.lang.Annotation這一接口,并且不能再去繼承別的類或是接口.
2. 參數(shù)成員只能用public或默認(rèn)(default)這兩個(gè)訪問權(quán)修飾
3. 參數(shù)成員只能用基本類型byte,short,char,int,long,float,double,boolean八種基本數(shù)據(jù)類型和String、Enum、Class、annotations等數(shù)據(jù)類型,以及這一些類型的數(shù)組.
4. 要獲取類方法和字段的注解信息,必須通過Java的反射技術(shù)來獲取 Annotation對(duì)象,因?yàn)槟愠酥鉀]有別的獲取注解對(duì)象的方法
5. 注解也可以沒有定義成員, 不過這樣注解就沒啥用了
自定義注解類時(shí), 可以指定目標(biāo) (類、方法、字段, 構(gòu)造函數(shù)等) , 注解的生命周期(運(yùn)行時(shí),class文件或者源碼中有效), 是否將注解包含在javadoc中及是否允許子類繼承父類中的注解, 具體如下:
1. @Target 表示該注解目標(biāo),可能的 ElemenetType 參數(shù)包括:
ElemenetType.CONSTRUCTOR 構(gòu)造器聲明 ElemenetType.FIELD 域聲明(包括 enum 實(shí)例) ElemenetType.LOCAL_VARIABLE 局部變量聲明 ElemenetType.METHOD 方法聲明 ElemenetType.PACKAGE 包聲明 ElemenetType.PARAMETER 參數(shù)聲明 ElemenetType.TYPE 類,接口(包括注解類型)或enum聲明
2. @Retention 表示該注解的生命周期,可選的 RetentionPolicy 參數(shù)包括
RetentionPolicy.SOURCE 注解將被編譯器丟棄 RetentionPolicy.CLASS 注解在class文件中可用,但會(huì)被VM丟棄 RetentionPolicy.RUNTIME VM將在運(yùn)行期也保留注釋,因此可以通過反射機(jī)制讀取注解的信息
3. @Documented 指示將此注解包含在 javadoc 中
4. @Inherited 指示允許子類繼承父類中的注解
二、在java中如何使用
2.1、定義注解
package com.test.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class MyAnnotation {
/**
* 注解類
* @author T4980D
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyClassAnnotation {
String uri();
String desc();
}
/**
* 構(gòu)造方法注解
* @author T4980D
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.CONSTRUCTOR)
public @interface MyConstructorAnnotation {
String uri();
String desc();
}
/**
* 我的方法注解
* @author Owner
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyMethodAnnotation {
String uri();
String desc();
}
/**
* 字段注解定義
* @author Owner
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyFieldAnnotation {
String uri();
String desc();
}
/**
*
* 可以同時(shí)應(yīng)用到類上和方法上
* @author T4980D
*
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Yts {
// 定義枚舉
public enum YtsType {
util, entity, service, model
}
// 設(shè)置默認(rèn)值
public YtsType classType() default YtsType.util;
// 數(shù)組
int[] arr() default {3, 7, 5};
String color() default "blue";
}
}
2.2、基本測(cè)試注解
package com.test.annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import com.test.annotation.MyAnnotation.MyClassAnnotation;
import com.test.annotation.MyAnnotation.MyConstructorAnnotation;
import com.test.annotation.MyAnnotation.MyFieldAnnotation;
import com.test.annotation.MyAnnotation.MyMethodAnnotation;
import com.test.annotation.MyAnnotation.Yts;
import com.test.annotation.MyAnnotation.Yts.YtsType;
@MyClassAnnotation(desc = "The class", uri = "com.test.annotation.Test")
@Yts(classType =YtsType.util)
public class TestAnnotation {
@MyFieldAnnotation(desc = "The class field", uri = "com.test.annotation.Test#id")
private String id;
@MyConstructorAnnotation(desc = "The class constructor", uri = "com.test.annotation.Test#MySample")
public TestAnnotation() {
}
public String getId() {
return id;
}
@MyMethodAnnotation(desc = "The class method", uri = "com.test.annotation.Test#setId")
public void setId(String id) {
System.out.println(" method info: "+id);
this.id = id;
}
@MyMethodAnnotation(desc = "The class method sayHello", uri = "com.test.annotation.Test#sayHello")
@Yts
public void sayHello(String name){
if(name == null || name.equals("")){
System.out.println("hello world!");
}else{
System.out.println(name + "\t:say hello world!");
}
}
public static void main(String[] args) throws Exception {
Class<TestAnnotation> clazz = TestAnnotation.class;
// 得到類注解
MyClassAnnotation myClassAnnotation = clazz.getAnnotation(MyClassAnnotation.class);
System.out.println(myClassAnnotation.desc() + " "+ myClassAnnotation.uri());
// 得到構(gòu)造方法注解
Constructor<TestAnnotation> cons = clazz.getConstructor(new Class[]{});
MyConstructorAnnotation myConstructorAnnotation = cons.getAnnotation(MyConstructorAnnotation.class);
System.out.println(myConstructorAnnotation.desc() + " "+ myConstructorAnnotation.uri());
// 獲取方法注解
Method method = clazz.getMethod("setId", new Class[]{int.class});
MyMethodAnnotation myMethodAnnotation = method.getAnnotation(MyMethodAnnotation.class);
System.out.println(myMethodAnnotation.desc() + " "+ myMethodAnnotation.uri());
// 獲取字段注解
Field field = clazz.getDeclaredField("id");
MyFieldAnnotation myFieldAnnotation = field.getAnnotation(MyFieldAnnotation.class);
System.out.println(myFieldAnnotation.desc() + " "+ myFieldAnnotation.uri());
}
}
2.3、通過反射解析
package com.test.annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import com.test.annotation.MyAnnotation.MyClassAnnotation;
import com.test.annotation.MyAnnotation.MyMethodAnnotation;
import com.test.annotation.MyAnnotation.Yts;
import com.test.annotation.MyAnnotation.Yts.YtsType;
public class ParseAnnotation {
/**
* 解析方法注解
* @param <T>
* @param clazz
*/
public static <T> void parseMethod(Class<T> clazz) {
try {
T obj = clazz.newInstance();
for (Method method : clazz.getDeclaredMethods()) {
MyMethodAnnotation methodAnnotation = method.getAnnotation(MyMethodAnnotation.class);
if (methodAnnotation!=null) {
//通過反射調(diào)用帶有此注解的方法
method.invoke(obj, methodAnnotation.uri());
}
Yts yts = (Yts) method.getAnnotation(Yts.class);
if (yts != null) {
if (YtsType.util.equals(yts.classType())) {
System.out.println("this is a util method");
} else {
System.out.println("this is a other method");
}
System.out.println(Arrays.toString(yts.arr())); //打印數(shù)組
System.out.println(yts.color()); //輸出顏色
}
System.out.println("\t\t-----------------------");
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 解析類注解
* @param <T>
* @param clazz
*/
public static <T> void parseType(Class<T> clazz) {
try {
Yts yts = (Yts) clazz.getAnnotation(Yts.class);
if (yts != null) {
if (YtsType.util.equals(yts.classType())) {
System.out.println("this is a util class");
} else {
System.out.println("this is a other class");
}
}
MyClassAnnotation classAnnotation = (MyClassAnnotation) clazz.getAnnotation(MyClassAnnotation.class);
if (classAnnotation != null) {
System.err.println(" class info: "+classAnnotation.uri());
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
parseMethod(TestAnnotation.class);
parseType(TestAnnotation.class);
}
}
三、注解應(yīng)用案例
3.1、關(guān)于細(xì)粒度權(quán)限攔截的問題,在Struts2中可以根據(jù)登錄用戶所具有的的權(quán)限進(jìn)行任一一個(gè)action方法的攔截,可以定義一個(gè)自定義方法注解,例如
@Retention(RetentionPolicy.RUNTIME)//代表Permission注解保留在的階段
@Target(ElementType.METHOD)//標(biāo)注在方法上面
public @interface Permission {
/** 模塊 */
String module();
/** 權(quán)限值 */
String privilege();
}
3、2 比如有一個(gè)部門action,Department.action,有一個(gè)方法public String departmentlistUI(){}可以這樣定義方法
@Permission(module="department",privilege="view")
public String departmentlistUI(){
}
3.3、然后自定定義一個(gè)權(quán)限攔截器PrivilegeInterceptor.java并在struts.xml中注冊(cè),在實(shí)現(xiàn)interceptor接口后,實(shí)現(xiàn)方法public String intercept(ActionInvocation invocation) throws Exception {},在這里調(diào)用任一個(gè)action方法都會(huì)經(jīng)過該攔截方法,通過invocation可以獲取當(dāng)前調(diào)用的action的名字,以及調(diào)用的action的哪個(gè)方法,通過這段代碼可以獲取action名字和方法名。
String actionName=invocation.getProxy().getActionName();
String methodName=invocation.getProxy().getMethod();
System.out.println("攔截到:action的名字:"+actionName+"方法名:"+methodName);
4、然后通過反射技術(shù),獲取該方法上的自定義權(quán)限注解,獲取當(dāng)前登錄的用戶(從session中),遍歷當(dāng)前用戶的所擁有的權(quán)限組,并且遍歷任一個(gè)權(quán)限組下的所有的權(quán)限,看是否包括該方法上注解所需的權(quán)限。這樣就可以完成細(xì)粒度的action方法權(quán)限攔截了。
private boolean validate(ActionInvocation invocation) throws SecurityException, NoSuchMethodException {
String methodName=invocation.getProxy().getMethod();
Method currentMethod = invocation.getAction().getClass().getMethod(methodName);
if(currentMethod != null && currentMethod.isAnnotationPresent(Permission.class)){
//得到方法上的注解
Permission permission = currentMethod.getAnnotation(Permission.class);
//該方法上的所需要的權(quán)限
SystemPrivilege methodPrivilege = new SystemPrivilege(new SystemPrivilegePK(permission.module(), permission.privilege()));
//得到當(dāng)前登錄的用戶
Employee e = (Employee) ActionContext.getContext().getSession().get("loginUser");
//遍歷當(dāng)前用戶下的所有的權(quán)限組
for(PrivilegeGroup group : e.getGroups()){
//如果該權(quán)限組下包含,要訪問該方法所需要的權(quán)限,就放行
if(group.getPrivileges().contains(methodPrivilege)){
return true;
}
}
//說明遍歷的該用戶所有的權(quán)限組,沒有發(fā)現(xiàn)該權(quán)限,說明沒有該權(quán)限
return false;
}
//沒有標(biāo)注注解,表示誰都可以調(diào)用該方法
return true;
}
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
Spring AOP里的靜態(tài)代理和動(dòng)態(tài)代理用法詳解
這篇文章主要介紹了 Spring AOP里的靜態(tài)代理和動(dòng)態(tài)代理用法詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
淺談Java自定義注解和運(yùn)行時(shí)靠反射獲取注解
下面小編就為大家?guī)硪黄獪\談Java自定義注解和運(yùn)行時(shí)靠反射獲取注解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11
SpringBoot對(duì)接小程序微信支付的實(shí)現(xiàn)
本文主要介紹了SpringBoot對(duì)接小程序微信支付的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧<BR>2023-09-09
使用Java根據(jù)文件路徑下載zip文件到本地代碼示例
在開發(fā)過程中我們會(huì)遇到需要對(duì)文件進(jìn)行壓縮并下載的功能需求,這篇文章主要給大家介紹了關(guān)于如何使用Java根據(jù)文件路徑下載zip文件到本地的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-03-03
Java基礎(chǔ)教程之對(duì)象的方法與數(shù)據(jù)成員
這篇文章主要介紹了Java基礎(chǔ)教程之對(duì)象的方法與數(shù)據(jù)成員,本文講解對(duì)象的方法與數(shù)據(jù)成員相關(guān)知識(shí),因?yàn)閖ava是面向?qū)ο笳Z言,本文的知識(shí)都是經(jīng)常要用到的,需要的朋友可以參考下2014-08-08
Spring Boot使用Thymeleaf + Gradle構(gòu)建war到Tomcat
今天小編就為大家分享一篇關(guān)于Spring Boot使用Thymeleaf + Gradle構(gòu)建war到Tomcat,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12

