文章目录

  • 一、反射
    • 1. 反射概念
    • 2. 反射机制的优缺点
    • 3. 反射的用途
    • 4. 反射技术的使用
    • 5. 反射常用的Api
    • 6. 反射执行构造函数
    • 7. 反射执行给属性赋值
    • 8. 反射执行调用方法
  • 二、注解
    • 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.什么是反射、反射优缺点
2.反射的用途/反射应用场景
3.反射调用方法/给属性赋值
4.反射如何越过泛型检查
5.什么是注解/注解生效的原理
6.自定义注解实现API接口限流框架

一、反射
1. 反射概念

使用反射机制可以动态获取当前class的信息 比如方法的信息、注解信息、方法的参数、属性等。
.java 源代码 编译.class 类加载器 jvm 字节码

2. 反射机制的优缺点

优点:提供开发者能够更好封装框架实现扩展功能。
缺点:
(1)反射会消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射;
(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

3. 反射的用途

反编译:.class–>.java
1.通过反射机制访问java对象的属性,方法,构造方法等
2. JDBC加载驱动连接 class.forname
Class.forName(“com.mysql.jdbc.Driver”); // 动态加载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)任何数据类型(包括基本的数据类型)都有一个“静态”的class属性
(3)通过class类的静态方法: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;//默认执行无参构造函数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. 反射执行构造函数

执行无参数构造函数和执行有参数构造函数

   /*** 使用反射机制初始化对象*/@Testpublic void constructorTest() throws InstantiationException, IllegalAccessException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException {// //2.类的的完成路径 报名+类名Class<?> userClass2 = Class.forName("com.gblfy.elk.entity.UserEntity");// //默认执行无参构造函数UserEntity userEntity = (UserEntity) userClass2.newInstance();System.out.println(userEntity);//执行有参构造函数Constructor<?> declaredConstructor = userClass2.getDeclaredConstructor(String.class, Integer.class);UserEntity userEntity2 = (UserEntity) declaredConstructor.newInstance("mayikt", 22);System.out.println(userEntity2);}
7. 反射执行给属性赋值

反射执行给公有属性赋值和反射执行给私有属性赋值

/*** 反射如何给属性赋值*/@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. 反射执行调用方法

反射调用公有方法

   //使用反射机制调用公用无参方法@Testpublic void methodNoparamTest() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException {Class<?> userClass2 = Class.forName("com.gblfy.elk.entity.UserEntity");//创建类实例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");//创建类实例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以及开发人员等都可以通过反射拿到注解信息,进而做一些相关处理

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("执行无参构造函数");}public UserEntity(String userName, Integer userAge) {System.out.println("执行有参构造函数");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");//创建类实例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("-----------------执行目标方法-----------------");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 {//并发map储存private ConcurrentHashMap<String, RateLimiter> rateLimiterStrategy = new ConcurrentHashMap();/*** 只要在方法上添加该自定义限流注解,就会被AOP环绕通知拦截** @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) {// 执行目标方法return joinPoint.proceed();}// 1.获取注解上的限流名称(name)String name = gblfyStreamLimit.name();// 2.获取注解上的limitNum(限流次数),实现对不同的方法限流策略不一样的效果double limitNum = gblfyStreamLimit.limitNum();RateLimiter rateLimiter = rateLimiterStrategy.get(name);if (rateLimiter == null) {//3.动态匹配并创建不同的限流策略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("-----------------执行目标方法-----------------");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反射自定义注解底层设计原理相关推荐

  1. Java反射+自定义注解实现配置文件数组加载(实现@ConfigurationProperties(xxx))

    Java.Rust 技术交流群: 783303214 一.背景 最近有小朋友问我,怎么样在.properties文件中配置数组参数,我给他举了上篇文章中的注解@ConfigurationPropert ...

  2. java中注解动态传参_Java自定义注解源码+原理解释(使用Java自定义注解校验bean传入参数合法性)...

    Java自定义注解源码+原理解释(使用Java自定义注解校验bean传入参数合法性)java 前言:因为前段时间忙于写接口,在接口中须要作不少的参数校验,本着简洁.高效的原则,便写了这个小工具供本身使 ...

  3. 第7章 Java反射与注解

    第7章 Java反射与注解 注解Annotation Annotation的作用 Annotation的格式 Annotation使用位置 内置注解 元注解 自定义注解 设置后自动生成的注解 2.反射 ...

  4. Java中自定义注解的使用

    Java中自定义注解的使用 一般来说,市面上有一些的框架,企业都不会直接拿过来就用,通过会做二次开发或封装,为了更加适配自己的开发规范和业务.那么在封装或适配的过程中,自定义注解就起着比较重要的作用. ...

  5. java之自定义注解的完整使用

    小坏java自定义注解的完整使用 一.何为java注解之道 1.java 注解的理解之道 2.java 注解的使用示例之道 3.Java 如何自定义注解之道 4.java 元注解之道 5.java 如 ...

  6. java反射和注解开发(备java基础,javaee框架原理)-任亮-专题视频课程

    java反射和注解开发(备java基础,javaee框架原理)-5358人已学习 课程介绍         Java注解是附加在代码中的一些元信息,用于一些工具在编译.运行时进行解析和使用,起到说明. ...

  7. Java并发机制的底层实现原理

    Java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化为汇编指令在CPU上执行,Java中所使用的并发机制依赖于JVM的实现和CPU的指令.本章我们将 ...

  8. 《Java并发编程的艺术》一一第2章Java并发机制的底层实现原理

    第2章Java并发机制的底层实现原理 2.1 volatile的应用 Java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化为汇编指令在CPU上执行, ...

  9. 分布式红锁的加锁的lua底层设计原理

    分布式红锁的加锁的lua底层设计原理 提前做2个动作: 1.先把3台 redis key全部清空(为了不受debug干扰,必须先删除锁) 127.0.0.1:6379> flushdb OK 2 ...

最新文章

  1. 2021年大数据Flink(二十五):Flink 状态管理
  2. Dockerfile实践优化建议
  3. MODIS(TerraAqua)陆地标准产品
  4. 大一计算机课程ppt作业,大学生计算机基础作业PPT.ppt
  5. 苹果终端date命令_苹果M1 Mac电脑关闭SIP方法
  6. keyshot环境素材文件_超赞|15个不翻墙免费可商用矢量素材下载网站推荐
  7. 个人博客开发系列:前台博客页面开发部署完成
  8. Python __str __()和__repr __()函数
  9. 开课吧课堂:深入了解学习C++的意义与就业方向
  10. 如何判断当前循环的栏目是不是最后一个
  11. 计算机考研视频哪个机构的好,计算机考研辅导视频十大排名
  12. 从零开始学编程系列汇总
  13. 如何优雅地排版微信公众号内的代码块?我推荐几款常用的发帖工具!
  14. 从乘法求导法则到BPTT算法
  15. 用turtle绘图做一个钟表时钟
  16. 小心!新媒体环境下,营销传播还有几个大坑!
  17. Spring系列教程六: Spring jdbcTemplate在Dao中的使用
  18. VsCode与Sublime编辑器优缺点对比
  19. [慈溪2012]书架(bookshelf)
  20. LintCode Find the Duplicate Number

热门文章

  1. 名校博士生被电信诈骗10多万,却被嘲“博士也会被骗书白读了”,学校发声!...
  2. 中国科学院大学庆生 一颗小行星以“国科大”命名
  3. 深度学习浪潮过后,计算机视觉将走向何方
  4. 黑白棋游戏水平(2)--pytorch剪裁
  5. 从框架源码中学习结构型设计模式
  6. CNN(Convolutional Neural Network) 的基础
  7. C++ Deque(双向队列
  8. MonoBehaviour常用方法
  9. cuda的shared momery
  10. 当60亿次攻击来袭,人机联合打了一场漂亮的防御战