什么是反射呢?
来看看GPTs的回答!
三种获取class的方式
// 获取class
Class<? extends User> aClass = User.class;
try {
// 第一种方式,通过class创建对象
User user1 = (User) aClass.getConstructor().newInstance();
System.out.println(user1);
// 第二种方式,通过forName加载类,然后反射创建对象
Class<?> bclass = Class.forName("com.example.advancedlearning.entity.User");
User user2 = (User) bclass.getConstructor().newInstance();
System.out.println(user2);
//new User
User newUser = new User();
// 获取classs
Class<? extends User> cclass = newUser.getClass();
// class肯定都是相等的
System.out.println(aClass == bclass);
System.out.println(aClass == cclass);
// 对象肯定都是不相等的
System.out.println(user1 == user2);
System.out.println(user1 == newUser);
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException | InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException(e);
}
反射如何创建有参构造函数对象?
try {
Class<?> aClass = Class.forName("com.example.advancedlearning.entity.User");
// 通过class创建的对象,默认走的是无参构造函数
// getConstructor只能拿到public的构造函数
User user1 = (User) aClass.getConstructor().newInstance();
System.out.println(user1);
System.out.println("----------------------------------");
// 通过getDeclaredConstructor可以拿到所有的构造函数,但是需要setAccessible(true)来访问private的构造函数
User user2 = (User) aClass.getDeclaredConstructor(String.class, Integer.class).newInstance("zhangsan", 20);
System.out.println(user2);
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException |
InvocationTargetException e) {
throw new RuntimeException(e);
}
反射里的API
通过反射拿到类的字段
Class<?> aClass = Class.forName("com.example.advancedlearning.entity.User");
// 通过getDeclaredFields可以拿到所有的字段
// getFields只能拿到public的字段
Field[] declaredFields = aClass.getDeclaredFields();
for (java.lang.reflect.Field field :declaredFields) {
System.out.println("字段名:" + field.getName());
System.out.println("字段类型:" + field.getType());
}
给public和private属性赋值
try {
Class<?> aClass = Class.forName("com.example.advancedlearning.entity.User");
// 通过getDeclaredFields可以拿到所有的字段
// getFields只能拿到public的字段
Field[] declaredFields = aClass.getDeclaredFields();
for (java.lang.reflect.Field field :declaredFields) {
System.out.println("字段名:" + field.getName() + ", 字段类型:" + field.getType());
}
// 给publicUser公共字段赋值
User user = (User) aClass.getConstructor().newInstance();
Field publicUser = aClass.getField("publicUser");
// publicUser.setAccessible(true);
publicUser.set(user, "lisi");
// 给private属性userName赋值
Field userName = aClass.getDeclaredField("userName");
userName.setAccessible(true);// setAccessible是为了访问private属性
userName.set(user, "wangwu");
System.out.println(user);
} catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException | InstantiationException |
IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
拿到所有方法,调用私有方法和调用私有带参数方法
try {
Class<?> aClass = Class.forName("com.example.advancedlearning.entity.User");
// 在JDK17中,通过反射创建对象,需要用getConstructor方法
// 而不是newInstance(),因为newInstance()方法已经被废弃
// 为了确保兼容性和安全性,使用getConstructor().newInstance()来创建对象
User user = (User) aClass.getConstructor().newInstance();
// 拿到所有的方法
java.lang.reflect.Method[] methods = aClass.getMethods();
for (java.lang.reflect.Method method : methods) {
System.out.println("方法名:" + method.getName()
+ ", 返回类型:" + method.getReturnType()
+ ", 参数类型:" + Arrays.toString(method.getParameterTypes()));
}
// 分割线
System.out.println("----------------------------------");
// 调用mayikt方法
Method mayikt = aClass.getDeclaredMethod("mayikt");
mayikt.setAccessible(true); // setAccessible是为了访问private属性
Object invoke = mayikt.invoke(user);// invoke是为了调用private方法
// 调用私有方法sum方法传入两个参数
Method sum = aClass.getDeclaredMethod("sum", Integer.class, Integer.class);
sum.setAccessible(true);
Integer integer = (Integer) sum.invoke(user, 10, 20);
System.out.println("调用sum方法返回值:" + integer);
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException |
InvocationTargetException e) {
throw new RuntimeException(e);
}
通过反射越过泛型检查
try {
// 创建一个字符串集合
List<String> list = new ArrayList<>();
list.add("zhangsan");
// 通过反射机制调用add方法,传一个int类型的参数
Class<?> aClass = list.getClass();
Method add = aClass.getDeclaredMethod("add", Object.class);
add.setAccessible(true);
add.invoke(list, 10);
// 泛型检查只有在编译时存在,可以通过反射直接越过泛型检查
System.out.println(list);
// 虽然是越过了泛型检查,但是lombok会报错
list.forEach(System.out::println);
} catch (NoSuchMethodException | IllegalAccessException |
InvocationTargetException e) {
throw new RuntimeException(e);
}
什么是注解?
什么是元注解?
获取方法上的注解
try {
Class<?> aClass = Class.forName("com.example.advancedlearning.entity.User");
// 创建对象
User user = (User) aClass.getConstructor().newInstance();
// 获取mayikt方法
Method mayikt = aClass.getDeclaredMethod("mayikt");
// 获取mayikt方法的注解
MyAnnotation myAnnotation = mayikt.getDeclaredAnnotation(MyAnnotation.class);
System.out.println(myAnnotation.annotationType().getName());
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException |
InvocationTargetException e) {
throw new RuntimeException(e);
}
获取类上的注解
try {
Class<?> aClass = Class.forName("com.example.advancedlearning.entity.User");
MyAnnotation myAnnotation = aClass.getDeclaredAnnotation(MyAnnotation.class);
System.out.println(myAnnotation);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
获取字段上的注解
try {
Class<?> aClass = Class.forName("com.example.advancedlearning.entity.User");
java.lang.reflect.Field userName = aClass.getDeclaredField("userName");
MyAnnotation myAnnotation = userName.getDeclaredAnnotation(MyAnnotation.class);
System.out.println(myAnnotation);
} catch (ClassNotFoundException | NoSuchFieldException e) {
throw new RuntimeException(e);
}
获取构造函数上的注解
try {
Class<?> aClass = Class.forName("com.example.advancedlearning.entity.User");
// 获取构造函数对象
Constructor<?> constructor = aClass.getDeclaredConstructor(String.class, Integer.class);
MyAnnotation myAnnotation = constructor.getDeclaredAnnotation(MyAnnotation.class);
System.out.println(myAnnotation);
// 获取无参构造函数
Constructor<?> constructor1 = aClass.getDeclaredConstructor();
MyAnnotation myAnnotation1 = constructor1.getDeclaredAnnotation(MyAnnotation.class);
System.out.println(myAnnotation1);
} catch (ClassNotFoundException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
反射+注解实现功能
MyCurrentLimit
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 限流注解
public @interface MyCurrentLimit {
/**
* name 限流名称
*/
String name() default "";
/**
* limit 每秒限制多少次
*/
int limit() default 10;
}
CurrentLimitAop
import com.example.advancedlearning.annotation.MyCurrentLimit;
import com.example.advancedlearning.common.Result;
import com.google.common.util.concurrent.RateLimiter;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.Aspect;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
@Aspect
@Component
public class CurrentLimitAop {
// 整一个ConcurrentHashMap来存储每个接口的RateLimiter
private ConcurrentHashMap<String, RateLimiter> rateLimiterMap = new ConcurrentHashMap<>();
/**
* Spring AOP 相关注解
* 在使用 @Aspect 的切面类中,通常会结合其他注解来定义切入点和通知:
*
* @Pointcut: 定义切入点,指定在哪些方法上执行增强逻辑。
* @Before: 定义前置通知,在目标方法执行前执行。
* @After: 定义后置通知,在目标方法执行后执行。
* @AfterReturning: 定义返回通知,在目标方法正常返回后执行。
* @AfterThrowing: 定义异常通知,在目标方法抛出异常时执行。
* @Around: 定义环绕通知,可以控制目标方法的执行时机、参数和返回值。
*/
// 环绕通知com.example.advancedlearning.annotation.MyCurrentLimit
@Around("@annotation(com.example.advancedlearning.annotation.MyCurrentLimit)")
public Object around(ProceedingJoinPoint pjp) {
/*
环绕通知更好的控制方法是否执行!
*/
try {
// 获取signature,signature是一个方法签名对象
Signature signature = pjp.getSignature();
// 强转成方法签名对象
MethodSignature methodSignature = (MethodSignature) signature;
// 拿到注解的limit值
MyCurrentLimit myCurrentLimit = methodSignature.getMethod().getAnnotation(MyCurrentLimit.class);
// 拿到注解的name值
String name = myCurrentLimit.name();
// 拿到注解的limit值
int limit = myCurrentLimit.limit();
// 从rateLimiterMap中获取RateLimiter对象,如果没有则创建一个
RateLimiter rateLimiter = rateLimiterMap
.computeIfAbsent(name, k -> RateLimiter.create(limit));
if (!rateLimiter.tryAcquire()) {
return Result.error("访问太频繁啦!");
}
// 限流
System.out.println("name: " + name + ", limit: " + limit);
// 放行目标方法
return pjp.proceed();
} catch (Throwable e) {
log.error("未知异常:{}", e.getMessage(), e);
return Result.error("哎呀,服务器繁忙啦!");
}
}
}
MemberController
import com.example.advancedlearning.annotation.MyAnnotation;
import com.example.advancedlearning.annotation.MyCurrentLimit;
import com.example.advancedlearning.common.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@RestController
public class MemberController {
@GetMapping("/get")
@MyCurrentLimit(name = "get", limit = 2)
public Result<String> get() {
return Result.success("hello");
}
@GetMapping("/test")
public Result<Map<String, Object>> test() {
Map<String, Object> data = new HashMap<>();
data.put("name", "张三");
data.put("age", 18);
return Result.success("获取成功", data);
}
@GetMapping("/add")
@MyCurrentLimit(name = "add", limit = 9)
public Result<String> add() {
return Result.success("This is a Addd Method");
}
@GetMapping("/delete")
public Result<String> delete() {
return Result.success("This is a Delete Method");
}
@GetMapping("/update")
public Result<String> update() {
return Result.success("This is a Update Method");
}
}