从零写一个具有IOC-AOP-MVC功能的框架—学习笔记—04.容器的创建以及容器成员的增删查改

1. 本节需要完成的内容

  1. 新建@Aspect注解
  2. 增加ClassUtil#newInstance方法来通过Class对象新建一个真正的实例对象
  3. 增加ValidationUtil类作为参数校验类
  4. 编写BeanContainer类以及其内部方法: 完成容器的创建以及增删查改操作

2. 第一部分工作

2.1 该部分需要完成的内容:

  1. 新建@Aspect注解
  2. 增加ClassUtil#newInstance方法
  3. 编写@ValidationUtils校验类

2.2 新建@Aspect注解

说明: 因为我们后续的AOP功能实现时,需要扫描被@Aspect注解标记的类,并放入容器中,所以我们这里就提前新建@Apspect注解

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---04.容器的创建以及容器成员的增删查改

2.2 增加ClassUtil#newInstance方法

2.2.1 ClassUtil#newInstance需要完成的代码如下:

/**
     * 实例化class
     *
     * @param clazz
     * @param accessible 是否可以通过反射来访问该class的private修饰的构造函数
     * @param <T>
     * @return
     */
    public static <T> T newInstance(Class<T> clazz, boolean accessible) {
        try {
            Constructor constructor = clazz.getDeclaredConstructor();
            constructor.setAccessible(accessible); // 防止获取到的是private类型的构造函数
            return (T) constructor.newInstance();
        } catch (Exception e) {
            log.error("newInstance error", e);
            throw new RuntimeException(e);
        }
    }

2.2.5 ClassUtil#newInstance方法解读

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---04.容器的创建以及容器成员的增删查改

2.3 编写ValidationUtil类

2.3.1 需要完成的代码如下

package com.wuyiccc.helloframework.util;

import java.util.Collection;
import java.util.Map;

/**
 * @author wuyiccc
 * @date 2020/7/13 10:41
 * 岂曰无衣,与子同袍~
 */
public class ValidationUtil {

    /**
     * String是否为null或者""
     *
     * @param obj
     * @return
     */
    public static boolean isEmpty(String obj) {
        return obj == null || "".equals(obj);
    }


    /**
     * java的数组是否为null或者size=0
     *
     * @param obj
     * @return
     */
    public static boolean isEmpty(Object[] obj) {
        return obj == null || obj.length == 0;
    }


    /**
     * 判断Collection是否为null或者size=0
     *
     * @param obj
     * @return 是否为空
     */
    public static boolean isEmpty(Collection<?> obj) {
        return obj == null || obj.isEmpty();
    }

    /**
     * Map是否为null 或 size 为0
     * @param obj
     * @return
     */
    public static boolean isEmpty(Map<?, ?> obj) {
        return obj == null || obj.isEmpty();
    }
}

2.3.2 ValidationUtil代码解读:

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---04.容器的创建以及容器成员的增删查改

3. 第二部分工作

3.1 该部分需要完成的内容

  1. 完成BeanContainer类的编写
  2. BeanContainer类所具有的主要功能:加载指定包路径下的bean,通过注解筛选出Bean的Class对象集合,通过接口或者父类获取实现类或者子类的Class集合

3.2 该部分需要完成的代码如下

package com.wuyiccc.helloframework.core;

import com.wuyiccc.helloframework.aop.annotation.Aspect;
import com.wuyiccc.helloframework.core.annotation.Component;
import com.wuyiccc.helloframework.core.annotation.Controller;
import com.wuyiccc.helloframework.core.annotation.Repository;
import com.wuyiccc.helloframework.core.annotation.Service;
import com.wuyiccc.helloframework.util.ClassUtil;
import com.wuyiccc.helloframework.util.ValidationUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.lang.annotation.Annotation;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author wuyiccc
 * @date 2020/7/13 10:19
 * 岂曰无衣,与子同袍~
 */

@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BeanContainer {


    /**
     * 存放所有被配置标记的目标对象的Map
     */
    private final Map<Class<?>, Object> beanMap = new ConcurrentHashMap<>();

    /**
     * 注解列表
     */
    private static final List<Class<? extends Annotation>> BEAN_ANNOTATION = Arrays.asList(Component.class, Controller.class, Service.class, Repository.class, Aspect.class);

    /**
     * 容器是否已经加载过bean
     */
    private boolean loaded = false;

    /**
     * 获取Bean容器实例
     *
     * @return BeanContainer
     */
    public static BeanContainer getInstance() {
        return ContainerHolder.HOLDER.instance;
    }

    private enum ContainerHolder {
        HOLDER;
        private BeanContainer instance;

        ContainerHolder() {
            instance = new BeanContainer();
        }
    }

    /**
     * Bean实例数量
     *
     * @return
     */
    public int size() {
        return beanMap.size();
    }

    public boolean isLoaded() {
        return loaded;
    }

    /**
     * 加载指定packageName包括其子包下的bean
     *
     * @param packageName
     */
    public synchronized void loadBeans(String packageName) {

        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);
        }

        for (Class<?> clazz : classSet) {

            for (Class<? extends Annotation> annotation : BEAN_ANNOTATION) {

                if (clazz.isAnnotationPresent(annotation)) {
                    beanMap.put(clazz, ClassUtil.newInstance(clazz, true));
                    break;
                }
            }
        }
        loaded = true;
    }


    /**
     * 添加一个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
     * @return
     */
    public Object getBean(Class<?> clazz) {
        return beanMap.get(clazz);
    }


    /**
     * 获取容器管理的所有Class对象集合
     *
     * @return
     */
    public Set<Class<?>> getClasses() {
        return beanMap.keySet();
    }

    /**
     * 获取所有的Bean集合
     *
     * @return Bean集合
     */
    public Set<Object> getBeans() {
        return new HashSet<>(beanMap.values());
    }


    /**
     * 根据注解筛选出Bean的Class对象集合
     *
     * @param annotation 注解
     * @return Class集合
     */
    public Set<Class<?>> getClassesByAnnotation(Class<? extends Annotation> annotation) {

        Set<Class<?>> keySet = getClasses();

        if (ValidationUtil.isEmpty(keySet)) {
            log.error("nothing in beanMap");
            return null;
        }

        // 通过注解筛选出符和条件的Class对象
        Set<Class<?>> classSet = new HashSet<>();
        for (Class<?> clazz : keySet) {
            // 检查Class对象是否有相关的注解标记
            if (clazz.isAnnotationPresent(annotation)) {
                classSet.add(clazz);
            }
        }
        return classSet.size() > 0 ? classSet : null; // 统一定义,如果size==0 ,那么返回null 而不是空的classSet
    }


    /**
     * 通过接口或者父类获取实现类或者子类的Class集合,不包括其本身
     * @param interfaceOrClass 接口Class或者父类Class
     * @return Class集合
     */
    public Set<Class<?>> getClassesBySuper(Class<?> interfaceOrClass) {

        // 获取beanMap中所有class对象
        Set<Class<?>> keySet = getClasses();
        if (ValidationUtil.isEmpty(keySet)) {
            log.warn("nothing in beanMap");
            return null;
        }

        // 判断ketSet里的元素是否是传入的接口的实现类或者是类的子类, 如果是,就添加到集合中
        Set<Class<?>> classSet = new HashSet<>();
        for (Class<?> clazz : keySet) {
            if (interfaceOrClass.isAssignableFrom(clazz) && !clazz.equals(interfaceOrClass)) { // 判断interfaceOrClass是否是clazz父级别的类
                classSet.add(clazz);
            }
        }
        return classSet.size() > 0 ? classSet : null;
    }




}

3.3 相关代码讲解如下

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---04.容器的创建以及容器成员的增删查改

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---04.容器的创建以及容器成员的增删查改

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---04.容器的创建以及容器成员的增删查改

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---04.容器的创建以及容器成员的增删查改

github地址: https://github.com/wuyiccc/he…

原文 

https://segmentfault.com/a/1190000023204595

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » 从零写一个具有IOC-AOP-MVC功能的框架—学习笔记—04.容器的创建以及容器成员的增删查改

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址