Spring IOC 和 DI手写 (按照自己思想写的)

一. (不喜欢勿喷,还在大学阶段 今后有高人指点的话 会修改写的更好 谢谢支持

编写自己的 MyClassUtils 主要用于获取一个包名下的所有.class,接口的不回获取到

package cn.edu.hbpu.util;

import java.io.*;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;

public class MyClassUtils
{
    /**
     * 加载所有的class文件
     * @param packageName 包名
     * @return class  list集合
     */
    public static List<Class<?>> getClasses(String packageName)
    {
        List<Class<?>> allClass = new ArrayList<Class<?>> ();
        // 获取包的名字 并进行替换 比如 cn.edu.hbpu -> cn/edu/hbpu
        String packageDirName = packageName.replace('.', '/');

        try
        {
            //得到物理文件url路径
            URL resource = Thread.currentThread ().getContextClassLoader ().getResource (packageDirName);

            //得到物理文件具体路径
            // ********一定要注意 指定编码格式获取,不然会出错*******
            String filePath = URLDecoder.decode(resource.getFile(), "UTF-8");

            //递归循环该文件下的所有 class文件 反射Class.forName 添加到集合中
            listPackage (filePath,packageName,allClass);

        } catch (Exception e)
        {
            e.printStackTrace ();
        }
        return allClass;
    }

    /**
     *
     * @param filePath 物理地址
     * @param allClass
     */
    public static void listPackage(String filePath, String packageName, List<Class<?>> allClass)
    {
        //创建文件 filePath: /D:/Intellij%20IEDA/IDEAworkSpace2/SpringIOC/target/classes/cn/edu/hbpu
        File file = new File (filePath);
        //判断该文件是否是一个文件夹,是否存在  如果不是  报异常
        if ( !file.isDirectory() || !file.exists ()) {
            return;
        }
        /**
         * 过滤文件夹 把是文件夹的或者以.class结尾的文件都提取出来
         */
        File[] files = file.listFiles (new FileFilter ()
        {
            @Override
            public boolean accept(File file)
            {
                return (file.isDirectory ()) || file.getName ().endsWith (".class");
            }
        });

        //遍历  cn.edu.hbpu 下的所有文件
        for(File everyFile:files)
        {
            if(everyFile.isDirectory ())
            {
                //传入文件的  具体地址  和相应的包名
                listPackage (everyFile.getAbsolutePath (),packageName+"."+everyFile.getName (), allClass);
            }
            //代表  是普通的.class文件
            else {
                //得到文件的全限定类名 比如 cn.edu.hbpu.service.ProductServiceImpl
                String classAllName=packageName+"."+everyFile.getName ().substring (0,everyFile.getName ().length ()-6);
                try
                {
                    //添加到集合中
                    Class<?> everyClass = Class.forName (classAllName);
                    /**
                     * 如果是接口类型,就直接省略
                     * 把不是接口类型的扫描进去
                     */
                    if(!everyClass.isInterface ())
                    {
                        allClass.add (everyClass);
                    }
                } catch (ClassNotFoundException e)
                {
                    e.printStackTrace ();
                }
            }
        }
    }


}

在这里插入图片描述

二.开始实现自己的IOC

1.包名属性
2.map集合 ->ioc容器
3.构造方法要初始化ioc容器 并且要 扫描包把加了MyCompoment注解的类实例化再加入到spring 容器中。

// 扫描包的路径
    private String packageName;

    //spring容器
    private ConcurrentHashMap<String, Object> ioc;

    public MySpringIOC(String packageName) throws Exception
    {
        this.packageName = packageName;
        //实例化ioc容器
        ioc = new ConcurrentHashMap<String, Object> ();
        //初始化bean 把所有加了注解的bean加载到ioc容器中
        initBean ();
    }

initBean:

/**
     * 初始化bean容器  准备工作
     */
    private void initBean() throws Exception
    {
        /**
         * 扫描该包下的所有.class文件  反射得到所有的class文件
         */
        List<Class<?>> classes = MyClassUtils.getClasses (this.packageName);

        //得到加了MyCompoment注解的集合
        List<Class<?>> anncotaionedClasses = findClassIsPreAnnoctation (classes);

        //根据anncotaionedClasses 开始实例化bean (反射实现的)
        newInstanceBean (anncotaionedClasses);

        //实现AutoWired功能  也就是依赖注入
        autoWiredBeanByName();

    }

findClassIsPreAnnoctation :

/**
     * 返回被注解申明的 class  这里就是被MyCompoment修饰的类
     *
     * @param classes
     * @return
     */
    private List<Class<?>> findClassIsPreAnnoctation(List<Class<?>> classes)
    {
        //加了注解的集合
        List<Class<?>> annoctationPresentClasses = new ArrayList<> ();

        for (Class clazz : classes)
        {
            //判断是否加了MyCompoment注解
            if (clazz.isAnnotationPresent (MyCompoment.class))
            {
                //添加到容器中
                annoctationPresentClasses.add (clazz);
                continue;
            }
        }
        return annoctationPresentClasses;
    }

两个注解类:

package spring;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义注解
 */
@Target(value = { ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCompoment
{
    /**
     * 给bean申明一个bean id  默认为空
     * @return
     */
    String beanName() default "";
}


package spring;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 只能用于属性上面 ElementType.FIELD
 */
@Target(value = { ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAutoWired
{
}

newInstanceBean:方法

/**
     * 反射实例化bean
     */
    private void newInstanceBean(List<Class<?>> anncotaionedClasses) throws Exception
    {
        //没有空参构造器的 clazz  等有空参构造器的初始化完了再初始化
        List<Class<?>> nullConstructor = new ArrayList<> ();

        for (Class clazz : anncotaionedClasses)
        {
            //判断是否有空参构造方法,有的话直接初始化,没有的话放置到后面
            Constructor constructor = clazz.getConstructor ();
            if (constructor == null)
            {
                anncotaionedClasses.remove (clazz);
                nullConstructor.add (clazz);
                continue;
            }
            //反射实例化
            Object o = clazz.newInstance ();
            // 获取 类名即可
            String className = toLowerCaseFirstOne (clazz.getSimpleName ());
            String beanId = toLowerCaseFirstOne (className);
            //添加到ioc容器中
            ioc.put (beanId,o);
        }

        //单独初始化 有参构造的bean  (这里我还未实现 等待以后实现)
        
    }

    // 首字母转小写
    public static String toLowerCaseFirstOne(String s)
    {
        if (Character.isLowerCase (s.charAt (0)))
        {
            return s;
        }

        else
        {
            return (new StringBuilder ()).append (Character.toLowerCase (s.charAt (0))).append (s.substring (1)).toString ();
        }
    }

autoWiredBeanByName

依赖注入的实现,也就是被MyAutoWired注解修饰的字段

/**
     * 实现AutoWired功能,依赖注入
     * 注意这个只是根据名字注入
     */
    private void autoWiredBeanByName() throws Exception
    {
        Set<Map.Entry<String, Object>> iocSet = ioc.entrySet ();
        for(Map.Entry entry : iocSet)
        {
            //得到每一个bean对象  实现依赖注入
            Object diObj = entry.getValue ();
            Field[] declaredFields = diObj.getClass ().getDeclaredFields ();
            for (Field field : declaredFields)
            {
                //如果是被  MyAutoWired  修饰的字段则进行赋值
                if(field.isAnnotationPresent (MyAutoWired.class))
                {
                    String fieldName = field.getName ();
                    Object bean = this.ioc.get (fieldName);
                    if(bean!=null)
                    {
                        // 私有访问允许访问
                        field.setAccessible (true);
                        // 给属性赋值
                        field.set(diObj, bean);
                        continue;
                    }
                }
            }

        }
    }

最后 实验的类加上去 ProductServiceImpl 和 ProductDao

package cn.edu.hbpu.service;

import cn.edu.hbpu.dao.ProductDao;
import spring.MyAutoWired;
import spring.MyCompoment;

@MyCompoment
public class ProductServiceImpl implements ProductService
{

    @MyAutoWired
    private ProductDao productDao;

    public void addProduct()
    {
        System.out.println ("ProductServiceImpl 添加商品");
        productDao.addProduct ();
    }
}

package cn.edu.hbpu.dao;

import spring.MyCompoment;

@MyCompoment
public class ProductDao
{
    public void addProduct()
    {
        System.out.println ("dao层实现");
    }
}

获取的代码

/**
     * 返回ioc容器
     * @return
     */
    public ConcurrentHashMap getIOC()
    {
        return this.ioc;
    }

    /**
     * 根据id获取bean
     * @param beanId  id
     * @return
     */
    public Object getBeanById(String beanId)
    {
        return ioc.get (beanId);
    }

测试

public class MyIOCTest
{
    public static void main(String[] args) throws Exception
    {

      /*  List<Class<?>> classes = MyClassUtils.getClasses ("cn.edu.hbpu");
        for (Class clazz : classes)
        {
            System.out.println (clazz.getSimpleName ());
        }*/

        MySpringIOC mySpringIOC = new MySpringIOC ("cn.edu.hbpu");
        ProductServiceImpl productServiceImpl = (ProductServiceImpl)mySpringIOC.getBeanById ("productServiceImpl");
        productServiceImpl.addProduct ();
    }
}

最终效果图
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值