feat(reflection): add interactive reflection visualization lab
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
package com.example.scaffold.learning;
|
||||
|
||||
import com.example.scaffold.learning.reflection.ReflectionLabTarget;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/learning/reflection")
|
||||
public class ReflectionLearningController {
|
||||
|
||||
@GetMapping("/overview")
|
||||
public Map<String, Object> overview() {
|
||||
return Map.of(
|
||||
"whatIsReflection", List.of(
|
||||
"运行时检查类、字段、方法、构造器",
|
||||
"运行时动态创建对象",
|
||||
"运行时调用方法、读写字段",
|
||||
"Spring / MyBatis / Jackson 等框架大量依赖反射"
|
||||
),
|
||||
"whyItMatters", List.of(
|
||||
"理解框架为什么能自动装配、自动绑定、自动序列化",
|
||||
"理解代理、注解扫描、Bean 创建背后的机制",
|
||||
"理解反射带来的灵活性与性能成本"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@GetMapping("/class-info")
|
||||
public Map<String, Object> classInfo() throws Exception {
|
||||
Class<?> clazz = ReflectionLabTarget.class;
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("className", clazz.getName());
|
||||
result.put("simpleName", clazz.getSimpleName());
|
||||
result.put("constructors", Arrays.stream(clazz.getDeclaredConstructors()).map(Constructor::toString).toList());
|
||||
result.put("fields", Arrays.stream(clazz.getDeclaredFields()).map(Field::toString).toList());
|
||||
result.put("methods", Arrays.stream(clazz.getDeclaredMethods()).map(Method::toString).toList());
|
||||
return result;
|
||||
}
|
||||
|
||||
@GetMapping("/instantiate")
|
||||
public Map<String, Object> instantiate(@RequestParam(defaultValue = "ref-user") String name,
|
||||
@RequestParam(defaultValue = "5") int count) throws Exception {
|
||||
Constructor<ReflectionLabTarget> constructor = ReflectionLabTarget.class.getDeclaredConstructor(String.class, int.class);
|
||||
ReflectionLabTarget obj = constructor.newInstance(name, count);
|
||||
return Map.of(
|
||||
"instance", obj.getClass().getName(),
|
||||
"identityHashCode", System.identityHashCode(obj),
|
||||
"name", obj.getName(),
|
||||
"count", obj.getCount(),
|
||||
"message", "通过反射构造器动态创建对象成功"
|
||||
);
|
||||
}
|
||||
|
||||
@GetMapping("/field-access")
|
||||
public Map<String, Object> fieldAccess(@RequestParam(defaultValue = "changed-by-reflection") String value) throws Exception {
|
||||
ReflectionLabTarget obj = new ReflectionLabTarget();
|
||||
Field field = ReflectionLabTarget.class.getDeclaredField("name");
|
||||
field.setAccessible(true);
|
||||
Object before = field.get(obj);
|
||||
field.set(obj, value);
|
||||
Object after = field.get(obj);
|
||||
return Map.of(
|
||||
"field", field.getName(),
|
||||
"before", before,
|
||||
"after", after,
|
||||
"message", "私有字段已通过反射修改"
|
||||
);
|
||||
}
|
||||
|
||||
@GetMapping("/method-call")
|
||||
public Map<String, Object> methodCall(@RequestParam(defaultValue = "你好") String prefix) throws Exception {
|
||||
ReflectionLabTarget obj = new ReflectionLabTarget("Spring", 2);
|
||||
Method publicMethod = ReflectionLabTarget.class.getDeclaredMethod("greet", String.class);
|
||||
Object publicResult = publicMethod.invoke(obj, prefix);
|
||||
|
||||
Method privateMethod = ReflectionLabTarget.class.getDeclaredMethod("secretFormula", String.class);
|
||||
privateMethod.setAccessible(true);
|
||||
Object privateResult = privateMethod.invoke(obj, "debug");
|
||||
|
||||
Method staticMethod = ReflectionLabTarget.class.getDeclaredMethod("staticInfo");
|
||||
Object staticResult = staticMethod.invoke(null);
|
||||
|
||||
return Map.of(
|
||||
"publicMethodResult", publicResult,
|
||||
"privateMethodResult", privateResult,
|
||||
"staticMethodResult", staticResult,
|
||||
"message", "公开方法、私有方法、静态方法都已通过反射调用"
|
||||
);
|
||||
}
|
||||
|
||||
@GetMapping("/why-frameworks-use-it")
|
||||
public Map<String, Object> whyFrameworksUseIt() {
|
||||
return Map.of(
|
||||
"spring", List.of("扫描注解", "创建 Bean", "依赖注入", "调用生命周期方法"),
|
||||
"jackson", List.of("读取字段", "调用 getter/setter", "对象序列化/反序列化"),
|
||||
"mybatis", List.of("结果集映射到对象", "动态代理 Mapper 接口"),
|
||||
"warning", "反射很强大,但要理解它的性能成本、可读性成本和封装破坏风险"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.example.scaffold.learning.reflection;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ReflectionLabTarget {
|
||||
private String name = "default-name";
|
||||
private int count = 3;
|
||||
private final List<String> tags = List.of("spring", "reflection", "proxy");
|
||||
|
||||
public ReflectionLabTarget() {
|
||||
}
|
||||
|
||||
public ReflectionLabTarget(String name, int count) {
|
||||
this.name = name;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public String greet(String prefix) {
|
||||
return prefix + ", " + name + " x" + count;
|
||||
}
|
||||
|
||||
private String secretFormula(String input) {
|
||||
return "secret:" + input + ":" + (count * 7);
|
||||
}
|
||||
|
||||
public static Map<String, Object> staticInfo() {
|
||||
return Map.of(
|
||||
"topic", "reflection",
|
||||
"message", "静态方法也可以通过反射调用"
|
||||
);
|
||||
}
|
||||
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public int getCount() { return count; }
|
||||
public void setCount(int count) { this.count = count; }
|
||||
public List<String> getTags() { return tags; }
|
||||
}
|
||||
Reference in New Issue
Block a user