日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java反射自定义注解底层设计原理

發(fā)布時間:2024/9/27 java 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java反射自定义注解底层设计原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

          • 一、反射
            • 1. 反射概念
            • 2. 反射機制的優(yōu)缺點
            • 3. 反射的用途
            • 4. 反射技術的使用
            • 5. 反射常用的Api
            • 6. 反射執(zhí)行構造函數
            • 7. 反射執(zhí)行給屬性賦值
            • 8. 反射執(zhí)行調用方法
          • 二、注解
            • 2.1. 注解概念
            • 2.2. 常用注解
            • 2.3. 元注解
            • 2.4. 常用注解
            • 2.5. 注解的Target
            • 2.6. 獲取注解信息
            • 2.7. 注解如何生效
            • 2.8. 注解實現案例
            • 2.09. 封裝自定義注解限流框架
            • 2.10. 整合Aop實現接口限流
            • 2.11. 案例

1.什么是反射、反射優(yōu)缺點
2.反射的用途/反射應用場景
3.反射調用方法/給屬性賦值
4.反射如何越過泛型檢查
5.什么是注解/注解生效的原理
6.自定義注解實現API接口限流框架

一、反射
1. 反射概念

使用反射機制可以動態(tài)獲取當前class的信息 比如方法的信息、注解信息、方法的參數、屬性等。
.java 源代碼 編譯.class 類加載器 jvm 字節(jié)碼

2. 反射機制的優(yōu)缺點

優(yōu)點:提供開發(fā)者能夠更好封裝框架實現擴展功能。
缺點:
(1)反射會消耗一定的系統資源,因此如果不需要動態(tài)地創(chuàng)建一個對象,那么就不需要用反射;
(2)反射調用方法時可以忽略權限檢查,因此可能會破壞封裝性而導致安全問題。

3. 反射的用途

反編譯:.class–>.java
1.通過反射機制訪問java對象的屬性,方法,構造方法等
2. JDBC加載驅動連接 class.forname
Class.forName(“com.mysql.jdbc.Driver”); // 動態(tài)加載mysql驅動
3. Spring容器框架IOC實例化對象

<bean id="mayikt" class="com.mayikt.UserEntity" />

4.自定義注解生效(反射+Aop)
5.第三方核心的框架 mybatis orm

4. 反射技術的使用

Class類 代表類的實體,在運行的Java應用程序中表示類和接口
Field類 代表類的成員變量(成員變量也稱為類的屬性)
Method類 代表類的方法
Constructor類 代表類的構造方法
1.getField、getMethod和getCostructor方法可以獲得指定名字的域、方法和構造器。
2.getFields、getMethods和getCostructors方法可以獲得類提供的public域、方法和構造器數組,其中包括超類的共有成員。
3.getDeclatedFields、getDeclatedMethods和getDeclaredConstructors方法可以獲得類中聲明的全部域、方法和構造器,其中包括私有和受保護的成員,但不包括超類的成員。

5. 反射常用的Api

(1)Object–>getClass
(2)任何數據類型(包括基本的數據類型)都有一個“靜態(tài)”的class屬性
(3)通過class類的靜態(tài)方法:forName(String className)(最常用)
Class<?> aClass = Class.forName(“com.mayikt.entity.UserEntity”);

/*** 反射機制使用的三種方式* <p>* 第1種:獲取class UserEntity.class* 第2種:獲取class Class.forName("類的全路徑");* 第3種:new UserEntity().getClass()*/@Testpublic void objCreateTest() throws InstantiationException, IllegalAccessException, ClassNotFoundException {Class<UserEntity> userClass1 = UserEntity.class;//默認執(zhí)行無參構造函數UserEntity userEntity1 = userClass1.newInstance();System.out.println(userEntity1);//2.類的的完成路徑 報名+類名Class<?> userClass2 = Class.forName("com.gblfy.elk.entity.UserEntity");System.out.println(userClass1 == userClass2);//3.new UserEntity().getClass()UserEntity userEntity2 = new UserEntity();Class userClass3 = userEntity2.getClass();System.out.println(userClass1 == userClass3);//trueSystem.out.println(userEntity1 == userEntity2);//false}

運行期間,一個類,只有一個Class對象產生

6. 反射執(zhí)行構造函數

執(zhí)行無參數構造函數和執(zhí)行有參數構造函數

/*** 使用反射機制初始化對象*/@Testpublic void constructorTest() throws InstantiationException, IllegalAccessException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException {// //2.類的的完成路徑 報名+類名Class<?> userClass2 = Class.forName("com.gblfy.elk.entity.UserEntity");// //默認執(zhí)行無參構造函數UserEntity userEntity = (UserEntity) userClass2.newInstance();System.out.println(userEntity);//執(zhí)行有參構造函數Constructor<?> declaredConstructor = userClass2.getDeclaredConstructor(String.class, Integer.class);UserEntity userEntity2 = (UserEntity) declaredConstructor.newInstance("mayikt", 22);System.out.println(userEntity2);}
7. 反射執(zhí)行給屬性賦值

反射執(zhí)行給公有屬性賦值和反射執(zhí)行給私有屬性賦值

/*** 反射如何給屬性賦值*/@Testpublic void evaluationTest() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {Class<?> userClass2 = Class.forName("com.gblfy.elk.entity.UserEntity");UserEntity userEntity2 = (UserEntity) userClass2.newInstance();//給公有屬性賦值Field publicName = userClass2.getDeclaredField("publicName");publicName.set(userEntity2, "mayikt");System.out.println(userEntity2.getPublicName());//給私有屬性賦值Field userName = userClass2.getDeclaredField("userName");//設置訪問私有屬性權限userName.setAccessible(true);userName.set(userEntity2, "mayikt2");System.out.println(userEntity2.getUserName());} 注意: xception in thread "main" java.lang.IllegalAccessException: Class com.mayikt.test.Test03 can not access a member of class com.mayikt.entity.UserEntity with modifiers "private"at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)at java.lang.reflect.Field.set(Field.java:761)at com.mayikt.test.Test03.main(Test03.java:28) 解決辦法: // 設置允許訪問私有屬性 userName.setAccessible(true);
8. 反射執(zhí)行調用方法

反射調用公有方法

//使用反射機制調用公用無參方法@Testpublic void methodNoparamTest() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException {Class<?> userClass2 = Class.forName("com.gblfy.elk.entity.UserEntity");//創(chuàng)建類實例Object o = userClass2.newInstance();//獲取公有和私有方法Method method = userClass2.getDeclaredMethod("mayikt");//設置訪問私有方法權限method.setAccessible(true);method.invoke(o);}

反射調用私有方法和反射調用方法傳遞參數

//使用反射機制調用私有有參方法@Testpublic void methodCarryParamTest() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException {Class<?> userClass2 = Class.forName("com.gblfy.elk.entity.UserEntity");//創(chuàng)建類實例Object o = userClass2.newInstance();//獲取公有和私有方法Method method = userClass2.getDeclaredMethod("sum", Integer.class, Integer.class);//設置訪問私有方法權限method.setAccessible(true);Integer result = (Integer) method.invoke(o, 1, 5);System.out.println(result);}
二、注解
2.1. 注解概念

什么是注解
注解用來給類聲明附加額外信息,可以標注在類、字段、方法等上面,編譯器、JVM以及開發(fā)人員等都可以通過反射拿到注解信息,進而做一些相關處理

SpringBoot 全部都是采用注解化

2.2. 常用注解
@Override 只能標注在子類覆蓋父類的方法上面,有提示的作用 @Deprecated 標注在過時的方法或類上面,有提示的作用 @SuppressWarnings("unchecked") 標注在編譯器認為有問題的類、 方法等上面,用來取消編譯器的警告提示,警告類型有serial、unchecked、unused、all
2.3. 元注解
元注解用來在聲明新注解時指定新注解的一些特性 @Target 指定新注解標注的位置,比如類、字段、方法等,取值有ElementType.Method等 @Retention 指定新注解的信息保留到什么時候,取值有RetentionPolicy.RUNTIME等 @Inherited 指定新注解標注在父類上時可被子類繼承
2.4. 常用注解
@Target(ElementType.METHOD) // 指定新注解可以標注在方法上 @Retention(RetentionPolicy.RUNTIME) // 指定新注解保留到程序運行時期 @Inherited // 指定新注解標注在父類上時可被子類繼承 public @interface MayiktName {public String name(); } 自定義注解 運行 :反射+aop
2.5. 注解的Target
TYPE:類、接口(包括注解類型)和枚舉的聲明 FIELD:字段聲明(包括枚舉常量) METHOD:方法聲明 PARAMETER:參數聲明 CONSTRUCTOR:構造函數聲明 LOCAL_VARIABLE:本地變量聲明 ANNOTATION_TYPE:注解類型聲明 PACKAGE:包聲明 TYPE_PARAMETER:類型參數聲明,JavaSE8引進,可以應用于類的泛型聲明之處 TYPE_USE:JavaSE8引進,此類型包括類型聲明和類型參數聲明
2.6. 獲取注解信息
package com.gblfy.elk.annotate;import java.lang.annotation.*;/*** ElementType.TYPE 注解在類上生效* ElementType.METHOD 注解在方法上生效* ElementType.FIELD 注解在屬性上生效* Retention 加此注解,反射才可以獲取* Inherited 子類可以繼承*/ @Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD,ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface MayiktName { } package com.gblfy.elk.entity;import com.gblfy.elk.annotate.MayiktName;@MayiktName public class UserEntity {private String userName;private Integer userAge;@MayiktNamepublic String publicName;public UserEntity() {System.out.println("執(zhí)行無參構造函數");}public UserEntity(String userName, Integer userAge) {System.out.println("執(zhí)行有參構造函數");this.userName = userName;this.userAge = userAge;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public Integer getUserAge() {return userAge;}public void setUserAge(Integer userAge) {this.userAge = userAge;}public String getPublicName() {return publicName;}public void setPublicName(String publicName) {this.publicName = publicName;}@Overridepublic String toString() {final StringBuffer sb = new StringBuffer("UserEntity{");sb.append("userName='").append(userName).append('\'');sb.append(", userAge=").append(userAge);sb.append('}');return sb.toString();}@MayiktNameprivate void mayikt() {System.out.println("mayikt");}@MayiktNameprivate Integer sum(Integer a, Integer b) {return a + b;} } /*** 注解聯練習** @author gblfy* @date 2022-03-13*/ public class AnnotateCase {//判斷某類上是否加上@MayiktName注解@Testpublic void classAnnotateTest() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException {//加載類Class<?> userClass = Class.forName("com.gblfy.elk.entity.UserEntity");// 1.獲取當前類上的注解MayiktName declaredAnnotation = userClass.getDeclaredAnnotation(MayiktName.class);System.out.println(declaredAnnotation);}//判斷指定方法上是否加上@MayiktName注解@Testpublic void methodAnnotateTest() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException {//加載類Class<?> userClass = Class.forName("com.gblfy.elk.entity.UserEntity");//創(chuàng)建類實例Object o = userClass.newInstance();//獲取指定mayikt方法Method method = userClass.getDeclaredMethod("mayikt");//獲取該方法上的注解,有則返回,無則返回nullMayiktName mayiktName = method.getDeclaredAnnotation(MayiktName.class);System.out.println(mayiktName);}//判斷某屬性上是否加上@MayiktName注解@Testpublic void fieldAnnotateTest() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException {//加載類Class<?> userClass = Class.forName("com.gblfy.elk.entity.UserEntity");// 1.獲取屬性上的注解Field publicName = userClass.getDeclaredField("publicName");MayiktName mayiktName = publicName.getDeclaredAnnotation(MayiktName.class);System.out.println(mayiktName);} }
2.7. 注解如何生效

實際項目中 注解想生效通過反射+aop機制

2.8. 注解實現案例

自定義限流注解

對我們接口實現 限流 比如 每s 只能訪問1次 或者每s 訪問兩次。
Maven

<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.79</version></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>22.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>

使用谷歌的guava例子

package com.gblfy.elk.controller;import com.gblfy.elk.annotate.GblfyStreamLimit; import com.google.common.util.concurrent.RateLimiter; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;@RestController public class SreamLimitController {/*** 每秒生成1.0個令牌* 滑動窗口、令牌桶、漏桶算法實現*/private RateLimiter rateLimiter = RateLimiter.create(1.0);@GetMapping("/get")public String get() {System.out.println("-----------------執(zhí)行目標方法-----------------");boolean result = rateLimiter.tryAcquire();if (!result) {return "當前訪問人數過多,請稍后重試!";}return "my is get";}@GetMapping("/add")public String add() {return "my is add";} }
2.09. 封裝自定義注解限流框架

整合自定義注解

package com.gblfy.elk.annotate;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/*** 自定義請求限流注解** @author gblfy* @date 2022-03-13*/ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface GblfyStreamLimit {/*** 限流名稱** @return*/String name() default "";/*** 限流次數,默認限流頻次 1秒/20次** @return*/double limitNum() default 20.0; }
2.10. 整合Aop實現接口限流
package com.gblfy.elk.aop;import com.gblfy.elk.annotate.GblfyStreamLimit; import com.google.common.util.concurrent.RateLimiter; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component;import java.util.concurrent.ConcurrentHashMap;@Aspect @Component public class StreamLimitAop {//并發(fā)map儲存private ConcurrentHashMap<String, RateLimiter> rateLimiterStrategy = new ConcurrentHashMap();/*** 只要在方法上添加該自定義限流注解,就會被AOP環(huán)繞通知攔截** @param joinPoint* @return*/@Around(value = "@annotation(com.gblfy.elk.annotate.GblfyStreamLimit)")public Object around(ProceedingJoinPoint joinPoint) {try {//獲取攔截的方法名Signature sig = joinPoint.getSignature();//獲取攔截的方法名MethodSignature methodSignature = (MethodSignature) sig;// 判斷方法上是否有加上該注解,如果有加上注解則限流GblfyStreamLimit gblfyStreamLimit =methodSignature.getMethod().getDeclaredAnnotation(GblfyStreamLimit.class);if (gblfyStreamLimit == null) {// 執(zhí)行目標方法return joinPoint.proceed();}// 1.獲取注解上的限流名稱(name)String name = gblfyStreamLimit.name();// 2.獲取注解上的limitNum(限流次數),實現對不同的方法限流策略不一樣的效果double limitNum = gblfyStreamLimit.limitNum();RateLimiter rateLimiter = rateLimiterStrategy.get(name);if (rateLimiter == null) {//3.動態(tài)匹配并創(chuàng)建不同的限流策略rateLimiter = RateLimiter.create(limitNum);rateLimiterStrategy.put(name, rateLimiter);}// 開始限流boolean result = rateLimiter.tryAcquire();if (!result) {return "當前訪問人數過多,請稍后重試!";}return joinPoint.proceed();} catch (Throwable throwable) {return "系統出現了錯誤!";}}/*** 前置通知*/@Before(value = "@annotation(com.gblfy.elk.annotate.GblfyStreamLimit)")public void before() {System.out.println("----------------------前置通知----------------------");}/*** 后置通知*/@AfterReturning(value = "@annotation(com.gblfy.elk.annotate.GblfyStreamLimit)")public void AfterReturning() {System.out.println("----------------------后置通知----------------------");}/*** 異常通知** @param point*/@AfterThrowing(value = "@annotation(com.gblfy.elk.annotate.GblfyStreamLimit)", throwing = "e")public void serviceAspect(JoinPoint point, Exception e) {System.out.println("----------------------異常通知----------------------");} }
2.11. 案例
package com.gblfy.elk.controller;import com.gblfy.elk.annotate.GblfyStreamLimit; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;@RestController public class SreamLimitController {@GetMapping("/get2")@GblfyStreamLimit(name = "get2", limitNum = 1.0)public String get2() {System.out.println("-----------------執(zhí)行目標方法-----------------");return "my is get";}@GetMapping("/add")public String add() {return "my is add";} }

http://127.0.0.1:8080/get
http://127.0.0.1:8080/my

總結

以上是生活随笔為你收集整理的Java反射自定义注解底层设计原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。