简单模拟SpringIOC的怎么创建对象和获取对象

本文介绍了一个简单的IOC容器实现过程,包括添加依赖、包扫描、创建注解、容器工厂及处理器等核心组件的设计与编码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

废话不多说直接上代码

实现步骤流程

  1. 添加包对应的依赖
  2. 编写包扫描工具
  3. 编写注解来创建对象
  4. 编写容器工厂
  5. 编写处理器的接口
  6. 编写字段处理器
  7. 编写方法处理器(可以通过字段或方法注入)
  8. 编写上下文对象 (进行解耦,不让容器工厂强行依赖某个具体的实现)
  9. 测试

1、添加包对应的依赖


    <dependencies>
        <!-- 包扫描工具 -->
        <dependency>
            <groupId>io.github.classgraph</groupId>
            <artifactId>classgraph</artifactId>
            <version>4.8.149</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

2、编写包扫描工具

public class ScanUtils{
    
    public static ClassInfoList scan(String className){

         // 创建对象
        ClassGraph cg = new ClassGraph();
        // 扫描对应的表返回结果集
        ScanResult scanResult = cg.acceptPackages(packageName).scan();
        // 返回结果集中所有的类
        return scanResult.getAllClasses();
    }
}

3、编写注解来创建对象

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
    /**
     * 这个value属性就是容器中的id
     * @return
     */
    String value();

    /**
     * bean的创建方式 (单例还是原型)
     * 默认为单例
     * @return
     */
    String scope() default "singleton";
}

4、编写容器工厂

public class ContainerFactory{

    // 容器工厂单例
    private Map<String,Object> singletonMap = new HashMap<>();

    // 容器工厂原型
    private Map<String,Class<?>> prototypeMap = new HashMap<>();

     
}

5、编写处理器的接口

public interface InjectHandler {
    /**
     * 对对象进行赋值
     * @param target
     * @param factory
     */
    void handle(Object target,ContainerFactory factory);
}

6、编写字段处理器

public class FieldInjectHandler implements InjectHandler{
    /**
     * 处理类字段的注入逻辑
     * @param target 需要注入的实例
     * @Param factory 当前工厂
     */
    @Override
    public void handle(Object target,ContainerFactory factory){
        // 先得到实例的Class对象
        Class<?> clazz = target.getClass();
        // 获取所有私有字段
        Field[] fields = clazz.getDeclaredFields();
        // 循环遍历这些字段查看是否带有@Resource注解
        for (Field field : fields) {
            if (field.isAnnotationPresent(Resource.class)) {
                // 找到需要注入的对象的id
                String id = field.getAnnotation(Resource.class).name();
                // 根据id从容器工厂中取出这个实例并赋值给这个Field字段
                Object property = factory.getBean(id);
                // 将对象赋值给field完成注入
                setField(field,property,target);
            }
        }
    }

    /**
     *
     * @param field
     * @param property
     * @param target
     */
    private void setField(Field field,Object property,Object target){
        // 判断访问开放是否打开
        if (!field.isAccessible()){
            // 打开访问开关
            field.setAccessible(true);
        }
        try {
            // 给字段注入
            field.set(target,property);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Inject property fail",e);
        }
    }

    /*
    * private UserService userService;
    * 通过set方法赋值
    * public void set(Object obj,Object value )
    * 参数一: 当前类对象
    * 参数二: 需要赋值的属性
    * */
}

7、编写方法处理器

public class MethodInjectHandler implements InjectHandler{
    @Override
    public void handle(Object target, ContainerFactory factory) {
        // 获取class对象
        Class<?> clazz = target.getClass();
        // 获取当前类的所有方法
        Method[] methods = clazz.getDeclaredMethods();
        // 遍历所有的方法判断是否有@Resource注解
        for (Method method : methods){
            // 判断method是否有@Resource注解
            if (method.isAnnotationPresent(Resource.class)){
                // 获取这个方法上注解的所有信息
                String name = method.getAnnotation(Resource.class).name();
                // 获取注解上值对应的实现类
                Object obj =factory.getBean(name);
                // 调用方法将值注入进去
                setMethod(method,target,obj);
            }
        }
    }

    private void setMethod(Method method,Object target,Object prototype){
        try {
            method.invoke(target,prototype);
        } catch (Exception e) {
            throw new RuntimeException("method set 参数 fail!",e);
        }
    }
}

8、编写方法处理器

public class InjectHandlerContext {
    /**
     * 用于保存 InjectHandler父类的 实现类进行赋值
     */
    private List<InjectHandler> handlers = new ArrayList<>();

    public InjectHandlerContext(){
        // 将处理器
        handlers.add(new FieldInjectHandler());
        handlers.add(new MethodInjectHandler());
    }

    /**
     *
     * @param target
     * @param factory
     * @return
     */
    public void handle(Object target,ContainerFactory factory){
     // 通过循环的方式进行赋值 如果类上的字段有@Resource注解则通过字段进行赋值
     // 通过循环的方式进行赋值 如果类上的方法有@Resource注解则通过方法进行赋值
        for (InjectHandler handle:handlers){
            handle.handle(target,factory);
        }
    };
}

9、测试

此处只给截图了

目录结构

MVC三层架构

 

 Conponent注解的value就是容器中的key,如果没用Scope则是单例。

在字段中设置@Resource注解或在字段中设置@Resource注解都可以 但是name的值必须是serviceImpl的@Component注解的vlaue值 不然会找不到实例,而注入失败,最后这里回事一个递归的操作,从Controller一直到Dao没用需要依赖的字段set方法.......

大概就是这样子要源码的可以私信!!!!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值