自研Spring容器,带你解析ioc内部原理

spring设计架构

image-20210507104401379"

Test:测试模块

Core container :核心模块

Beans :将对象设置成Beans,Core核心工具类,Context上下文将Beans和Core组装运行环境,SpEL表达式语言

Aop :将java中动态代理为基础一系列横线切面

Data:操作数据库

Web:web组件开发支持

Jsp实现原理

image-20210507104431631

日志

image-20210507104543925

Url

image-20210507104625929

反射

image-20210507104634579

三种获取Class方法

https://www.cnblogs.com/wwjj4811/p/12539804.html

注解

image-20210507104336449

自研框架-前传

image-20210507104314083

自研框架-ioc

注解怎么创建?

image-20210507104303164

ioc容器怎么拿到对象名?
package org.simpleframework.utils;

import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
@Slf4j
public class ClassUtil {

    public static Set<Class<?>> exractPackClass(String packgeName){

        获取当前线程的类加载器
        ClassLoader classLoder = getClassLoder();

        //通过类加载器获取到加载的资源
        URL url = classLoder.getResource(packgeName.replace(".", "/"));
        if (url == null) {
            log.warn("获取不到url"+packgeName);
            return null;
        }
        //依据不同资源类型,采用不用方式获取
        Set<Class<?>> classSet = null;

        //过滤出文件类型的资源
        if(url.getProtocol().equalsIgnoreCase("file")){//对比不区分大小写
           classSet = new HashSet<Class<?>>();
            File packageDiectory = new File(url.getPath());
            extractClassFile(classSet,packageDiectory,packgeName);
        }

        return classSet;


    }

    /***
     * 递归获取目标package里面所有class文件
     * @param classSet
     * @param packageDiectory
     * @param packgeName
     */
    private static void extractClassFile(Set<Class<?>> classSet, File packageDiectory, String packgeName) {
        //递归终止点,当递归到文件的时候就退出
        if (!packageDiectory.isDirectory()){
            return;
        }

        File[] files = packageDiectory.listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                //ava中的isDirectory()是检查一个对象是否是文件夹。返回值是boolean类型的。如果是则返回true,否则返回false
                if (file.isDirectory()){
                    return true;
                }else {
                    //获取文件绝对值路劲
                    String absolutePath = file.getAbsolutePath();
                    if (absolutePath.endsWith(".class")){
                        
                        //获取到绝对值路径后将通过反射加入
                        addToClassSet(absolutePath);
                    }
                    
                }
                return false;
            }

            //将Class文件的绝对值路径。获取生成class对象,并放入classSet中
            private void addToClassSet(String absolutePath) {
                //从class文件绝对值路径中提取包类名
                absolutePath = absolutePath.replace(File.separator, ".");
                String className = absolutePath.substring(absolutePath.indexOf(packgeName));
                className = className.substring(0,className.lastIndexOf("."));
                //通过反射将对象名拿出来
                Class<?> aClass = loadClass(className);
                classSet.add(aClass);
            }
        });

        if (files != null){
            for (File f: files) {
                extractClassFile(classSet, f, packgeName);
            }
        }
    }

    public static ClassLoader getClassLoder(){
        //获取当前线程的类加载器
        return Thread.currentThread().getContextClassLoader();

    }

    public static Class<?> loadClass(String className){
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    //获取class类实例
    public static <T> T newInstance(Class<?> clazz,boolean accessible) {
        try {
            Constructor declaredConstructor = clazz.getDeclaredConstructor();
            declaredConstructor.setAccessible(accessible);
            return (T) declaredConstructor.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

    }

}

image-20210507104242518

根据实际路径获取class文件名存入set集合

容器单例输出安全吗?

image-20210508170005287

开始创建容器吧!!

package org.simpleframework.core;

import com.sun.corba.se.impl.io.ValueUtility;
import com.sun.deploy.util.StringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.simpleframework.core.annotation.Compoment;
import org.simpleframework.core.annotation.Controller;
import org.simpleframework.core.annotation.Repository;
import org.simpleframework.core.annotation.Service;
import org.simpleframework.utils.ClassUtil;

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

/**
 * @description:
 * @author: zhangyihan
 * @createDate: 2021-04-29 14:50
 * @version: 1.0
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BeanContainer {


    //检查容器是否被加载过
    private boolean load = false;


    /**
     *获取bean实例
     *
     * @return
     */

    public static BeanContainer getInstance(){
        return ContainerHolder.HOLDER.instance;
    }


    //设置单例方法,将对象存入HOLDER
    //使用枚举可以防止反射的入侵
    private enum ContainerHolder{

        HOLDER;
        private BeanContainer instance;

        ContainerHolder(){

            instance =new BeanContainer();
        }

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


    /**
     * 加载bean的注解列表
     *
     * @return
     */
    private static final List<Class<? extends Annotation>> BEAN_ANNOTATION=
            Arrays.asList(Compoment.class, Controller.class, Service.class, Repository.class);


    //判断是否被加载
    public boolean islocad(){
        return load;
    }
    /***
     *
     * 扫描所有的类名
     *
     */
   public synchronized void localBeans(String packName){

       if (islocad()){
           log.warn("bean容器已经被加载过了");
           return;
       }

       //获取当前线程的包名将class文件类名通过反射获取出来
       Set<Class<?>> classSet = ClassUtil.exractPackClass(packName);

       if (classSet == null || classSet.isEmpty()){
           log.warn("找不到包类名"+packName);

           return;
       }

       //将获取到的类名遍历出来
       for (Class aClass:classSet){

           //将标有注解的类循环遍历出来
          for (Class<? extends Annotation> beanClass : BEAN_ANNOTATION)
          {
              //判断是否加了那四个注解
              if (aClass.isAnnotationPresent(beanClass)){

                  //加了的话将类名本身作为减,实例作为值传入map之中
                  beanMap.put(aClass,ClassUtil.newInstance(aClass,true));
              }

          }


       }

       load = true ;

   }


    /***
     * 添加一个class对象及其实例
     *
     */

     public Object addBean(Class<?> clazz,Object bean){

         //map会返回传入值的对象
         Object o = beanMap.put(clazz, bean);
         return o;
     }

    /***
     * 删除一个容器管理对象
     *
     */
     public Object removeBean(Class<?> clazz){
         //根据名字删除,有值会返回删除值的类型,没就是null
         return beanMap.remove(clazz);
     }


    /***
     * 获取一个容器管理对象
     *
     */
    public Object getBean(Class<?> clazz){
        return beanMap.get(clazz);
    }



    /***
     * 获取容器管理所有对象
     *
     */
    public Set<Class<?>> getClasses(){
        //根据名字删除,有值会返回删除值的类型,没就是null
        return beanMap.keySet();
    }


    /***
     * 获取容器bean集合
     *
     */
    public Set<Object> getBeansValues(){
        //根据名字删除,有值会返回删除值的类型,没就是null
        return new HashSet<>(beanMap.values());
    }

    /***
     * 根据注解筛选出bean的class集合
     *
     */
    public Set<Class<?>> getClassByAnnotation(Class<? extends Annotation> annotation){
        //获取beanMap的所有class对象
        Set<Class<?>> keySet = getClasses();
        if (keySet == null || "".equals(keySet)){
           log.warn("nothing in beanMap");
           return null;
        }
        //通过注解筛选出class对象,并添加到set里
        Set<Class<?>> classSet = new HashSet<>();
        for(Class<?> clazz :keySet){
            if (clazz.isAnnotationPresent(annotation)){
                classSet.add(clazz);
            }
        }
        //统一返回值
        return classSet.size() > 0? classSet:null;
    }


    /***
     * 通过接口或者父类获取实现类或者子类的class集合,不包含本身
     *
     */
    public Set<Class<?>> getClassBySuper(Class<?> interfaceORClass){
        //获取beanMap容器的所有class对象
        Set<Class<?>> keySet = getClasses();
        if (keySet == null || "".equals(keySet)){
            log.warn("nothing in beanMap");
            return null;
        }
        //通过注解筛选出class对象是否传入接口的子类,并添加到set里
        Set<Class<?>> classSet = new HashSet<>();
        for(Class<?> clazz :keySet){
            //是否是传入接口的子类
            if (interfaceORClass.isAssignableFrom(clazz) && !clazz.equals(interfaceORClass)){
                classSet.add(clazz);
            }
        }
        //统一返回值
        return classSet.size() > 0? classSet:null;
    }



}

实现容器的依赖注入

image-20210507163534042
1.定义相关注解

image-20210507165800377

2.创建注入类-DependencyInjector

package org.simpleframework.inject;

import lombok.extern.slf4j.Slf4j;
import org.simpleframework.core.BeanContainer;
import org.simpleframework.inject.annotation.Autowired;
import org.simpleframework.utils.ClassUtil;

import java.lang.reflect.Field;
import java.util.Set;

@Slf4j
public class DependencyInjector {

    //获取容器
    private BeanContainer beanContainer;

    public DependencyInjector() {
        beanContainer = BeanContainer.getInstance();
    }


    /**
     * 执行ioc依赖注入
     *
     */

    public void doIoc(){



        if ((beanContainer.getClasses() == null || "".equals(beanContainer.getClasses()))){
            log.warn("empty classet");
            return;
        }
        //1.遍历Bean容器中所有的Class对象
        for (Class<?> clazz :beanContainer.getClasses()){
            //2.遍历Class对象的所有成员变量
            // getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段。
            Field[] fields = clazz.getDeclaredFields();
            if (fields == null || "".equals(fields)){
                continue;
            }
            for (Field field :fields){

                //3.找出被Autowired标记的成员变量
                if (field.isAnnotationPresent(Autowired.class)){
                    
                    Autowired autowired = field.getAnnotation(Autowired.class);
                    String value = autowired.value();

                    //4.获取成员变量的类型
                    Class<?> aClass = field.getType();
                    //5.获取成员变量的类型在容器里面对饮的实例
                    Object fieldvalue = getFieldInstance(aClass,value);
                    if (fieldvalue == null){
                        throw new RuntimeException("运行autowired异常");
                    }else {

                        //6.通过反射将对应的成员变量实例注入到成员变量所在类的实例里
                        Object targetbean = beanContainer.getBean(clazz);
                        ClassUtil.setField(field,targetbean,fieldvalue,true);



                    }
                }
            }


        }

    }


    /**
     *获取成员变量获取的实例
     * @param aClass
     * @return
     */
    private Object getFieldInstance(Class<?> aClass,String value) {
        Object bean =beanContainer.getBean(aClass);
        //判断变量是否为空,为空是类,不为空是接口
        if (bean != null){
            //类直接返回
            return bean;
        }else {
            //接口获取实现类
           Class<?> impl = getImpl(aClass,value);
           if (impl != null){
               return beanContainer.getBean(impl);
           }else {
               return null;
           }

        }
    }

    /**
     * 获取接口实现类
     * @param bean
     * @return
     */
    private Class<?> getImpl(Class<?> bean,String value) {
         //调用实现接口子类
        Set<Class<?>> classBySuper = beanContainer.getClassBySuper(bean);
        //是否有这个实现子类
        if (!(classBySuper == null || "".equals(classBySuper))){
            //是否设置默认值输出实现类
        if ((classBySuper == null || "".equals(value))){
              //只有一个实现类
            if (classBySuper.size() == 1){
                //迭代输出
                return classBySuper.iterator().next();
            }else {
                //多个实现类,抛出异常让用户自己选择加out注解
                throw new RuntimeException("多个实现类"+bean.getName());
            }

        }else {
            for (Class<?> aClass : classBySuper){
               if (value.equals(aClass.getSimpleName())){

                   return aClass;
               }

            }
        }
        }
      return null;
    }



}

工具类创建属性

    /***
     * 设置类属性值
     * @param field 成员变量
     * @param target 类实例
     * @param value 成员变量的值
     * @param accessible 是否允许有私自属性
     */
    public static void setField(Field field, Object target, Object value, Boolean accessible)
    {
        field.setAccessible(accessible);
        try {
            //给target实例里面的field成员变量设置value的值
            field.set(target,value);
        }catch (IllegalAccessException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

    }

}

使用

image-20210508164753665 image-20210508164719752

当有两类时就会报出有多个实现类的错误,需要指定实现

image-20210508165547968

beanPostProcessors使用

beanPostProcessors是什么?

bean的后置处理器,bean初始化之前干点什么,之后又干点什么,在不影响代码的情况下创建类似于插件的功能,aop的实现原理也是如此。

image-20210524161132828

创建一个现实类

image-20210524155211532

创建一个list集合存放处理器

image-20210524155446336

判断这个类是否实现了beanPostProcessors接口

image-20210524160752543

将list里面的beanPostProcessors遍历出来一一实现

image-20210524161919900

运行测试,再多加一个类也是如此,不改变代码加功能

image-20210531121301931
Aop的代理逻辑也是在beanPostProcessors实现

如果对你有帮助,请点关注吧~第一时间获取后续更新内容…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值