手写简单IoC容器

学习 Spring,跟着二哥简单写个 IoC 容器。 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface MyAutowired { } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface MyComponent { } public class SimpleIoC { Map<Class<?>, Object> beans = new HashMap<>(); //扫描 public void scan(String packageName) { List<Class<?>> classes = getClassesInPackage(packageName); for (Class<?> clazz : classes) { if (clazz.isAnnotationPresent(MyComponent.class)) { registerBean(clazz); } } di(); } //获取包下的类,简化实现 private List<Class<?>> getClassesInPackage(String packageName) { // 实际实现需要扫描classpath,这里简化处理. return Arrays.asList(UserDao.class, UserService.class); } //注册bean private void registerBean (Class<?> clazz) { try { Object instance = clazz.getDeclaredConstructor().newInstance(); beans.put(clazz, instance); } catch (Exception e) { throw new RuntimeException("创建bean失败"); } } //获取bean @SuppressWarnings("unchecked") public <T> T getBean(Class<T> clazz) { return (T)beans.get(clazz); } //依赖注入 private void di() { for (Object bean : beans.values()) { Field[] fields = bean.getClass().getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(MyAutowired.class)) { field.setAccessible(true); Object dependency = getBean(field.getType()); try { field.set(bean, dependency); } catch (Exception e) { throw new RuntimeException("依赖注入失败"); } } } } } } //DAO层 @MyComponent class UserDao { public void save(String user) { System.out.println("保存用户: " + user); } } // Service层 @MyComponent class UserService { @MyAutowired private UserDao userDao; public void createUser(String name) { userDao.save(name); System.out.println("用户创建完成"); } } class Test { public static void main(String[] args) { SimpleIoC ioc = new SimpleIoC(); ioc.scan("package"); UserService bean = ioc.getBean(UserService.class); bean.createUser("dong"); } } 参考链接: ...

March 7, 2026 · 1 分钟 · 210 字 · Me

Java反射

什么是反射 在spring项目中,只需要写个@Service或者@Component,然后在别的地方用@Autowired声明一个接口变量,Spring就能返回给我们一个实现了该接口的具体对象。这是如何实现的呢?它不可能在编译时就知道加了注解的类与类之间的关系,所以只能是在程序启动运行时,Spring动态地发现了这些类,读取了他们的结构,然后创建对象。这背后的技术支撑又是什么?答案就是反射。 反射是Java提供的一种在程序运行时 检查/获取类、接口、字段、方法、构造器等结构信息的能力。 操作/调用对象、字段、方法的能力。 它就像一面镜子,让程序在运行时“照见”自己的结构。 反射的基石:Class对象 编译器在编译 Java 源代码时会生成 .class 文件(字节码文件)。当 JVM 需要用到某个类时,它的类加载器会读取并解析对应的 .class 文件,在方法区(或元空间)构建该类的运行时数据结构,同时在堆内存中创建一个代表该类的 java.lang.Class 对象。每个被加载的类在 JVM 中都有且只有一个对应的 Class 对象(在同一个类加载器命名空间内)。 这里的Class是一个类的名字,不要和class关键字搞混。 有三种方法获取Class对象 Person person = new Person("me", 20); //法一:通过对象实例 Class< ? extends Person> clazz1 = person.getClass(); //法二:自带属性(基本数据类型也有) Class<Person> clazz2 = Person.class; //法三:Class类的静态方法 forName try { Class<?> clazz3 = Class.forName("org.myblog.reflection.Person"); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } 解释一下这三种方法泛型的使用:法一使用Class<? extends Person> 因为Class对象是在运行时从Person实例获取的,而Person实例的具体类型只能在运行时创建和确定,编译阶段无法判断,所以使用通配符 ,又因为person可能是Person实例,也可能是Person的子类实例,所以最终写成Class< ? extends Person>;法二使用Class<Person>因为编译时已知具体类型;法三使用Class<?>因为通过字符串动态加载类,编译时无法确定具体类型,所以使用通配符。这三个 Class 对象都是同一个(上面也提到了,一个类唯一对应一个 Class 对象)。 ...

August 10, 2025 · 3 分钟 · 518 字 · Me