实现简易版Spring的IOC容器

一、了解IOC

  • 依赖一个类似工厂的IOC容器
  • 将对象的创建、依赖关系的管理以及生命周期交由IOC容器管理
  • 降低系统在实现上的复杂性和耦合度,易于扩展,满足开闭原则

依赖注入DI,上层控制下层

image.png

image.png

image.png

依赖注入的方式

  • Setter
  • Interface
  • Constructor
  • Annotation

image.png

IOC容器优势

  • 避免在各处使用new来创建类,并且可以做到统一维护
  • 创建实例的时候不需要了解其中的细节
  • 反射+工厂模式的合体,满足开闭原则

二、IOC容器的实现

需要实现的点:

image.png

  • 提取标记对象

    • 指定范围,获取范围内的所有类

      • 使用类加载器

image.png

image.png

    • 遍历所有类,获取被注解标记的类并加载进容器里
  • 实现容器

    • 容器的组成部分

      • 保存Class对象及其实例的载体
    • 容器的加载 的实现思路

      • 配置的管理与获取–使用ConcurrentHashMap进行实例存储
      • 获取指定范围内的Class对象
      • 依据配置提取Class对象,连同实例一并存入容器

代码实例

Bean容器实现代码

/**
 * @NoArgsConstructor(创建一个没有参数的构造器)
 * @author :LY
 * @date :Created in 2021/4/5 11:23
 * @modified By:
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BeanContainer {
    /**
     * ConcurrentHashMap并发性好,jdk1.8后进行了大改进,摒弃了分段锁概念,利用了cas和红黑树来细化锁的粒度和提升扩容效率,进一步提升并发性能
     * 存放所有被配置标记的目标对象的Map
     */
    private final Map<Class<?>,Object> beanMap = new  ConcurrentHashMap();
    /**
     * 加载bean的注解列表
     */
    private static final List<Class<? extends Annotation>> BEAN_ANNOTATION
            = Arrays.asList(Component.class, Controller.class, Service.class, Repository.class);
    /**
     * 获取Bean容器实例
     * @return
     */
    public static BeanContainer getInstance(){
        return ContainerHolder.HOLDER.instance;
    }
    private enum ContainerHolder{
        HOLDER;
        private BeanContainer instance;
        //默认是private访问权限
        ContainerHolder(){
            instance = new BeanContainer();
        }
    }
    /**
     * 容器是否已经被加载过
     */
    private boolean loaded = false;
    /**
     * 是否加载该Bean
     * @return 是否已加载
     */
    public boolean isLoaded(){
        return loaded;
    }
    /**
     * Bean实例数量
     * @return 数量
     */
    public int size(){
        return beanMap.size();
    }
    /**
     * 扫描加载所有Bean
     * @param packageName 包名
     */
    public synchronized void loadBeans(String packageName){
        //判断bean容器是否被加载过
        if (isLoaded()){
            log.warn("BeanContainer has been loaded.");
            return;
        }
        Set<Class<?>> classSet = ClassUtil.extractPackageClass(packageName);
        if (ValidationUtil.isEmpty(classSet)){
            log.warn("extract nothing from packageName " + packageName);
            return;
        }
        //lambda表达式,等价于foreach
        classSet.forEach(clazz->{
            BEAN_ANNOTATION.forEach(annotation ->{
                //如果类上标记了定义的注解
                if (clazz.isAnnotationPresent(annotation)){
                    //将目标本身作为键,目标类的实例作为值,放入到beanMap中
                    beanMap.put(clazz,ClassUtil.newInstance(clazz,true));
                }
            });
        });
        loaded = true;
    }
}

测试提取类

    @DisplayName("加载目标类及其实例到BeanContainer : loadBeansTest")
    @Test
    public void loadBeansTest(){
        Assertions.assertEquals(false,beanContainer.isLoaded());
        beanContainer.loadBeans("com.w2cs");
       Assertions.assertEquals(6,beanContainer.size());
        Assertions.assertEquals(true,beanContainer.isLoaded());
    }

测试通过

image.png

  • 容器的操作方式

    • 增加、删除操作
    • 根据Class获取对应实例
    • 获取所有的Class和实例
    • 通过注解来获取被注解标注的Class
    • 通过超类获取对应的子类Class
    • 获取容器载体保存Class的数量

容器操作代码

    /**
     * 添加一个class对象及其Bean实例
     * @param clazz Class对象
     * @param bean Bean实例
     * @return 原有的Bean实例,没有则返回null
     */
     public Object addBean(Class<?> clazz,Object bean){
        return beanMap.put(clazz,bean);
     }  
    /**
     * 移除一个IOC容器管理的对象
     * @param clazz Class对象
     * @return 删除的Bean实例,没有则返回null
     */
     public Object removeBean(Class<?> clazz){
         return beanMap.remove(clazz);
     }
    /**
     * 根据Class对象湖区Bean实例
     * @param clazz Class对象
    * @return Bean实例
     */
     public Object getBean(Class<?> clazz){
         return beanMap.get(clazz);
     }
    /**
     * 获取容器管理的所有Class对象集合
     * @return Class集合
     */
     public Set<Class<?>> getClasses(){
         return beanMap.keySet();
     }
    /**
     * 获取所有Bean集合
     * @return Bean集合
     */
     public  Set<Object> getBean(){
         return new HashSet<>(beanMap.values()) ;
     }
    /**
     * 根据注解筛选出Bean的Class集合
     * @param annotation 注解
     * @return Class集合
     */
     public Set<Class<?>> getClassesByAnnotation(Class<? extends Annotation> annotation){
         //1.获取beanMap的所有class集合
         Set<Class<?>> keySet = getClasses();
         if (ValidationUtil.isEmpty(keySet)){
             log.warn("noting in beanMap");
             return null;
         }
         //2.通过注解筛选被注解标记的class对象,并添加到classSet里
         Set<Class<?>> classSet = new HashSet<>();
         keySet.forEach(clazz->{
             //类是否有相关的注解标记
             if (clazz.isAnnotationPresent(annotation)){
                 classSet.add(clazz);
             }
         });
         return classSet.size()>0?classSet:null;
     }
    /**
     * 通过接口或者父类获取实现类或者子类的Class集合,不包括其本身
     * @param interfaceOrClass 接口或者父类Class
     * @return Class集合
     */
    public Set<Class<?>> getClassesBySuper(Class<?> interfaceOrClass){
        //1.获取beanMap的所有class集合
        Set<Class<?>> keySet = getClasses();
        if (ValidationUtil.isEmpty(keySet)){
            log.warn("noting in beanMap");
            return null;
        }
        //2.判断keySet里的元素是否是传入的接口或者类的子类,如果是,并添加到classSet里
        Set<Class<?>> classSet = new HashSet<>();
        keySet.forEach(clazz->{
            //判断keySet里的元素是否是传入的接口或者类的子类
            if (interfaceOrClass.isAssignableFrom(clazz) && !clazz.equals(interfaceOrClass)){
                classSet.add(clazz);
            }
        });
        return classSet.size() > 0 ? classSet : null;
    }
  • 实现容器的依赖注入(目前容器里面管理的Bean实例仍可能是不完备的)
    • 实例里面某些必须的成员变量还没有创建

    • 实现思路

      • 定义相关的注解标签
      • 实现创建被注解标记的成员变量实例,并将其注入到成员变量里
      • 依赖注入的使用(暂时只支持成员变量的注入)

代码

/**
 * @author :LY
 * @date :Created in 2021/4/6 16:47
 * @modified By:
 */
@Slf4j
public class DependencyInjector {

    /**
     * Bean容器
     */
    private BeanContainer beanContainer;
    public DependencyInjector(){
        //获取容器实例
        beanContainer = BeanContainer.getInstance();
    }

    /**
     * 执行依赖注入 通过类型注入
     */
    public void doIoc(){
        //1.遍历Bean容器中所有的Class对象
        if (ValidationUtil.isEmpty(beanContainer.getClasses())){
            log.warn("empty classes in BeanContainer");
            return;
        }
        for (Class<?> clazz : beanContainer.getClasses()){
            //2.遍历Class对象的所有成员变量
            Field[] fields = clazz.getDeclaredFields();
            if (ValidationUtil.isEmpty(fields)){
                continue;
            }
            for (Field field : fields) {
                //3.找出被Autowired标记的成员变量
                if (field.isAnnotationPresent(Autowired.class)){
                    Autowired autowired = field.getAnnotation(Autowired.class);
                    String autowiredValue = autowired.value();
                    //4.获取这些成员变量的类型
                    Class<?> fieldClass = field.getType();
                    //5.获取这些成员变量的类型在容器里对应的实例
                    Object fieldValue = getFieldInstance(fieldClass,autowiredValue);
                    if (fieldValue == null){
                        throw new RuntimeException("unable to inject relevant type , target fieldClass is:" + fieldClass.getName());
                    }else {
                        //6.通过反射将对应的成员变量实例注入到成员变量所在类的实例里
                        Object targetBean = beanContainer.getBean(clazz);
                        ClassUtil.setField(field,targetBean,fieldValue,true);
                    }
                }
            }
        }
    }
    /**
     * 从容器中获取实例对象
     * @param fieldClass 实例类型
     * @param autowiredValue 指定具体实现 在接口拥有多个实现时需要指定
     * @return
     */
    private Object getFieldInstance(Class<?> fieldClass,String autowiredValue) {
        Object fieldValue = beanContainer.getBean(fieldClass);
        if (fieldValue != null){
            return fieldValue;
        }else {
            //如果是接口的话,获取它的实现类类型
            Class<?> implementedClass = getImplementClass(fieldClass,autowiredValue);
            if (implementedClass != null){
                return beanContainer.getBean(implementedClass);
            }else {
                return null;
            }
        }
    }
    /**
     * 获取接口
     * @param fieldClass
     * @return
     */
    private Class<?> getImplementClass(Class<?> fieldClass,String autowiredValue) {
        Set<Class<?>> classSet = beanContainer.getClassesBySuper(fieldClass);
        if (!ValidationUtil.isEmpty(classSet)){
            //出现多个实现类
            if (ValidationUtil.isEmpty(autowiredValue)){
                //用户没告诉具体实现类,有以下几种情况
                if (classSet.size() == 1){
                    //容器里只有一个实现类,直接返回
                    return classSet.iterator().next();
                }else {
                    //容器里有多个,用户并未指定实现类,则抛出异常
                    throw new RuntimeException("multipe implemented classes for "+ fieldClass.getName()+" please set @Autowired's value to pick one");
                }

            }else {

                for (Class<?> clazz : classSet) {
                    if (autowiredValue.equals(clazz.getSimpleName())){
                        //获取到用户指定的实例
                        return clazz;
                    }
                }

            }
        }
        return null;
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值