面试官可能会问你IOC的原理,如果你回答:我手动实现过Spring的IOC呢?

你好,我是风一样的树懒,一个工作十多年的后端开发,曾就职京东、阿里等多家互联网头部企业。

点击下方👇关注公众号,带你一起复习后端技术,看看面试考点,补充积累技术知识,每天都为面试准备积累

如何自己实现一个简单的 Java IOC(Inversion of Control)容器,可以通过以下步骤来完成:


01
IOC的核心功能


  • Bean 定义和管理:使用注解或 XML 定义 Bean。

  • 依赖注入:支持构造函数注入和属性注入。

  • Bean 的生命周期管理:支持单例模式的 Bean。


02
示例代码


Step 1: 创建注解

定义注解用于标记组件和注入点。

// 标记为组件@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface Component {    String value() default "";}// 标记为自动注入@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface Autowired {}

Step 2: 定义一个简单的 IOC 容器

实现一个核心容器来扫描和管理 Bean。

import java.lang.reflect.Field;import java.util.HashMap;import java.util.Map;public class SimpleIOC {    private Map<String, Object> beanContainer = new HashMap<>();    public SimpleIOC(String packageName) throws Exception {        // 扫描包路径并初始化 Bean        scanPackage(packageName);    }    private void scanPackage(String packageName) throws Exception {        // 使用类加载器获取包路径下的所有类(这里可以用 ClassLoader 或第三方库)        // 为简化,假设扫描到了两个类:UserService 和 UserRepository        // 示例:手动注册 Bean(模拟扫描)        Class<?> userServiceClass = UserService.class;        Class<?> userRepositoryClass = UserRepository.class;        // 创建 Bean 并加入容器        registerBean(userServiceClass);        registerBean(userRepositoryClass);        // 依赖注入        autowireDependencies();    }    private void registerBean(Class<?> clazz) throws Exception {        if (clazz.isAnnotationPresent(Component.class)) {            Component component = clazz.getAnnotation(Component.class);            String beanName = component.value();            if (beanName.isEmpty()) {                beanName = clazz.getSimpleName();            }            Object instance = clazz.getDeclaredConstructor().newInstance();            beanContainer.put(beanName, instance);        }    }    private void autowireDependencies() throws Exception {        for (Object bean : beanContainer.values()) {            Field[] fields = bean.getClass().getDeclaredFields();            for (Field field : fields) {                if (field.isAnnotationPresent(Autowired.class)) {                    // 找到需要注入的类型                    Class<?> fieldType = field.getType();                    Object dependency = findBeanByType(fieldType);                    if (dependency == null) {                        throw new Exception("No bean found for type: " + fieldType.getName());                    }                    // 注入依赖                    field.setAccessible(true);                    field.set(bean, dependency);                }            }        }    }    private Object findBeanByType(Class<?> type) {        for (Object bean : beanContainer.values()) {            if (type.isAssignableFrom(bean.getClass())) {                return bean;            }        }        return null;    }    public Object getBean(String name) {        return beanContainer.get(name);    }}

Step 3: 定义业务类

模拟服务和存储层。

@Component("userService")public class UserService {    @Autowired    private UserRepository userRepository;    public void printUser() {        System.out.println("User: " + userRepository.getUser());    }}@Component("userRepository")public class UserRepository {    public String getUser() {        return "John Doe";    }}

Step 4: 使用 IOC 容器

测试 IOC 容器的初始化和使用。

public class Main {    public static void main(String[] args) throws Exception {        // 初始化 IOC 容器        SimpleIOC ioc = new SimpleIOC("com.example");        // 获取 Bean        UserService userService = (UserService) ioc.getBean("userService");        // 调用方法        userService.printUser(); // 输出: User: John Doe    }}


03
功能总结


@Component:标记一个类为 Bean。

@Autowired:支持字段的自动注入。

容器实现:

  • Bean 注册:扫描标记为 @Component 的类。

  • 依赖注入:通过反射为 @Autowired 标记的字段注入依赖。


04
4. 优化建议


  • 扫描类:可以用 ClassLoader 动态扫描包路径。

  • 注入方式:支持构造器注入和方法注入。

  • Bean 生命周期:实现单例、多例模式支持。

  • 扩展支持:添加 AOP、事件机制等。


今天的内容就分享到这儿,喜欢的朋友可以关注,点赞。有什么不足的地方欢迎留言指出,您的关注是我前进的动力!

END


扫码关注

一起积累后端知识
不积跬步,无以至千里
不积小流,无以成江海

喜欢此内容的人还喜欢

谈谈id那些事(五)——美团的 Leaf 的ID生成


一个阿里二面面试官必问的问题


Lambda表达式说爱你不容易


分享面试:mysql数据库索引失效的情况


Spring-Boot中一个不起眼的好工具StopWatch