一、注解(Annotation)
1祟滴、什么是注解
jdk1.5后出的特性。代碼的說明歌溉,是一個元數(shù)據(jù)。
注解在 Java 中以“@注解名”的形式呈現(xiàn)骑晶。
2痛垛、 Java 內置的常用注解
@Override : 用于注解方法,說明該方法是重寫方法
@SuppressWarnings : 用于抑制編譯器警告
@Deprecated : 用于注解屬性桶蛔、方法匙头、類。 說明已經過時過期
@FunctionalInterface : jdk1.8 用于注解接口仔雷,說明該接口是一個函數(shù)式接口
二蹂析、元注解:
元數(shù)據(jù):裝載數(shù)據(jù)的的數(shù)據(jù) String name = "atguigu";
元注解:定義注解的注解
1、java.lang.annotation提供了四種元注解:
@Retention –什么時候使用該注解
@Target –注解用于什么地方
@Documented –修飾的注解可以隨之生成說明文檔碟婆,注解的生命周期必須是 RUNTIME
@Inherited – 是否允許子類繼承該注解
2电抚、元注解使用說明
1.)@Retention– 定義該注解的生命周期
● RetentionPolicy.SOURCE : 在編譯階段丟棄。這些注解在編譯結束之后就不再有任何意義竖共,所以它們不會寫入字節(jié)碼蝙叛。@Override, @SuppressWarnings都屬于這類注解。
● RetentionPolicy.CLASS : 在類加載的時候丟棄公给。在字節(jié)碼文件的處理中有用借帘。注解默認使用這種方式
● RetentionPolicy.RUNTIME : 始終不會丟棄,運行期也保留該注解淌铐,因此可以使用反射機制讀取該注解的信息肺然。
2.)Target – 表示該注解用于什么地方。默認值為任何元素腿准,ElementType參數(shù)包括
● ElementType.CONSTRUCTOR:用于描述構造器
● ElementType.FIELD:成員變量际起、對象、屬性(包括enum實例)
● ElementType.LOCAL_VARIABLE:用于描述局部變量
● ElementType.METHOD:用于描述方法
● ElementType.PACKAGE:用于描述包
● ElementType.PARAMETER:用于描述方法參數(shù)
● ElementType.TYPE:用于描述類释涛、接口(包括注解類型) 或enum聲明
ElementType.ANNOTATION_TYPE :用于描述注解
3.)@Documented–一個簡單的Annotations標記注解加叁,表示是否將注解信息添加在java文檔中。
4.)@Inherited – 定義該注釋和子類的關系
@Inherited 元注解是一個標記注解唇撬,@Inherited闡述了某個被標注的類型是被繼承的它匕。
三、自定義注解:
1窖认、規(guī)則:
1. Annotation的類型為@interface,
所有的Annotation會自動繼承java.lang.Annotation這一接口,并且不能再去繼承別的類或是接口.
2. 參數(shù)成員只能用public或默認(default)這兩個訪問權修飾
3. 參數(shù)成員只能用基本類型byte,short,char,int,long,float,double,boolean八種基本數(shù)據(jù)類型和String豫柬、Enum告希、Class、annotations等數(shù)據(jù)類型,以及這些類型的數(shù)組.
2烧给、格式
package com.dodou.liwh.annotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@Documented
public @interface AppleName {
String name() default "";//default 表示參數(shù)的默認值
String value() default "";//value()是默認方法燕偶,調用時可以不寫
}
四、注解的使用:調用是方法——結果是值
注解本質是一個繼承了Annotation的特殊接口础嫡,其具體實現(xiàn)類是Java運行時生成的動態(tài)代理類指么。而我們通過反射獲取注解時,返回的是Java運行時生成的動態(tài)代理對象$Proxy1榴鼎。通過代理對象調用自定義注解(接口)的方法伯诬,會最終調用AnnotationInvocationHandler的invoke方法。該方法會從memberValues這個Map中索引出對應的值巫财。而memberValues的來源是Java常量池盗似。
1)使用反射獲取到注解,拿到注解的數(shù)據(jù)
aop的JoinPoint也可拿到平项,原理就是java的反射機制
2)結合aop赫舒,作為aop的切入點規(guī)則
package com.dodou.liwh.annotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@Documented
public @interface AppleName {
String name() default "";//default 表示參數(shù)的默認值
String value() default "";//value()是默認方法,調用時可以不寫
}
package com.dodou.liwh.annotation;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configurable
@ComponentScan("com.dodou.liwh.annotation")
@EnableAspectJAutoProxy
public class AopConfig {
}
package com.dodou.liwh.annotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Component
@Aspect
public class LogAspect {
//定義切入點的方法闽瓢,一次書寫切入規(guī)則接癌,處處引用
//這里的規(guī)則:標注了@annotation(com.dodou.liwh.annotation.AppleName) 這個注解的
@Pointcut("@annotation(com.dodou.liwh.annotation.AppleName)")
public void pointCut() {
}
//引用切入點方法
@After("pointCut()")
public void after(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
//使用方法上的注解
AppleName annotation = method.getAnnotation(AppleName.class);
System.out.println("注解式攔截:調用自定義注解:" + annotation.name());
}
//自己寫切入點表達式
@Before("execution(* com.dodou.liwh.annotation.MethodAction.*(..))")
public void before(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
System.out.println("切入點表達式攔截:" + method.getName() + ":apple");
}
}
package com.dodou.liwh.annotation;
import org.springframework.stereotype.Service;
@Service
public class AnnotationAction {
//使用了@AppleName注解,滿足aop切入點方法:進行切入
@AppleName(name = "我吃蘋果")
public void eat() {
//被切入的方法
}
}
package com.dodou.liwh.annotation;
import org.springframework.stereotype.Service;
@Service
public class MethodAction {
public void eat() {
//被切入的方法
}
}
package com.dodou.liwh.annotation;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);
//已標注@AppleName的類
AnnotationAction annotationAction = (AnnotationAction) context.getBean("annotationAction");
annotationAction.eat();
//未標注@AppleName的類
MethodAction methodAction = (MethodAction) context.getBean("methodAction");
methodAction.eat();
}
}
3)執(zhí)行結果