SpringBoot自定義注解開(kāi)發(fā)指南
一、Java注解(Annotation)
含義:Java注解是附加在代碼中的一些元信息,用于一些工具在編譯、 運(yùn)行時(shí)進(jìn)行解析和使用,起到說(shuō)明、配置的功能。
1、JDK基本注解
@Override ——》重寫(xiě)
@Deprecated ——》已過(guò)時(shí)
@SuppressWarnings(value = "unchecked") ——》壓制編輯器警告
2、JDK元注解
含義:元注解用于修飾其他的注解(紀(jì)委:管干部的干部)
①、@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) ——》接口、類(lèi)
@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}),也就是此注解可以在方法和類(lèi)上面使用
③、@Inherited:指定被修飾的Annotation將具有繼承性
④、@Documented:指定被修飾的該Annotation可以被javadoc工具提取成文檔.
二、自定義注解開(kāi)發(fā)
1、含義
使用@interface關(guān)鍵字, 其定義過(guò)程與定義接口非常類(lèi)似, 需要注意的是:
Annotation的成員變量在Annotation定義中是以無(wú)參的方法形式來(lái)聲明的, 其方法名和返回值類(lèi)型定義了該成員變量的名字和類(lèi)型, 而且我們還可以使用default關(guān)鍵字為這個(gè)成員變量設(shè)定默認(rèn)值
2、演示
①、枚舉類(lèi):enum,指的是常量的集合
②、注解類(lèi)
Ⅰ、演示@Retention(RetentionPolicy.SOURCE)注解:MyAnnotation.java
package com.lv.annotation;
import org.springframework.beans.factory.annotation.Autowired;
import java.lang.annotation.*;
/**
* @author T440s
*/
//生成一個(gè)注釋
@Documented
//表示當(dāng)前注解可以打在什么東西上面,此處可以放在類(lèi)上與方法上
@Target({ElementType.TYPE,ElementType.METHOD})
//指定被修飾的Annotation將具有繼承性
@Inherited
//注解僅存在于源碼中,在class字節(jié)碼文件中不包含
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation {
String value() default "";
}TestController.java:注意這引用了MyAnnotation注解
package com.lv.controller;
import com.lv.annotation.MyAnnotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@MyAnnotation
@Controller
public class TestController {
@Autowired
private String name;
@MyAnnotation
public void aa(){
}
}運(yùn)行后target層注解消失:注解僅存在于源碼中,在class字節(jié)碼文件中不包含

Ⅱ、MyAnnotation注解為@Retention(RetentionPolicy.RUNTIME)時(shí)
——注解會(huì)在class字節(jié)碼文件中存在,在運(yùn)行時(shí)可以通過(guò)反射獲取到
運(yùn)行test.java:
package com.lv.controller;
import java.lang.annotation.Annotation;
public class Test {
public static void main(String[] args) {
// 反射
for(Annotation a:TestController.class.getAnnotations()){
System.out.println(a);
}
}
}
Ⅲ、取注解里的屬性值
注解:MyAnnotation.java
String message() default "aaa";
拿值:
package com.lv.controller;
import com.lv.annotation.MyAnnotation;
import java.lang.annotation.Annotation;
public class Test {
public static void main(String[] args) {
// 反射
for(Annotation a:TestController.class.getAnnotations()){
if(a instanceof MyAnnotation){
System.out.println(((MyAnnotation) a).message());
}
}
}
}
Ⅳ、判斷在該類(lèi)有無(wú)該注解
測(cè)試:
package com.lv.controller;
import com.lv.annotation.MyAnnotation;
import java.lang.annotation.Annotation;
public class Test {
public static void main(String[] args) {
// 直接將MyAnnotation這注解取出
MyAnnotation myAnnotation=TestController.class.getAnnotation(MyAnnotation.class);
if(myAnnotation !=null){
System.out.println(myAnnotation.message());
}
}
}
三、完成切面日志操作
當(dāng)我們?cè)趯?xiě)增刪改的時(shí)候,會(huì)有很多冗余的代碼,后期修改很麻煩,如:
@RequestMapping("/add")
public String add(){
System.out.println("xxx在增加");
System.out.println("增加成功");
return "yes";
}我們就可以定義aop面向切面,將前面那部分放入前置通知,后面一部分后置通知
新建切面:LogAop.java
package com.lv.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
//類(lèi)不被識(shí)別,將類(lèi)變成一個(gè)組件
@Component
@Slf4j
public class LogAop {
// 指定切入的規(guī)則,".."代表可有參可無(wú)參
@Pointcut("execution(* com.lv.controller.*Controller.*(..))")
public void logger(){}
// 環(huán)繞通知
@Around("logger()")
public Object around(ProceedingJoinPoint point){
// 獲得方法名稱(chēng)
Signature methodName=point.getSignature();
// 日志輸出
log.info(methodName+"進(jìn)來(lái)了");
Long l1=System.currentTimeMillis();
// 讓方法執(zhí)行
Object obj=null;
try {
obj=point.proceed(point.getArgs());
} catch (Throwable throwable) {
throwable.printStackTrace();
}
log.info(methodName+"走了"+"\t耗時(shí)"+(System.currentTimeMillis()-l1));
return obj;
}
}使用jrebel運(yùn)行:
package com.lv.controller;
import com.lv.annotation.MyAnnotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@MyAnnotation
//直接返回json數(shù)據(jù)
@RestController
//返回頁(yè)面跳轉(zhuǎn)數(shù)據(jù)
//@Controller
public class TestController {
@RequestMapping("/add")
public String add(){
return "yes";
}
@RequestMapping("/del")
public String del(){
return "yes";
}
@RequestMapping("/upd")
public String upd(){
return "yes";
}
@RequestMapping("/list")
public String list(){
return "yes";
}
}
使用注解來(lái)開(kāi)發(fā)aop日志:
新建注解類(lèi):MyLog.java
package com.lv.annotation;
import java.lang.annotation.*;
@Inherited
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
}同樣在切面類(lèi)中,記得改變切入的規(guī)則
@Pointcut("@annotation(com.lv.annotation.MyLog)")
需要輸出日志的方法就將新建的注解加上

四、完成前端響應(yīng)反應(yīng)
傳入四個(gè)文件:
ResponseParse.java:
package com.lv.response;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* @author hgh
*/
//響應(yīng)增強(qiáng)類(lèi)
@RestControllerAdvice
public class ResponseParse implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
//返回值決定他是否需要進(jìn)入beforeBodyWrite
return methodParameter.getMethod().isAnnotationPresent(ResponseResult.class);
}
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
//更改返回值
if (o == null) {
return Result.success();
}
if (o instanceof Integer) {
return Result.failure(ResultCode.queryCode((Integer) o));
}
if (o instanceof ResultCode) {
return Result.failure((ResultCode) o);
}
if (o instanceof Result) {
return o;
}
return null;
}
}ResponseResult.java:
package com.lv.response;
import java.lang.annotation.*;
/**
* @author hgh
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
@Target({ElementType.METHOD})
public @interface ResponseResult {
}Result.java:
package com.lv.response;
import lombok.Data;
import java.io.Serializable;
/**
* 響應(yīng)對(duì)象封裝類(lèi)
*
* @author hgh
*/
@Data
public class Result<T> implements Serializable {
private final int code;
private final String message;
private final T data;
/**
* 私有構(gòu)造, 只允許通過(guò)static調(diào)用構(gòu)造
*
* @param resultCode 結(jié)果枚舉
* @param data 響應(yīng)數(shù)據(jù)
*/
private Result(ResultCode resultCode, T data) {
this.code = resultCode.getCode();
this.message = resultCode.getMessage();
this.data = data;
}
/**
* 成功調(diào)用返回的結(jié)果(無(wú)數(shù)據(jù)攜帶)
*
* @return Result
*/
public static Result success() {
return success(null);
}
/**
* 成功調(diào)用返回的結(jié)果(數(shù)據(jù)攜帶)
*
* @return Result
*/
public static <T> Result success(T data) {
return new Result(ResultCode.SUCCESS, data);
}
/**
* 失敗調(diào)用返回的結(jié)果(數(shù)據(jù)攜帶)
*
* @param resultCode 狀態(tài)枚舉
* @param data 攜帶的數(shù)據(jù)
* @return Result
*/
public static <T> Result failure(ResultCode resultCode, T data) {
return new Result(resultCode, data);
}
/**
* 失敗調(diào)用返回的結(jié)果(無(wú)數(shù)據(jù)攜帶)
*
* @param resultCode 狀態(tài)枚舉
* @return Result
*/
public static Result failure(ResultCode resultCode) {
return failure(resultCode, null);
}
}ResultCode.java:
package com.lv.response;
import java.io.Serializable;
/**
* 響應(yīng)結(jié)果碼枚舉
*
* @author hgh
*/
public enum ResultCode implements Serializable {
/* 正常狀態(tài) */
SUCCESS(100, "成功"),
FAILURE(101, "失敗"),
UNKNOWN(102, "未知響應(yīng)"),
/**
* 用戶(hù)code范圍: 200~300;
*/
USER_ACCOUNT_NOT_FIND(201, "用戶(hù)名不存在"),
USER_ACCOUNT_DISABLED(202, "該用戶(hù)已被禁用"),
USER_PASSWORD_NOT_MATCH(203, "該用戶(hù)密碼不一致"),
USER_PERMISSION_ERROR(204, "該用戶(hù)不具備訪(fǎng)問(wèn)權(quán)限"),
USER_STATE_OFF_LINE(205, "該用戶(hù)未登錄");
private final Integer code;
private final String message;
ResultCode(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
public static ResultCode queryCode(Integer code) {
for (ResultCode value : values()) {
if (code.equals(value.code)) {
return value;
}
}
return UNKNOWN;
}
}測(cè)試:
package com.lv.controller;
import com.lv.annotation.MyAnnotation;
import com.lv.annotation.MyLog;
import com.lv.response.ResponseResult;
import com.lv.response.Result;
import com.lv.response.ResultCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@MyAnnotation
//直接返回json數(shù)據(jù)
@RestController
//返回頁(yè)面跳轉(zhuǎn)數(shù)據(jù)
//@Controller
public class TestController {
@MyLog
@ResponseResult
@RequestMapping("/add")
public Result add(){
return Result.success("yes");
}
@RequestMapping("/del")
@ResponseResult
public Object del(){
return 201;
}
@RequestMapping("/upd")
@ResponseResult
public Object upd(){
return ResultCode.USER_ACCOUNT_NOT_FIND;
}
@RequestMapping("/list")
@ResponseResult
public Object list(){
return Result.success("yes");
}
}增加:

刪除:

總結(jié)
到此這篇關(guān)于SpringBoot自定義注解的文章就介紹到這了,更多相關(guān)SpringBoot自定義注解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java控制臺(tái)實(shí)現(xiàn)猜拳游戲小游戲
這篇文章主要為大家詳細(xì)介紹了Java控制臺(tái)實(shí)現(xiàn)猜拳游戲小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11
調(diào)用Process.waitfor導(dǎo)致的進(jìn)程掛起問(wèn)題及解決
這篇文章主要介紹了調(diào)用Process.waitfor導(dǎo)致的進(jìn)程掛起問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Spring?boot?運(yùn)用策略模式實(shí)現(xiàn)避免多次使用if
這篇文章主要介紹了Spring?boot?運(yùn)用策略模式實(shí)現(xiàn)避免多次使用if,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09
spring-kafka使消費(fèi)者動(dòng)態(tài)訂閱新增的topic問(wèn)題
這篇文章主要介紹了spring-kafka使消費(fèi)者動(dòng)態(tài)訂閱新增的topic問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
SpringBoot框架實(shí)現(xiàn)切換啟動(dòng)開(kāi)發(fā)環(huán)境和測(cè)試環(huán)境
這篇文章主要介紹了SpringBoot框架實(shí)現(xiàn)切換啟動(dòng)開(kāi)發(fā)環(huán)境和測(cè)試環(huán)境,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
SpringBoot詳解如何實(shí)現(xiàn)讀寫(xiě)分離
當(dāng)響應(yīng)的瓶頸在數(shù)據(jù)庫(kù)的時(shí)候,就要考慮數(shù)據(jù)庫(kù)的讀寫(xiě)分離,當(dāng)然還可以分庫(kù)分表,那是單表數(shù)據(jù)量特別大,當(dāng)單表數(shù)據(jù)量不是特別大,但是請(qǐng)求量比較大的時(shí)候,就要考慮讀寫(xiě)分離了.具體的話(huà),還是要看自己的業(yè)務(wù)...如果還是很慢,那就要分庫(kù)分表了...我們這篇就簡(jiǎn)單講一下讀寫(xiě)分離2022-05-05
Spring Boot集成Redis實(shí)戰(zhàn)操作功能
這篇文章主要介紹了Spring Boot集成Redis實(shí)戰(zhàn)操作,包括如何集成redis以及redis的一些優(yōu)點(diǎn),本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-11-11
IDEA 2020.2 +Gradle 6.6.1 + Spring Boot 2.3.4 創(chuàng)建多模塊項(xiàng)目的超詳細(xì)教程
這篇文章主要介紹了IDEA 2020.2 +Gradle 6.6.1 + Spring Boot 2.3.4 創(chuàng)建多模塊項(xiàng)目的教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
springboot接口返回?cái)?shù)據(jù)類(lèi)型全面解析
這篇文章主要介紹了springboot接口返回?cái)?shù)據(jù)類(lèi)型問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12

