Java使用反射实现IOC容器

2023-11-20

前面写过怎么通过Java的反射技术实现对象的创建和管理,达到IOC的效果。但是没有讲设计的思路,直接上代码,导致很多人没有思路,因此今天具体的讲IOC的编写思路理清。这里单纯的通过Java中的反射创建对象,至于扩展的部分会有提示思路
既然提到注解实现IOC,那么肯定要了解元注解的基本信息。

@Documented:被@Documented标注的类,在生成文档(doc)时,会显示@Documented注解信息。
@Inherited:可以被继承
@Target:可以声明的地方,通常为TYPE(类),FIELD(属性),METHOD(方法),
@Retention(RetentionPolicy.RUNTIME):参数有三个:CLASS,SOURCE,RUNTIME。
官方原文:注释保留策略。这种枚举类型的常量描述了保留注释的各种策略。它们与Retention元注释类型
结合使用,以指定注释要保留多长时间
1.RetentionPolicy.SOURCE —— 注释将被编译器丢弃(信息仅保留在源代码中,编译时将其忽略)。
2.RetentionPolicy.CLASS —— 注释将由编译器记录在类文件中,但不需要在运行时由 JVM 保留。这是默认行为
(编译时保留,将信息保留在CLASS文件中)。
3.RetentionPolicy.RUNTIME —— 注释将由编译器记录在类文件中,并在运行时由 JVM 保留,因此可以反射性地
读取它们(使用反射,其实就是在运行时通过JVM读取信息,类似于js脚本动态操作,这也是我们使用反射的用途)

上面简单的了解了一下元注解信息,创建注解类:@Annotation
这里即下面的例子,会参考SpringBoot的启动方式进行编写,演示一下IOC的原理,至于扩展的部分留给各位去发挥。
创建注解类:
Value普通属性值注入

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
    String value() default "";
}

Component组件(对象)创建

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component {
    String value() default "";//这不是数组,也不是方法,这是注解的属性声明,可以声明默认资,
    //也可不声明,String[] value()声明其为数组的形式
}

Autowared自动注入(赋值)

@Inherited
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowared {
    String value() default "";
}

AnnotationBootStrap启动类

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationBootStrap {
    boolean value() default true;
}

ComponentScanPackage类,自定义扫描包

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScanPackage {
    String value();
}

到此,基本信息创建成功。(思路:获得包路径 ---->扫描项目文件夹---->> 提取class文件 ---->>提取class全限定类名 —>> 通过Class.from创建类对象---->>获得无参构造---->>加入缓存---->遍历无参构造属性上注解信息进行赋值---->处理基本类型----->通过遍历缓存进行自动注入(注意:这里我设计的不够好,可能会产生null值,但不存在循环依赖问题)---->创建成功 )通过启动类,需要获取注解信息,因此需要获得类路径:
创建ApplicationContextAnnotationBeanFactory类(通过无参构造器创建实例,否则报错【这里可以发挥自己的想法,方法不止一个】(可以参考一下Spring解决循环依赖的缓存策略,设计三级缓存思路))

public class ApplicationContextAnnotationBeanFactory implements ApplicationContextBeanFactory {

    private Map<String, Object> objectMap;
    private List<Class> classList;
    //初始化构造器,先判断是否具备启动条件
    public ApplicationContextAnnotationBeanFactory(Class cls) throws Exception {
        if (!cls.isAnnotationPresent(AnnotationBootStrap.class)) {
            throw new RuntimeException(cls+"不是一个启动类,没有AnnotationBootStrap注解");
        } else {
            AnnotationBootStrap bootStrap = (AnnotationBootStrap) cls.getAnnotation(AnnotationBootStrap.class);
            if (bootStrap.value()) {
            //获得项目中的带有注解的Class
                this.classList = getClassList(cls);
               //获得Component标注的类对象实例
                objectMap = createObject();
            } else {
                throw new RuntimeException("AnnotationBootStrap启动类没有开启:false");
            }
        }
    }
    @Override
    public Object getBean(String name) throws ClassNotFoundException {
        return objectMap.get(name);
    }

    @Override
    public <T> T getBean(String name, Class cls) throws ClassNotFoundException {
        return (T) objectMap.get(name);
    }
    
    @Override
    public Integer getBeanSize() {
        return objectMap.size();
    }

    @Override
    public List<Object> getBeanList() {
        List<Object> list = new ArrayList<>();
        for (String beanName : objectMap.keySet()) {
            list.add(objectMap.get(beanName));
        }
        return list;
    }
    
    @Override
    public List<Class> getClassList(Class cls) throws ClassNotFoundException, FileNotFoundException {
        return new ScanPackagePath().scanPackagerPath(cls);
    }

    @Override
    public Map<String, Object> createObject() throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
        CreateFactoryBean createFactoryBean = new CreateFactoryBean();
        objectMap = createFactoryBean.getNoConstructor(classList);
        return objectMap;
    }
}

CreateFactoryBean类,创建Component标注的class


public class CreateFactoryBean {

    public Map<String, Object> getNoConstructor(List<Class> classList) throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
        Map<String, Object> objectMap = new HashMap<>();
        getNoConstructorObject(classList, objectMap);
        return objectMap;
    }
    /**
     * 创建注解无参构造的对象,将其加入容器
     */
    private void getNoConstructorObject(List<Class> classList, Map<String, Object> objectMap) throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
        for (Class aClass : classList) {
            if (aClass.isAnnotationPresent(Component.class)) {
                Component component = (Component) aClass.getAnnotation(Component.class);
                String beanName = null;
                if (component.value().equals("")) {
                    beanName = aClass.getName();//如果没有设置自定义名字,则将全路径名作为名字
                } else {
                    beanName = component.value();//得到自定义名称
                }
                Constructor constructor = aClass.getConstructor();//获得无参构造
                Object o = constructor.newInstance();//创建对象
                setParameter(o);//初始化参数
                objectMap.put(beanName, o);
            }
        }
        setObjectParameter(objectMap);
    }

    /**
     * 对引用的对象类型进行赋值
     */
    private void setObjectParameter(Map<String, Object> objectMap) throws IllegalAccessException {
        for (String s : objectMap.keySet()) {
            Class aClass = objectMap.get(s).getClass();
            Field[] fields = aClass.getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(Autowared.class)) {
                    Autowared autowared = field.getAnnotation(Autowared.class);
                    String value = autowared.value();
                    field.setAccessible(true);
                    if (value.equals("")){
                        for (String bean : objectMap.keySet()) {
                            if (field.getType().isAssignableFrom(objectMap.get(bean).getClass())
                                    ||objectMap.get(bean).getClass().isAssignableFrom(field.getType())){
                                field.set(objectMap.get(s),objectMap.get(bean));
                                break;
                            }
                        }
                    }else{
                        field.set(objectMap.get(s),objectMap.get(value));
                    }
                }
            }
        }
    }
    /**
     * 注入注解的值
     */
    public void setParameter(Object o) throws IllegalAccessException {
        for (Field field : o.getClass().getDeclaredFields()) {
            if (field.isAnnotationPresent(Value.class)) {
                Value value = field.getAnnotation(Value.class);
                String value1 = value.value();
                field.setAccessible(true);
                if (isPrimitive(field)) {
                    setPrimitive(o, value1, field);
                } else {
                    field.set(o, value1);
                }
            }
        }
    }

    /**
     * 配置基本数据类型
     */
    private void setPrimitive(Object o, String value1, Field field) throws IllegalAccessException {
        if (field.getType().isAssignableFrom(int.class) || field.getType().isAssignableFrom(Integer.class)) {
            field.set(o, Integer.parseInt(value1));
        }else if (field.getType().isAssignableFrom(short.class) || field.getType().isAssignableFrom(Short.class)){
            field.set(o, Short.parseShort(value1));
        }else if (field.getType().isAssignableFrom(long.class) || field.getType().isAssignableFrom(Long.class)){
            field.set(o,Long.parseLong(value1));
        }else if (field.getType().isAssignableFrom(char.class)) {
            field.set(o, value1.charAt(0));
        }else if (field.getType().isAssignableFrom(byte.class) || field.getType().isAssignableFrom(Byte.class)){
            field.set(o,Byte.parseByte(value1));
        }else if (field.getType().isAssignableFrom(Boolean.class) || field.getType().isAssignableFrom(boolean.class)) {
            field.set(o, Boolean.parseBoolean(value1));
        } else if (field.getType().isAssignableFrom(float.class) || field.getType().isAssignableFrom(Float.class)) {
            field.set(o,Float.parseFloat(value1));
        } else if (field.getType().isAssignableFrom(double.class) || field.getType().isAssignableFrom(Double.class)) {
            field.set(o,Long.parseLong(value1));
        }
    }

    /**
     * 判断属性的类型是否为基本类型
     */
    private boolean isPrimitive(Field value) {
        if (value.getType().isPrimitive()) {
            return true;
        }
        return false;
    }
}

ScanPackagePath类,扫描包路径


public class ScanPackagePath {


    /**
     *扫描启动类的包路径
     */
    public List<Class> scanPackagerPath(Class cls) throws ClassNotFoundException, FileNotFoundException {
        String path = cls.getClassLoader().getResource("").getPath();
        String path1 = cls.getPackageName();
        if (isOnePath(cls)) {//判断是否为同一个路径
            return getClassList(path, path1);
        } else {
            List<Class> list = null;
            if (cls.isAnnotationPresent(ComponentScanPackage.class)) {
                ComponentScanPackage clsAnnotation = (ComponentScanPackage) cls.getAnnotation(ComponentScanPackage.class);
                String value = clsAnnotation.value();
                list = getClassList(path, value);
            }
            List<Class> list1 = getClassList(path, path1);
            for (Class aClass : list1) {
                list.add(aClass);
            }
            return list;
        }
    }

    /**
     * 判断是否是同一路径
     */
    private boolean isOnePath(Class cls) {
        if (cls.isAnnotationPresent(ComponentScanPackage.class)) {
            ComponentScanPackage clsAnnotation = (ComponentScanPackage) cls.getAnnotation(ComponentScanPackage.class);
            String path1 = clsAnnotation.value();
            String path2 = cls.getPackageName();
            if (path1.equals(path2) || path2.equals("") || path1.contains(path2) || path2.contains(path1)) {
                return true;
            } else {
                return false;
            }
        }
        return true;
    }

    /**
     *获得Class集合
     */
    private List<Class> getClassList(String classPath, String packageName) throws ClassNotFoundException, FileNotFoundException {
        List<Class> list = new ArrayList<>();
        String replace = packageName.replace(".", File.separator);
        File file = new File(classPath, replace);
        File file1 = new File(classPath);
        if (!file.exists()) {
            throw new FileNotFoundException(packageName + "不存在");
        }
        getClassObject(file,file1.getPath(), list);
        return list;
    }

    /**
     *获得Class类对象
     */
    private void getClassObject(File file,String classPath, List<Class> list) throws ClassNotFoundException {
        File[] files = file.listFiles();
        for (File cls : files) {
            if (cls.isDirectory()) {
                getClassObject(cls,classPath, list);
            } else {
                if (cls.isFile()) {
                    if (cls.getName().endsWith(".class")) {
                        String clsPath = cls.getPath();
                        Class aClass = createClass(clsPath,classPath);
                        if (aClass != null) {
                            list.add(aClass);
                        }
                    }
                }
            }
        }
    }

    /**
     * 创建对象
     */
    private Class createClass(String classPath, String path) throws ClassNotFoundException {
    //获得类的全限定类名
        String cls = classPath.substring(path.length()+1,classPath.length()-6).replace(File.separator,".");
        Class aClass = Class.forName(cls);
        return (aClass.isInterface()||aClass.isAnnotation())?null:aClass;
    }
}

容器ApplicationContext父接口

public interface ApplicationContext {

    Object getBean(String name) throws ClassNotFoundException;
    <T> T getBean(String name,Class cls)throws ClassNotFoundException;
    Integer getBeanSize();
    List<Object> getBeanList();

}

ApplicationContextBeanFactory二级接口(这里设计的不好,可以合并到ApplicationContext)

public interface ApplicationContextBeanFactory extends ApplicationContext {

    List<Class> getClassList(Class cls) throws ClassNotFoundException, FileNotFoundException;

    Map<String,Object> createObject() throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException;
}

ApplicationContextBeanFactory的实现类ApplicationContextAnnotationBeanFactory

public class ApplicationContextAnnotationBeanFactory implements ApplicationContextBeanFactory {

    private Map<String, Object> objectMap;
    private List<Class> classList;

    public ApplicationContextAnnotationBeanFactory(Class cls) throws Exception {
        if (!cls.isAnnotationPresent(AnnotationBootStrap.class)) {
            throw new RuntimeException(cls+"不是一个启动类,没有AnnotationBootStrap注解");
        } else {
            AnnotationBootStrap bootStrap = (AnnotationBootStrap) cls.getAnnotation(AnnotationBootStrap.class);
            if (bootStrap.value()) {
                this.classList = getClassList(cls);
                objectMap = createObject();
            } else {
                throw new RuntimeException("AnnotationBootStrap启动类没有开启:false");
            }
        }
    }

    @Override
    public Object getBean(String name) throws ClassNotFoundException {
        return objectMap.get(name);
    }

    @Override
    public <T> T getBean(String name, Class cls) throws ClassNotFoundException {
        return (T) objectMap.get(name);
    }


    @Override
    public Integer getBeanSize() {
        return objectMap.size();
    }
    @Override
    public List<Object> getBeanList() {
        List<Object> list = new ArrayList<>();
        for (String beanName : objectMap.keySet()) {
            list.add(objectMap.get(beanName));
        }
        return list;
    }
    @Override
    public List<Class> getClassList(Class cls) throws ClassNotFoundException, FileNotFoundException {
        return new ScanPackagePath().scanPackagerPath(cls);
    }

    @Override
    public Map<String, Object> createObject() throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
        CreateFactoryBean createFactoryBean = new CreateFactoryBean();
        objectMap = createFactoryBean.getNoConstructor(classList);
        return objectMap;
    }
}

启动类

@AnnotationBootStrap//声明该类为启动类(默认为true,false表示不启动该功能)
@ComponentScanPackage("cn.edu.mapper")//扫描包(可以不声明,默认使用该类的包路径)
public class MyTestAnnotation {

    public static void main(String[] args) throws Exception {
        ApplicationContext app = new ApplicationContextAnnotationBeanFactory(MyTestAnnotation.class);
        User user = (User) app.getBean("user");
        System.out.println(user);
    }
}

实体类

@Component("test")
public class Test {
    @Value("杨万里")
    private String name;

    public void print(){
        System.out.println("Hello,I am advance notice");
    }
    @Override
    public String toString() {
        return "Test{" +
                "name='" + name + '\'' +
                '}';
    }
}

@Component("user")
public class User {

    @Value("貂蝉")
    private String name;
    @Value("女")
    private String sex;
    @Value("3")
    private int age;
    @Autowared
    private Test test;

    public User() {
    }

    public User(String name, String sex, int age, Test test) {
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.test = test;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                ", test=" + test +
                '}';
    }
}

运行结果
在这里插入图片描述
在写这个IOC的时候,边写边想,所有在设计上思路并没有太清晰,整体上存在一些缺陷,请见谅。各位在参考这篇文章的时候,可以结合JDK动态代理和Cglib,参考Spring的基本原理可以达到更好的效果(此处没有对接口进行管理)。注意哦:private修饰的属性和方法注解类不能被继承,Spring中条件注解Condidtion条件注解是一个很好的参考源码地址,Gitee

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java使用反射实现IOC容器 的相关文章

随机推荐

  • logback日志在项目启动后立刻清理历史日志

    扣扣技术分享交流群 1125844267 背景 搭了一个maven项目 只有一个main方法 然后打成一个jar包以供别的程序去启动执行 项目中配置了logback日志策略 但是在生产环境下发现日志可以正常生成 但是没有删除历史日志 设置的
  • 最全面、最详细web前端面试题及答案总结

    最全面 最详细web前端面试题及答案总结 总结不易 希望可以帮助到即将面试或还在学习中的web前端小伙伴 祝面试顺利 拿高薪 本章是HTML考点的 重难点 因此我们采 简略回答的 式进 撰写 所以不会有太多详细的解释 我们约定 每个问题后我
  • STM32外部EXTI中断笔记(开始于2021-07-13)

    STM32外部EXTI中断笔记 1 EXTI简介 在STM32上外部中断线共有19个 互联型 其上每个GPIO都可作外部中断输入 供GPIO的外部中断线供有16个 EXTI Line x x 0 15 stm32只分配7个中断向量给这16个
  • beego+goAdmin+mysql+docker+natapp作为微信小程序地服务器“伪部署”

    写在前面的话 1 为什么我要叫伪部署 答 因为我把它们放在服务器运行 都是开发模式 生产模式实在不会弄 所以就这样了 2 系统环境 答 腾讯云服务器 系统为 ubuntu 版本不记得 应该是比较高的 3 前提假设 答 假设你的服务器已经安装
  • Nginx启动报No mapping for the Unicode character exists in the target multi-byte code pa

    安装路径不能含有中文
  • UnityVR--组件3--Line Renderer--线性渲染

    目录 线性渲染组件简介 绘制线条Line Renderer组件介绍 绘制拖尾Trail Renderer组件介绍 应用1 使用Line Renderer绘制线段 应用1实现 使用系统工具或自定义工具绘制线段 应用2 Trail Render
  • 【数据结构】带你手撕八大排序

    目录 一 排序的基础知识 1 排序的概念 2 排序的应用 3 常见的排序算法 二 八大排序的实现 1 插入排序 直接插入排序 直接插入排序的特性总结 2 插入排序 希尔排序 希尔排序的特性总结 3 选择排序 直接选择排序 直接插入排序特性总
  • 老版迅雷5.8无限制经典版

    迅雷5 8不升级版是一款经典热门的P2P下载工具 迅雷5 8去广告绿色版已完全对弹出式广告进行屏蔽 并自动开启高速下载通道 支持磁力链接和网页下载 完美支持WIN8 1 WIN10 不定时检测去除无用组件 为用户提供绿色纯净的下载环境和高速
  • CentOS7 安装Teamviewer

    CentOS7 安装Teamviewer 下载 wget https download teamviewer com download teamviewer i686 rpm 安装 yum install y 文件名 在终端执行一下命令进行
  • 异步通信时钟亚稳态打拍

    为了降低亚稳态出现的概率把异步信号单比特打两排 将下面的即可 最后用第三位的数据就是打两拍后的结果 在这里插入代码片 reg 2 0 wr n r always posedge clk or nesedge rst n begin if r
  • FPGA学习笔记(一)__电平知识

    常见电平标准 文章目录 1 TTL电平标准 2 LVTTL电平标准 1 LVTTL3V3 2 LVTTL2V5 3 CMOS电平标准 4 LVCOMS电平标准 1 LVCOMS3V3 2 LVCOMS2V5 3 LVCOMS1V8 4 LV
  • 选择多级分类_分类汇总——Excel中最直接有效的数据汇总方式

    在我们正常处理数据过程中 通常会有用到对数据中某一个或者多个指标 字段 进行汇总 求和 求平均等 的操作 我们可以使用譬如sumif sumifs averageif count等一些函数进行 这些函数在后面的文章中我也会讲到 今天我们来讲
  • [项目管理-15]:项目执行中的三大管理者:项目活动管理、职能部门管理、产品架构设计。

    目录 1 矩阵项目管理 2 项目活动管理 2 1 项目架构 2 2 项目管理活动 3 职能部门管理 要与产品 设备架构一致 3 1 组织架构 3 1 需求部门 3 2 硬件开发部门 3 3 软件开发部门 3 4 测试部门 4 产品设备管理
  • 部署前后端分离项目前端vue后端django

    1 前端部署 前后端分离的项目 部署时 前端我们只需要打包成dist文件 放到到后端项目中即可 npm run build 2 后端部署 后端部署 我这里主要讲基于uwsgi启动项目的方式 2 1 uwsgi的配置 uwsgi master
  • 6个好用的AI绘画工具,一键生成超精美图片!

    给大家分享6个好用的AI绘画工具 操作简单 小白也能用 生成的图片效果也好 其中有几个还完全免费 先给大家看看一些生成的图片吧 1 Vega AI 一个免费的AI绘画网站 手机号登录之后就可以使用了 它有文生图 图生图和条件生图的模式可选
  • 2023年最新5A景区有多少个?Python可视化告诉你

    2023年最新5A景区有多少个 Python可视化告诉你 五一小长假来了 很多人想抓住小长假的机会去旅游 5A景区是大多数人的首选 全国最新有多少个5A景区呢 应该还有很多人不知道 本文用Python进行可视化 告诉你答案 各年5A景区数量
  • vue3使用import.meta.env在vite.config.ts下使用env环境变量的方法

    vue3使用import meta env在vite config ts下使用env环境变量的方法 编程一枚的博客 CSDN博客
  • 一个关于jvm堆溢出引发的思考

    在本地测试无误的程序 放上正式服时 出现了堆溢出 本地是Windows系统下的 服务器是linux系统 后来经过测试发现是我在本地跑程序时 在eclipse中添加了如下参数 此处先解释下上面各参数的的含义 Xms512m 堆的最小值 Xmx
  • mysql视图

    一 什么是视图 视图是指计算机数据库中的视图 是一个虚拟表 其内容由查询定义 同真实的表一样 视图包含一系列带有名称的列和行数据 但是 视图并不在数据库中以存储的数据值集形式存在 行和列数据来自由定义视图的查询所引用的表 并且在引用视图时动
  • Java使用反射实现IOC容器

    前面写过怎么通过Java的反射技术实现对象的创建和管理 达到IOC的效果 但是没有讲设计的思路 直接上代码 导致很多人没有思路 因此今天具体的讲IOC的编写思路理清 这里单纯的通过Java中的反射创建对象 至于扩展的部分会有提示思路 既然提