模拟spring框架低层创建和管理对象(IOC、DI)
1、分析
- 创建工具类:指定一个目录,作为参数传入,获取这个目录下所有的.class文件,包括所在路径,遍历每个文件,获取其className类的全路径,如:javase.spring.classes.HelloController,获取beanName,helloController。(包扫描)
package javapro.spring.util;
import org.junit.Test;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class FileUtil {
public static String getBeanName(String className) {
int lastIndexOf = className.lastIndexOf(".");
String name = className.substring(lastIndexOf + 1);
char c = name.charAt(0);
char toLowerCase = Character.toLowerCase(c);
return toLowerCase + name.substring(1);
}
public static String getClassName(String path) {
Integer index = path.indexOf("classes");
String substring = path.substring(index + 8);
String s = substring.substring(0, substring.length() - 6);
String replaceAll = s.replaceAll("\\\\", "\\.");
return replaceAll;
}
public static List<String> readClassName(String packagePath, List<String> list) {
File file = new File(packagePath);
File[] files = file.listFiles();
if (files.length > 0) {
for (File f : files) {
if (f.isDirectory()) {
readClassName(f.getAbsolutePath(), list);
} else {
String absolutePath = f.getAbsolutePath();
String className = FileUtil.getClassName(absolutePath);
list.add(className);
}
}
}
return list;
}
@Test
public void test() {
FileUtil fileUtil = new FileUtil();
List<String> list = new ArrayList<>();
String path = "F:\\idea_Java\\excellent\\stage1\\javase\\SE01\\classes\\javase";
List<String> className = fileUtil.readClassName(path, list);
for (String c : className) {
System.out.println(c);
}
}
}
- 创建对象,反射Class.forName(className)获取到Class对象,通过Class类对象提供的newInstance创建对象实例。
- 把创建好的对象放入容器里面,规定:在目录下不许有同名的类名,包括不同路径。key唯一
利用Map实现(Map<String,Object> key=beanName,Object=对象实例) - Dept getBean(“dept”),从容器中获取对象
- 创建对象关系(利用反射),获取对象的关系(利用注解@Autowired),在对象属性上标识一个注解@Autowired,代表这个对象需要设置关联关系。从map获取要的对象,然后利用反射设置进去。
- 增加一个注解@Autowired
- 通过反射获取注解,如果有这个注解的属性就设置对象管理,如果没有就不关联
2、IOC、DI(依赖注入/关联对象)实现
package javapro.spring.util;
import javapro.spring.annotation.Autowired;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ComponentScanParser {
static Map<String, Object> beans = new HashMap<>();
public static Object getBean(String beanName) {
return beans.get(beanName);
}
public static void config(String packagePath) throws Exception {
List<String> listClassName = new ArrayList<>();
FileUtil.readClassName(packagePath, listClassName);
System.out.println("包扫描");
for (String className : listClassName) {
System.out.println(className);
Class<?> clazz = Class.forName(className);
Object instance = clazz.newInstance();
String beanName = FileUtil.getBeanName(className);
beans.put(beanName, instance);
}
}
public static void inject() throws IllegalAccessException {
for (String beanName : beans.keySet()) {
Object bean = getBean(beanName);
Class<?> clazz = bean.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
Autowired autowired = field.getDeclaredAnnotation(Autowired.class);
if (autowired != null) {
Object relationObject = getBean(field.getName());
field.setAccessible(true);
field.set(bean, relationObject);
}
}
}
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
String value() default "";
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
String value() default "";
}
package javapro.spring.run;
import javapro.spring.annotation.ComponentScan;
import javapro.spring.classes.Hello;
import javapro.spring.util.ComponentScanParser;
import java.net.URL;
@ComponentScan("javapro.spring.classes")
public class Run {
public static void main(String[] args) throws Exception{
Run run = new Run();
Class<?> clazz = run.getClass();
String path = clazz.getResource("/").getPath();
ComponentScan componentScan = clazz.getDeclaredAnnotation(ComponentScan.class);
String value = componentScan.value();
if (value != null) {
String packageName = value.replaceAll("\\.", "/");
String packagePath = path + packageName;
ComponentScanParser.config(packagePath);
Hello hello = (Hello)ComponentScanParser.getBean("hello");
hello.hi();
ComponentScanParser.inject();
System.out.println(ComponentScanParser.getBean("emp").toString());
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗