目錄
一、什么是自定義注解
1)Java注解簡(jiǎn)介
2)Java注解分類
JDK基本注解
JDK元注解
自定義注解
如何自定義注解?
二、自定義注解
1)獲取類上注解值
2)獲取類屬性上的注解屬性值
3)獲取方法上的注解值?
4)獲取參數(shù)修飾注解對(duì)應(yīng)的屬性值
三、aop應(yīng)用自定義注解
自定義注解日志的使用
一、什么是自定義注解
1)Java注解簡(jiǎn)介
Java注解是附加在代碼中的一些元信息,用于一些工具在編譯、運(yùn)行時(shí)進(jìn)行解析和使用,起到說(shuō)明、配置的功能,注解相關(guān)類都包含在java.lang.annotation包中。
2)Java注解分類
JDK基本注解
JDK元注解
自定義注解
JDK基本注解
@Override
重寫
@SuppressWarnings(value = "unchecked")
壓制編輯器警告
JDK元注解
@Retention:定義注解的保留策略
@Retention(RetentionPolicy.SOURCE) //注解僅存在于源碼中,在class字節(jié)碼文件中不包含
@Retention(RetentionPolicy.CLASS) //默認(rèn)的保留策略,注解會(huì)在class字節(jié)碼文件中存在,但運(yùn)行時(shí)無(wú)法獲得,
@Retention(RetentionPolicy.RUNTIME) //注解會(huì)在class字節(jié)碼文件中存在,在運(yùn)行時(shí)可以通過(guò)反射獲取到
@Target:指定被修飾的Annotation可以放置的位置(被修飾的目標(biāo))
@Target(ElementType.TYPE) //接口、類
@Target(ElementType.FIELD) //屬性
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法參數(shù)
@Target(ElementType.CONSTRUCTOR) //構(gòu)造函數(shù)
@Target(ElementType.LOCAL_VARIABLE) //局部變量
@Target(ElementType.ANNOTATION_TYPE) //注解
@Target(ElementType.PACKAGE) //包
注:可以指定多個(gè)位置,例如:
@Target({ElementType.METHOD, ElementType.TYPE}),也就是此注解可以在方法和類上面使用
@Inherited:指定被修飾的Annotation將具有繼承性
@Documented:指定被修飾的該Annotation可以被javadoc工具提取成文檔.
自定義注解
注解分類(根據(jù)Annotation是否包含成員變量,可以把Annotation分為兩類):
標(biāo)記Annotation:
沒(méi)有成員變量的Annotation; 這種Annotation僅利用自身的存在與否來(lái)提供信息
元數(shù)據(jù)Annotation:
包含成員變量的Annotation; 它們可以接受(和提供)更多的元數(shù)據(jù);
如何自定義注解?
使用@interface關(guān)鍵字, 其定義過(guò)程與定義接口非常類似, 需要注意的是:
? ?Annotation的成員變量在Annotation定義中是以無(wú)參的方法形式來(lái)聲明的, 其方法名和返回值類型定義了該成員變量的名字和類型,
? ?而且我們還可以使用default關(guān)鍵字為這個(gè)成員變量設(shè)定默認(rèn)值;
二、自定義注解
常見的自定義注解有四種:注解用在類上面、注解用在方法上面、注解用在屬性上面、注解用在參數(shù)上面
?@Target
?
?@Target里面標(biāo)記的屬性,決定了你自定義注解能放在哪里使用,將METHOD改為TEPY或者使用逗號(hào)分隔在后面添加也行,這樣方法,類,屬性都可以使用這個(gè)注解類了
??
如果不知道該注解是干嘛用的,可以點(diǎn)進(jìn)去查看,Ctrl+鼠標(biāo)鍵?
@Retention一共有三種:source、class、runtime?
如果屬性是value的話,可以省略value=?
1)獲取類上注解值
使用自定義注解就是為了拿這上面的數(shù)據(jù)的?
MyAnnotation1.java?
package com.xiaokun.ssm.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author 小坤
* @create 2022-10-28 20:09
*/
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation1 {
// 指的是注解中的屬性
public String desc() default "desc可以修飾符、方法、屬性";
public String value() default "value可以修飾符、方法、屬性";
}
?MyAnnotation2.java?
package com.xiaokun.ssm.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author 小坤
* @create 2022-10-28 20:09
*/
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation2 {
// 指的是注解中的屬性
public String desc() default "desc可以修飾符、方法、屬性";
public String value() default "value可以修飾符、方法、屬性";
}
Studentcontroller.java
package com.xiaokun.ssm.annotation;
/**
* @author 小坤
* @create 2022-10-28 20:11
*/
@MyAnnotation1(desc = "標(biāo)記在類上面")
public class Studentcontroller {
@MyAnnotation1("標(biāo)記在屬性id上面")
private String id;
@MyAnnotation1("標(biāo)記在屬性name上面")
private String name;
@MyAnnotation1
public void test1(@MyAnnotation2("用來(lái)修飾id參數(shù)") String id,@MyAnnotation2("用來(lái)修飾name參數(shù)") String name){
System.out.println("測(cè)試...");
}
}
Demo1.java
package com.jwj.ssm.annotation.demo;
import com.xiaokun.ssm.annotation.MyAnnotation1;
import com.xiaokun.ssm.annotation.Studentcontroller;
/**
* @author 小坤
* @create 2022-10-28 22:10
*
* 目標(biāo):
* 1.獲取studentController 類上自定義注解 中的內(nèi)容
* 2.獲取studentController 方法上自定義注解 中的內(nèi)容
* 3.獲取studentController 屬性上自定義注解 中的內(nèi)容
* 4.獲取studentController 參數(shù)上自定義注解 中的內(nèi)容
* * *..*Service.*pager(..)
* com.zking.service.BookService.queryPager(..);
* com.zking.service.OrderService.queryPager(..);
*/
public class Demo1 {
public static void main(String[] args) {
// 拿到類、拿注解
MyAnnotation1 annotation = Studentcontroller.class.getAnnotation(MyAnnotation1.class);
System.out.println(annotation.value());
System.out.println(annotation.desc());
}
}
這個(gè)時(shí)候我們運(yùn)行main方法時(shí),程序會(huì)報(bào)錯(cuò),圖中詳講,看圖???
2)獲取類屬性上的注解屬性值
Demo1.java??
package com.xiaokun.ssm.annotation.demo;
import com.xiaokun.ssm.annotation.MyAnnotation1;
import com.xiaokun.ssm.annotation.MyAnnotation2;
import com.xiaokun.ssm.annotation.Studentcontroller;
import java.lang.reflect.Field;
/**
* @author 小坤
* @create 2022-10-28 22:10
*
* 目標(biāo):
* 1.獲取studentController 類上自定義注解 中的內(nèi)容
* 2.獲取studentController 方法上自定義注解 中的內(nèi)容
* 3.獲取studentController 屬性上自定義注解 中的內(nèi)容
* 4.獲取studentController 參數(shù)上自定義注解 中的內(nèi)容
* * *..*Service.*pager(..)
* com.zking.service.BookService.queryPager(..);
* com.zking.service.OrderService.queryPager(..);
*/
public class Demo1 {
public static void main(String[] args) throws NoSuchFieldException {
// 拿到類、拿注解
MyAnnotation1 annotation = Studentcontroller.class.getAnnotation(MyAnnotation1.class);
System.out.println(annotation.value());
System.out.println(annotation.desc());
// 獲取屬性上的
Field id = Studentcontroller.class.getDeclaredField("id");
Field name = Studentcontroller.class.getDeclaredField("name");
System.out.println(id.getAnnotation(MyAnnotation1.class).value());
System.out.println(name.getAnnotation(MyAnnotation1.class).value());
}
}
運(yùn)行結(jié)果如圖:
3)獲取方法上的注解值?
// ? ? ? ?獲取到方法上的
? ? ? ? Method m1 = Studentcontroller.class.getDeclaredMethod("test1", String.class, String.class);
? ? ? ? System.out.println(m1.getAnnotation(MyAnnotation1.class).value());
4)獲取參數(shù)修飾注解對(duì)應(yīng)的屬性值
// 獲取參數(shù)上的標(biāo)識(shí)
for (Parameter p : m1.getParameters()) {
System.out.println(p.getAnnotation(MyAnnotation2.class).value());
}
三、aop應(yīng)用自定義注解
在做一個(gè)系統(tǒng)中,有時(shí)需要記錄操作日志,方便找到某個(gè)操作是誰(shuí)進(jìn)行的,這個(gè)可以用spring的aop來(lái)實(shí)現(xiàn),本篇博客記錄用自定義注解+aop應(yīng)用于springboot項(xiàng)目中實(shí)現(xiàn)操作日志的記錄
aop相關(guān)術(shù)語(yǔ)介紹
- 連接點(diǎn)(Joinpoint): 程序執(zhí)行的某個(gè)特定位置,如某個(gè)方法調(diào)用前,調(diào)用后,方法拋出異常后,這些代碼中的特定點(diǎn)稱為連接點(diǎn);簡(jiǎn)單來(lái)說(shuō),就是在哪加入你的邏輯增強(qiáng),連接點(diǎn)表示具體要攔截的方法,切點(diǎn)是定義一個(gè)范圍,而連接點(diǎn)是具體到某個(gè)方法
- 切點(diǎn)(PointCut):每個(gè)程序的連接點(diǎn)有多個(gè),如何定位到某個(gè)感興趣的連接點(diǎn),就需要通過(guò)切點(diǎn)來(lái)定位。比如,連接點(diǎn)是數(shù)據(jù)庫(kù)的記錄,切點(diǎn)是查詢條件;切點(diǎn)用于來(lái)限定Spring-AOP啟動(dòng)的范圍,通常我們采用表達(dá)式的方式來(lái)設(shè)置,所以關(guān)鍵詞是范圍
- 增強(qiáng)(Advice):增強(qiáng)是織入到目標(biāo)類連接點(diǎn)上的一段程序代碼;在Spring中,像BeforeAdvice等還帶有方位信息;通知是直譯過(guò)來(lái)的結(jié)果,我個(gè)人感覺叫做“業(yè)務(wù)增強(qiáng)”更合適,對(duì)照代碼就是攔截器定義的相關(guān)方法,通知分為如下幾種:
- 前置通知(before):在執(zhí)行業(yè)務(wù)代碼前做些操作,比如獲取連接對(duì)象
- 后置通知(after):在執(zhí)行業(yè)務(wù)代碼后做些操作,無(wú)論是否發(fā)生異常,它都會(huì)執(zhí)行,比如關(guān)閉連接對(duì)象
- 異常通知(afterThrowing):在執(zhí)行業(yè)務(wù)代碼后出現(xiàn)異常,需要做的操作,比如回滾事務(wù)
- 返回通知(afterReturning):在執(zhí)行業(yè)務(wù)代碼后無(wú)異常,會(huì)執(zhí)行的操作
-
環(huán)繞通知(around):環(huán)繞通知可以在方法調(diào)用前后完成自定義的行為,它也會(huì)選擇是否繼續(xù)執(zhí)行連接點(diǎn)或直接返回它們自己的返回值或拋出異常來(lái)結(jié)束執(zhí)行
?
目標(biāo)對(duì)象(Target):需要被加強(qiáng)的業(yè)務(wù)對(duì)象
織入(Weaving):織入就是將增強(qiáng)添加到對(duì)目標(biāo)類具體連接點(diǎn)上的過(guò)程;織入是一個(gè)形象的說(shuō)法,具體來(lái)說(shuō),就是生成代理對(duì)象并將切面內(nèi)容融入到業(yè)務(wù)流程的過(guò)程。
代理類(Proxy):一個(gè)類被AOP織入增強(qiáng)后,就產(chǎn)生了一個(gè)代理類
切面(Aspect):切面由切點(diǎn)和增強(qiáng)組成,它既包括了橫切邏輯的定義,也包括了連接點(diǎn)的定義,SpringAOP就是將切面所定義的橫切邏輯織入到切面所制定的連接點(diǎn)中。SpringAOP將切面定義的內(nèi)容織入到我們的代碼中,從而實(shí)現(xiàn)前后的控制邏輯。 比如我們常寫的攔截器Interceptor,就是一個(gè)切面類
自定義注解日志的使用
DemoController.java
package com.xiaokun.ssm.annotation.aop;
import org.springframework.stereotype.Controller;
/**
* @author 小坤
* @create 2022-10-29 14:19
*/
@Controller
public class DemoController {
@MyLog(desc = "這是一個(gè)測(cè)試類的方法")
public void test(){
System.out.println("測(cè)試方法");
}
}
MyLog.java
package com.xiaokun.ssm.annotation.aop;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
String desc();
}
MyLogAspect?.java
package com.xiaokun.ssm.annotation.aop;
import org.aspectj.lang.JoinPoint;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MyLogAspect {
private static final Logger logger = LoggerFactory.getLogger(MyLogAspect.class);
/**
* 只要用到了com.javaxl.p2.annotation.springAop.MyLog這個(gè)注解的,就是目標(biāo)類
*/
@Pointcut("@annotation(com.jwj.ssm.annotation.aop.MyLog)")
// 這是以前的寫法 @Around("execution"(* *..*Service.*Pager(..))")
// 上面這個(gè)已經(jīng)把這個(gè)替代掉了 @Pointcut("@execution(* *.*Controller.add())")
private void MyValid() {
}
@Before("MyValid()")
public void before(JoinPoint joinPoint) {
// joinPoint
// 目標(biāo)對(duì)象、目標(biāo)方法、傳遞的參數(shù)
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
logger.debug("[" + signature.getName() + " : start.....]");
System.out.println("[" + signature.getName() + " : start.....]");
MyLog myLog = signature.getMethod().getAnnotation(MyLog.class);
logger.debug("【目標(biāo)對(duì)象方法被調(diào)用時(shí)候產(chǎn)生的日志,記錄到日志表中】:"+myLog.desc());
System.out.println("【目標(biāo)對(duì)象方法被調(diào)用時(shí)候產(chǎn)生的日志,記錄到日志表中】:" + myLog.desc());
}
}
?添加測(cè)試方法
AnnotationTest.java文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-826083.html
package com.xiaokun.shiro;
import com.xiaokun.ssm.annotation.aop.DemoController;
import com.xiaokun.ssm.biz.ClazzBiz;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author 小坤
* @create 2022-10-27 22:21
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:applicationContext.xml"})
public class AnnotationTest {
@Autowired
private DemoController demoController;
@Test
public void test1(){
demoController.test();
}
}
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-826083.html
到了這里,關(guān)于Java自定義注解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!