目錄
一、SpringMVC之自定義注解
1.1 Java注解簡介
1.2 為什么要用注解
1.3 注解的分類 ?
1.3.1 JDK基本注解
1.3.2 JDK元注解?
1.3.3 自定義注解?
1.4 自定義注解三種使用案例
1.4.1?案例一(獲取類與方法上的注解值)
1.4.2?案例二(獲取類屬性上的注解屬性值)
1.4.3 案例三(獲取參數(shù)修飾注解對應(yīng)的屬性值)
二、Aop自定義注解的應(yīng)用 ?
2.1 自定義注解類
2.2?切面類
2.3?Controller層代碼
2.4 測試
一、SpringMVC之自定義注解
1.1 Java注解簡介
????????注解(Annotation)是Java語言的一種元數(shù)據(jù)(metadata)機制,它提供了一種在代碼中添加額外信息的方式。注解可以用于標記代碼的特定元素,如類、方法、字段、參數(shù)等,以便在編譯時、運行時或者通過工具進行處理。
注解相關(guān)類都包含在java.lang.annotation包中。
1.2 為什么要用注解
使用注解的主要目的是為了提供更多的元數(shù)據(jù)信息,以便在編譯時或運行時進行處理。注解可以用于以下幾個方面:
-
編譯時處理:注解可以在編譯時被編譯器識別和處理。通過在代碼中添加注解,我們可以告訴編譯器執(zhí)行特定的操作,如生成額外的代碼、進行靜態(tài)檢查、生成文檔等。例如,JUnit框架中的@Test注解用于標記測試方法,在編譯時會被JUnit運行器識別并執(zhí)行相應(yīng)的測試。
-
運行時處理:注解可以在程序運行時通過反射機制被讀取和處理。通過讀取注解,我們可以獲取代碼中的元數(shù)據(jù)信息,并根據(jù)注解的定義執(zhí)行相應(yīng)的邏輯。例如,Spring框架中的@Autowired注解用于自動注入依賴,通過讀取注解,Spring容器可以自動將依賴注入到相應(yīng)的對象中。
-
工具處理:注解可以被工具讀取和處理,以實現(xiàn)特定的功能。例如,JavaDoc工具可以讀取代碼中的注解,并生成相應(yīng)的文檔。其他工具,如代碼生成器、靜態(tài)分析工具等,也可以利用注解來實現(xiàn)特定的功能。
使用注解的好處包括:
-
提供更多的元數(shù)據(jù)信息:注解可以為代碼添加額外的元數(shù)據(jù)信息,使得代碼更加豐富和可讀。通過注解,我們可以標記代碼的特定含義、行為和規(guī)則,提高代碼的可理解性和可維護性。
-
簡化開發(fā)流程:注解可以簡化開發(fā)流程,減少重復(fù)的代碼和配置。通過使用注解,我們可以自動化一些常見的任務(wù),如依賴注入、配置解析、路由映射等,提高開發(fā)效率。
-
增強代碼的可靠性和安全性:注解可以用于進行靜態(tài)檢查和約束,以確保代碼的正確性和安全性。通過在代碼中添加注解,我們可以在編譯時或運行時進行驗證,避免一些常見的錯誤和問題。
????????總之,注解是一種強大的元數(shù)據(jù)機制,它可以為代碼添加額外的信息和行為,提高代碼的可讀性、可維護性和可靠性。通過使用注解,我們可以簡化開發(fā)流程,提高開發(fā)效率,并實現(xiàn)更靈活和可擴展的功能。
1.3 注解的分類 ?
1.3.1 JDK基本注解
????????JDK基本注解是Java開發(fā)工具包(JDK)中提供的一組預(yù)定義注解,用于標記代碼的特定元素。這些注解包括:
-
@Override:用于標記方法覆蓋(重寫)父類中的方法。當(dāng)一個方法使用了該注解時,編譯器會檢查該方法是否正確地覆蓋了父類中的方法。
-
@Deprecated:用于標記已過時的方法、類或字段。當(dāng)一個方法或類被標記為過時時,編譯器會發(fā)出警告,提醒開發(fā)者不再推薦使用該方法或類。
-
@SuppressWarnings:用于抑制編譯器產(chǎn)生的警告信息。可以在方法、類或整個代碼塊上使用該注解,以忽略特定類型的警告。
1.3.2 JDK元注解?
????????JDK元注解是用于注解其他注解的注解,它們提供了更多的元數(shù)據(jù)和行為來定義注解的行為。JDK中提供了四個元注解:
-
@Retention:用于指定注解的生命周期??梢栽O(shè)置為SOURCE(只在源代碼中可見)、CLASS(在編譯時可見)或RUNTIME(在運行時可見)。
-
@Target:用于指定注解可以應(yīng)用的目標元素類型??梢栽O(shè)置為TYPE(類、接口、枚舉)、METHOD(方法)、FIELD(字段)等。
-
@Documented:用于指定注解是否包含在Java文檔中。如果一個注解被@Documented注解修飾,那么它的信息將包含在生成的文檔中。
-
@Inherited:用于指定注解是否可以被繼承。如果一個注解被@Inherited注解修飾,那么它的子類將自動繼承該注解(不常用)。
@Target:指定被修飾的Annotation可以放置的位置(被修飾的目標)
@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)? ? //包
注:可以指定多個位置,例如:
@Target({ElementType.METHOD, ElementType.TYPE}),也就是此注解可以在方法和類上面使用?
1.3.3 自定義注解?
????????自定義注解是開發(fā)者根據(jù)自己的需求創(chuàng)建的注解。通過自定義注解,開發(fā)者可以為代碼添加特定的元數(shù)據(jù)信息,并定義相應(yīng)的處理邏輯。自定義注解的創(chuàng)建步驟包括:
- 使用@interface關(guān)鍵字定義一個注解類型。
- 在注解中定義需要的元素,可以包括基本類型、枚舉類型、Class類型、注解類型等。
- 使用元注解對注解進行修飾,例如@Retention、@Target等,以定義注解的生命周期和使用范圍。
- 在代碼中使用自定義注解,可以通過反射獲取注解的元素值,并根據(jù)注解的定義進行相應(yīng)的處理。
要創(chuàng)建一個自定義注解,你需要使用Java的注解機制。下面是一個簡單的示例,展示了如何創(chuàng)建一個自定義注解:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface CustomAnnotation { // 在這里定義注解的屬性 String value(); }
在上面的示例中,我們創(chuàng)建了一個名為
CustomAnnotation
的注解。它有一個屬性value
,可以用來傳遞一些自定義的信息。
????????通過自定義注解,開發(fā)者可以實現(xiàn)更靈活和可擴展的功能,如自定義驗證規(guī)則、日志記錄、權(quán)限控制等。自定義注解可以在類、方法、字段、參數(shù)等級別上使用,以滿足不同的需求。
1.4 自定義注解三種使用案例
注解(根據(jù)Annotation是否包含成員變量,可以把Annotation分為兩類):
1. 標記注解(Marker Annotation):這種注解沒有成員變量,它們僅通過自身的存在與否來提供信息。
例如:Java中的@Override注解就是一個標記注解,用于標記方法覆蓋(重寫)父類中的方法。
2. 元數(shù)據(jù)注解(Meta Annotation):這種注解包含成員變量,它們可以接受和提供更多的元數(shù)據(jù)信息。元數(shù)據(jù)注解除了標記代碼的特定元素外,還可以攜帶額外的數(shù)據(jù)或參數(shù)。通過元數(shù)據(jù)注解,我們可以為代碼添加更多的元數(shù)據(jù)信息,以便在編譯時、運行時或者通過工具進行處理。元數(shù)據(jù)注解可以用于配置、約束、驗證等方面。
例如:Spring框架中的@RequestMapping注解就是一個元數(shù)據(jù)注解,它不僅可以標記請求處理方法,還可以指定請求的URL路徑、請求方法、請求參數(shù)等。
1.4.1?案例一(獲取類與方法上的注解值)
1. 定義一個枚舉類:用來表示一組固定的值。
package com.ycxw.model;
public enum TranscationModel {
Read, Write, ReadWrite
}
2. 定義三個不同注解方式的類:
MyAnnotation1 :??
package com.ycxw.annotation;
import java.lang.annotation.*;
/**
* MyAnnotation1注解可以用在類、接口、屬性、方法上
* 注解運行期也保留
* 不可繼承
*/
@Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation1 {
String name();
}
MyAnnotation2?:??
package com.ycxw.annotation;
import com.ycxw.model.TranscationModel;
import java.lang.annotation.*;
/**
* MyAnnotation2注解可以用在方法上
* 注解運行期也保留
* 不可繼承
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation2 {
TranscationModel model() default TranscationModel.ReadWrite;
}
MyAnnotation3?:??
package com.ycxw.annotation;
import com.ycxw.model.TranscationModel;
import java.lang.annotation.*;
/**
* MyAnnotation3注解可以用在方法上
* 注解運行期也保留
* 可繼承
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation3 {
TranscationModel[] models() default TranscationModel.ReadWrite;
}
?Demo1測試類 :?獲取類與方法上的注解值
package com.ycxw.annotation.demo;
import com.ycxw.annotation.MyAnnotation1;
import com.ycxw.annotation.MyAnnotation2;
import com.ycxw.annotation.MyAnnotation3;
import com.ycxw.model.TranscationModel;
/**
* 獲取類與方法上的注解值
*/
@MyAnnotation1(name = "abc")
public class Demo1 {
@MyAnnotation1(name = "xyz")
private Integer age;
@MyAnnotation2(model = TranscationModel.Read)
public void list() {
System.out.println("list");
}
@MyAnnotation3(models = {TranscationModel.Read, TranscationModel.Write})
public void edit() {
System.out.println("edit");
}
}
?Demo1Test測試類:
package com.ycxw.annotation.demo;
import com.ycxw.annotation.MyAnnotation1;
import com.ycxw.annotation.MyAnnotation2;
import com.ycxw.annotation.MyAnnotation3;
import com.ycxw.model.TranscationModel;
import org.junit.Test;
public class Demo1Test {
@Test
public void list() throws Exception {
// 獲取類上的注解
MyAnnotation1 annotation1 = Demo1.class.getAnnotation(MyAnnotation1.class);
System.out.println(annotation1.name());//abc
// 獲取方法上的注解
MyAnnotation2 myAnnotation2 = Demo1.class.getMethod("list").getAnnotation(MyAnnotation2.class);
System.out.println(myAnnotation2.model());//Read
// 獲取屬性上的注解
MyAnnotation1 myAnnotation1 = Demo1.class.getDeclaredField("age").getAnnotation(MyAnnotation1.class);
System.out.println(myAnnotation1.name());// xyz
}
@Test
public void edit() throws Exception {
MyAnnotation3 myAnnotation3 = Demo1.class.getMethod("edit").getAnnotation(MyAnnotation3.class);
for (TranscationModel model : myAnnotation3.models()) {
System.out.println(model);//Read,Write
}
}
}
運行l(wèi)ist方法結(jié)果:
運行edit方法結(jié)果:
1.4.2?案例二(獲取類屬性上的注解屬性值)
1. 自定義注解類:
package com.ycxw.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//@Retention(RetentionPolicy.SOURCE)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TestAnnotation {
String value() default "默認value值";
String what() default "這里是默認的what屬性對應(yīng)的值";
}
2. 定義測試類:獲取類屬性上的注解屬性值
package com.ycxw.annotation.demo2;
import com.ycxw.annotation.TestAnnotation;
/**
* 獲取類屬性上的注解屬性值
*/
public class Demo2 {
@TestAnnotation(value = "這就是value對應(yīng)的值_msg1", what = "這就是what對應(yīng)的值_msg1")
private static String msg1;
@TestAnnotation("這就是value對應(yīng)的值1")
private static String msg2;
@TestAnnotation(value = "這就是value對應(yīng)的值2")
private static String msg3;
@TestAnnotation(what = "這就是what對應(yīng)的值")
private static String msg4;
}
?3. 測試
package com.ycxw.annotation.demo2;
import com.ycxw.annotation.TestAnnotation;
import org.junit.Test;
public class Demo2Test {
@Test
public void test1() throws Exception {
TestAnnotation msg1 = Demo2.class.getDeclaredField("msg1").getAnnotation(TestAnnotation.class);
System.out.println(msg1.value());
System.out.println(msg1.what());
}
@Test
public void test2() throws Exception{
TestAnnotation msg2 = Demo2.class.getDeclaredField("msg2").getAnnotation(TestAnnotation.class);
System.out.println(msg2.value());
System.out.println(msg2.what());
}
@Test
public void test3() throws Exception{
TestAnnotation msg3 = Demo2.class.getDeclaredField("msg3").getAnnotation(TestAnnotation.class);
System.out.println(msg3.value());
System.out.println(msg3.what());
}
@Test
public void test4() throws Exception{
TestAnnotation msg4 = Demo2.class.getDeclaredField("msg4").getAnnotation(TestAnnotation.class);
System.out.println(msg4.value());
System.out.println(msg4.what());
}
}
1.4.3 案例三(獲取參數(shù)修飾注解對應(yīng)的屬性值)
1, 創(chuàng)建自定義注解:
package com.ycxw.annotation;
import java.lang.annotation.*;
/**
* 非空注解:使用在方法的參數(shù)上,false表示此參數(shù)可以為空,true不能為空
*/
@Documented
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface IsNotNull {
boolean value() default false;
}
2. 創(chuàng)建測試類:獲取參數(shù)修飾注解對應(yīng)的屬性值
package com.ycxw.annotation.demo3;
import com.ycxw.annotation.IsNotNull;
/**
* 獲取參數(shù)修飾注解對應(yīng)的屬性值
*/
public class Demo3 {
public void hello1(@IsNotNull(true) String name) {
System.out.println("hello:" + name);
}
public void hello2(@IsNotNull String name) {
System.out.println("hello:" + name);
}
}
3. 測試
package com.ycxw.annotation.demo3;
import com.ycxw.annotation.IsNotNull;
import org.junit.Test;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
public class Demo3Test {
@Test
public void hello1() throws Exception {
Demo3 demo3 = new Demo3();
for (Parameter parameter : demo3.getClass().getMethod("hello1", String.class).getParameters()) {
IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
if(annotation != null){
System.out.println(annotation.value());//true
}
}
}
@Test
public void hello2() throws Exception {
Demo3 demo3 = new Demo3();
for (Parameter parameter : demo3.getClass().getMethod("hello2", String.class).getParameters()) {
IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
if(annotation != null){
System.out.println(annotation.value());//false
}
}
}
@Test
public void hello3() throws Exception {
// 模擬瀏覽器傳遞到后臺的參數(shù) 解讀@requestParam
String name = "zs";
Demo3 demo3 = new Demo3();
Method method = demo3.getClass().getMethod("hello1", String.class);
for (Parameter parameter : method.getParameters()) {
IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
if(annotation != null){
System.out.println(annotation.value());//true
if (annotation.value() && !"".equals(name)){
method.invoke(demo3,name);
}
}
}
}
}
?
二、Aop自定義注解的應(yīng)用 ?
2.1 自定義注解類
package com.ycxw.annotation;
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();
}
2.2?切面類
package com.ycxw.aspect;
import com.ycxw.annotation.MyLog;
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這個注解的,就是目標類
*/
@Pointcut("@annotation(com.ycxw.annotation.MyLog)")
private void MyValid() {
}
@Before("MyValid()")
public void before(JoinPoint joinPoint) {
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("【目標對象方法被調(diào)用時候產(chǎn)生的日志,記錄到日志表中】:"+myLog.desc());
System.out.println("【目標對象方法被調(diào)用時候產(chǎn)生的日志,記錄到日志表中】:" + myLog.desc());
}
}
2.3?Controller層代碼
package com.ycxw.web;
import com.ycxw.annotation.MyLog;
import org.springframework.stereotype.Component;
@Component
public class LogController {
@MyLog(desc = "這是結(jié)合spring aop知識,講解自定義注解應(yīng)用的一個案例")
public void testLogAspect(){
System.out.println("記錄日志...");
}
}
2.4 測試
訪問地址:http://localhost:8080/log/mylog文章來源:http://www.zghlxwxcb.cn/news/detail-725264.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-725264.html
到了這里,關(guān)于【SpringMVC】自定義注解與AOP結(jié)合使用的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!