我的开发日志:类路径扫描、DI 容器与动态代理
前言
我失忆了,完全不记得自己早上干了什么。
日程
早上 10 点左右开始,学了一早上,主要是类路径扫描相关的调试。
晚上 8 点了,真不能再摸🐟了。
学习记录
计算机网络:
1. 子网划分与子网掩码
学习内容
省流
- 手搓类路径扫描器
- 手搓基础 DI 容器
- 动态代理
1. 手搓类路径扫描器
1)首先要确定需要扫描的包
String path = packageName.replace('.', '/');
2)然后获取系统类加载器获取路径,并获取该路径下的所有资源
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
Enumeration<URL> resources = classLoader.getResources(path);
注意:系统类加载器 (ClassLoader.getSystemClassLoader()
) 的扫描范围包括所有在 JVM 启动时通过 -classpath
或 -cp
指定的路径(包括 Maven/Gradle 依赖)。
3)遍历所有的资源,通过 resource.getProtocol()
获取 URL 对象的协议类型,获取 URL 对象的类文件
while (resources.hasMoreElements()){
URL resource = resources.nextElement();
if (resource.getProtocol().equals("file")) {
classes.addAll(findClasses(new File(resource.getFile()), packageName, classFilter));
}
}
->进入 findClasses
方法
4)获取文件列表,遍历文件和子目录,获取 clazz
对象,并返回 List<Class<?>> classes
列表
File[] files = directory.listFiles();
for (File file : files) {
if (file.isDirectory()) {
String subPackage = packageName + "." + file.getName();
classes.addAll(findClasses(file, subPackage, classFilter));
} else if (file.getName().endsWith(".class")) {
String className = packageName + '.' +
file.getName().substring(0, file.getName().length() - 6); //获取class全类名
Class<?> clazz = Class.forName(className, false, Thread.currentThread().getContextClassLoader()); //根据全类名找到clazz对象(不对类进行初始化)
if (classFilter.test(clazz)) { //过滤器检查
classes.add(clazz);
}
}
}
return classes;
5)提供了一个扫描含有对应注解的类
public static List<Class<?>> scanClassesWithAnnotation(String packageName,Class<? extends java.lang.annotation.Annotation> annotation) {
return scanClasses(packageName, clazz -> clazz.isAnnotationPresent(annotation));
}
Class<? extends java.lang.annotation.Annotation>
表示接收的 Class
对象是 java.lang.annotation.Annotation
的任意子类。
2. 手搓基础 DI 容器
0)用 map 来储存映射,在创建类对象时进行扫描
// 存储类定义的映射(类名 -> 类对象)
private final Map<String, Class<?>> classRegistry = new HashMap<>();
// 存储单例实例的映射(类名 -> 实例)
private final Map<String, Object> singletonInstances = new HashMap<>();
// 正在创建的Bean记录(用于解决循环依赖)
private final Set<String> beansInCreation = new HashSet<>();
//接口到实现类的映射
private final Map<Class<?>, Class<?>> interfaceToImplementation = new HashMap<>();
// 包扫描路径
private final String basePackage;
public ContainerFactory(String basePackage) {
this.basePackage = basePackage;
scanComponents();
initializeInterfaceLinks();
initializeSingletons();
}
1)组件扫描
private void scanComponents() {
List<Class<?>> componentClasses = ClassPathScanner.scanClassesWithAnnotation(
basePackage, KatComponent.class);
for (Class<?> clazz : componentClasses) {
register(clazz);
}
}
-> 进入 register
方法
2)注册组件
public void register(Class<?> clazz) {
if (clazz.isAnnotationPresent(KatComponent.class)) {
String beanName = getBeanName(clazz);
classRegistry.put(beanName, clazz);
}
}
// 获取Bean名称
private String getBeanName(Class<?> clazz) {
KatComponent component = clazz.getAnnotation(KatComponent.class);
return component.value().isEmpty() ? clazz.getSimpleName() : component.value(); //注解没有指定Bean名称时,以类名作为Bean名称
}
3)对单例 Bean 进行初始化
// 初始化所有单例Bean
private void initializeSingletons() {
for (Map.Entry<String, Class<?>> entry : classRegistry.entrySet()) {
Class<?> clazz = entry.getValue();
if (clazz.isAnnotationPresent(KatSingleton.class)) {
getBean(clazz); // 触发单例初始化
}
}
}
->进入 getBean
方法
4)获取 Bean 实例
这里采用了依赖注入接口模式,所以要从接口索引中获取对应的实现类
// 获取Bean实例(接口映射)
@SuppressWarnings("unchecked") //忽略泛型警告
public <T> T getBean(Class<T> interfaceType) {
//接口模式
Class<?> implementationClass = interfaceToImplementation.get(interfaceType);
if (implementationClass == null) {
throw new RuntimeException("No implementation found for " + interfaceType);
}
return (T) getBean(getBeanName(implementationClass), implementationClass);
}
//初始化接口索引
private void initializeInterfaceLinks() {
for (Class<?> clazz : classRegistry.values()) {
for (Class<?> intf : clazz.getInterfaces()) {
if (!interfaceToImplementation.containsKey(intf)) {
interfaceToImplementation.put(intf, clazz);
}
}
}
}
–>进入实现类 Bean 创建
@SuppressWarnings("unchecked") //忽略泛型警告
public <T> T getBean(String beanName, Class<T> clazz) {
// 检查单例缓存
if (singletonInstances.containsKey(beanName)) {
return (T) singletonInstances.get(beanName);
}
// 检查是否已注册
if (!classRegistry.containsKey(beanName)) {
throw new RuntimeException("Bean not registered: " + beanName);
}
// 检查循环依赖
if (beansInCreation.contains(beanName)) {
throw new RuntimeException("Circular dependency detected for bean: " + beanName);
}
beansInCreation.add(beanName);
try {
Class<?> targetClass = classRegistry.get(beanName);
Object instance = createInstance(targetClass); //创建实例
// 如果是单例则缓存
if (targetClass.isAnnotationPresent(KatSingleton.class)) {
singletonInstances.put(beanName, instance);
}
return (T) instance;
} catch (Exception e) {
throw new RuntimeException("Failed to create bean: " + beanName, e);
} finally {
beansInCreation.remove(beanName);
}
}
—>进入 createInstance
方法
5)创建实例
private Object createInstance(Class<?> clazz) throws Exception {
// 1. 优先使用@KatAutowired构造器
Constructor<?> autowiredCtor = findAutowiredConstructor(clazz);
if (autowiredCtor != null) {
return createInstanceWithConstructor(autowiredCtor);
}
// 2. 使用默认无参构造器
try {
Object instance = clazz.getDeclaredConstructor().newInstance();
injectFields(instance);
return instance;
} catch (NoSuchMethodException e) {
throw new RuntimeException("No suitable constructor found for " + clazz.getName());
}
}
---->进入 findAutowiredConstructor
方法
// 查找@KatAutowired构造器
private Constructor<?> findAutowiredConstructor(Class<?> clazz) {
Constructor<?>[] ctors = clazz.getConstructors();
for (Constructor<?> ctor : ctors) {
if (ctor.isAnnotationPresent(KatAutowired.class)) {
return ctor;
}
}
return null;
}
---->进入 createInstanceWithConstructor
方法
// 使用构造器创建实例
private Object createInstanceWithConstructor(Constructor<?> ctor) throws Exception {
Class<?>[] paramTypes = ctor.getParameterTypes(); //获取参数
Object[] args = new Object[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++) { //添加参数
args[i] = getBean(paramTypes[i]);
}
Object instance = ctor.newInstance(args); //创建实例
injectFields(instance); //注入依赖字段
return instance;
}
----->进入 injectFields
方法
// 注入字段依赖
private void injectFields(Object instance) throws IllegalAccessException {
Class<?> clazz = instance.getClass();
//遍历目标类的所有字段(包括私有字段)
for (Field field : clazz.getDeclaredFields()) {
// 检查字段是否被@KatAutowired注解标注
if (field.isAnnotationPresent(KatAutowired.class)) {
Object dependency = getBean(field.getType());
field.setAccessible(true); //允许访问私有字段
field.set(instance, dependency); //注入目标字段
}
}
}
目前只是一个非常基础的版本,处理不了复杂的依赖关系,整体效率也比较低。
明天考虑兼容动态代理,多路径扫描(通过配置文件加载)。
3. 动态代理
在运行时动态创建代理类和对象,而不是在编译时静态定义。它对于依赖注入后的事务实现以及 AOP 非常重要。
1)原理分析
以 InvocationHandler
为例
InvocationHandler
是 Java 动态代理机制中的核心接口,它定义了代理对象方法调用的转发逻辑。
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
proxy
:动态生成的代理对象实例method
:被调用的方法对象args
:方法调用时传入的参数数组
使用示例:
class DebugInvocationHandler implements InvocationHandler {
private final Object target;
public DebugInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 方法调用前逻辑
System.out.printf("调用方法: %s,参数: %s%n",
method.getName(),
Arrays.toString(args));
// 调用真实对象的方法
Object result = method.invoke(target, args);
// 方法调用后逻辑
System.out.printf("方法 %s 调用完成,结果: %s%n",
method.getName(),
result);
return result;
}
}
public static void main(String[] args) {
RealSubject real = new RealSubject(); //真实的对象
//创建一个代理对象
Subject proxy = (Subject) Proxy.newProxyInstance(
Subject.class.getClassLoader(),
new Class[]{Subject.class},
new DebugInvocationHandler(real)
);
//代理对象.method() → InvocationHandler.invoke() → 真实对象.method()
proxy.request();
}
结语
大脑已经宕机。