从零写一个具有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.容器的创建以及容器成员的增删查改_第1张图片

2.2 增加ClassUtil#newInstance方法

2.2.1 ClassUtil#newInstance需要完成的代码如下:
    /**
     * 实例化class
     *
     * @param clazz
     * @param accessible 是否可以通过反射来访问该class的private修饰的构造函数
     * @param 
     * @return
     */
    public static  T newInstance(Class 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张图片

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. 第二部分工作

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, Object> beanMap = new ConcurrentHashMap<>();

    /**
     * 注解列表
     */
    private static final List> 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> classSet = ClassUtil.extractPackageClass(packageName);
        if (ValidationUtil.isEmpty(classSet)) {
            log.warn("extract nothing from packageName" + packageName);
        }

        for (Class clazz : classSet) {

            for (Class 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> getClasses() {
        return beanMap.keySet();
    }

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


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

        Set> keySet = getClasses();

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

        // 通过注解筛选出符和条件的Class对象
        Set> 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> getClassesBySuper(Class interfaceOrClass) {

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

        // 判断ketSet里的元素是否是传入的接口的实现类或者是类的子类, 如果是,就添加到集合中
        Set> 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.容器的创建以及容器成员的增删查改_第4张图片

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

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

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

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

你可能感兴趣的:(java,spring)