IOC的实现原理—反射与工厂模式

2023-05-16

反射机制概念

        我们考虑一个场景,如果我们在程序运行时,一个对象想要检视自己所拥有的成员属性,该如何操作?再考虑另一个场景,如果我们想要在运行期获得某个类的Class信息如它的属性、构造方法、一般方法后再考虑是否创建它的对象,这种情况该怎么办呢?这就需要用到反射!

        我们.java文件在编译后会变成.class文件,这就像是个镜面,本身是.java,在镜中是.class,他们其实是一样的;那么同理,我们看到镜子的反射是.class,就能通过反编译,了解到.java文件的本来面目

        对于反射,官方给出的概念:反射是Java语言的一个特性,它允许程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个Java类获取它所有的成员变量和方法并且显示出来。

        反射主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。在Java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。

        反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!类中有什么信息,利用反射机制就能可以获得什么信息,不过前提是得知道类的名字


反射机制的作用

        1、在运行时判断任意一个对象所属的类;

        2、在运行时获取类的对象;

        3、在运行时访问java对象的属性,方法,构造方法等。

        首先要搞清楚为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。

        静态编译:在编译时确定类型,绑定对象,即通过。

        动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了Java的灵活性,体现了多态的应用,有以降低类之间的藕合性。


反射机制的优缺点

        反射机制的优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容,进行反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。

        比如,一个大型的软件,不可能一次就把把它设计得很完美,把这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时动态地创建和编译,就可以实现该功能。

        反射机制的缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且让它满足我们的要求。这类操作总是慢于直接执行相同的操作。


反射与工厂模式实现IOC

        Spring中的IoC的实现原理就是工厂模式加反射机制。 我们首先看一下不用反射机制时的工厂模式:

interface fruit{
    public abstract void eat();
} 
class Apple implements fruit{
     public void eat(){
         System.out.println("Apple");
     }
} 
class Orange implements fruit{
     public void eat(){
         System.out.println("Orange");
     }
}
//构造工厂类
//也就是说以后如果我们在添加其他的实例的时候只需要修改工厂类就行了
class Factory{
     public static fruit getInstance(String fruitName){
         fruit f=null;
         if("Apple".equals(fruitName)){
             f=new Apple();
         }
         if("Orange".equals(fruitName)){
             f=new Orange();
         }
         return f;
     }
}
class hello{
     public static void main(String[] a){
         fruit f=Factory.getInstance("Orange");
         f.eat();
     }
}

        上面写法的缺点是当我们再添加一个子类的时候,就需要修改工厂类了。如果我们添加太多的子类的时候,改动就会很多。下面用反射机制实现工厂模式:

interface fruit{
     public abstract void eat();
}
class Apple implements fruit{
public void eat(){
         System.out.println("Apple");
     }
}
class Orange implements fruit{
public void eat(){
        System.out.println("Orange");
    }
}
class Factory{
    public static fruit getInstance(String ClassName){
        fruit f=null;
        try{
            f=(fruit)Class.forName(ClassName).newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
}
class hello{
    public static void main(String[] a){
        fruit f=Factory.getInstance("Reflect.Apple");
        if(f!=null){
            f.eat();
        }
    }
}

        现在就算我们添加任意多个子类的时候,工厂类都不需要修改。使用反射机制实现的工厂模式可以通过反射取得接口的实例,但是需要传入完整的包和类名。而且用户也无法知道一个接口有多少个可以使用的子类,所以我们通过属性文件的形式配置所需要的子类。

        下面编写使用反射机制并结合属性文件的工厂模式(即IoC)。首先创建一个fruit.properties的资源文件:

apple=Reflect.Apple
orange=Reflect.Orange

        然后编写主类代码:

interface fruit{
    public abstract void eat();
}
class Apple implements fruit{
    public void eat(){
        System.out.println("Apple");
    }
}
class Orange implements fruit{
    public void eat(){
        System.out.println("Orange");
    }
}
//操作属性文件类
class init{
    public static Properties getPro() throws FileNotFoundException, IOException{
        Properties pro=new Properties();
        File f=new File("fruit.properties");
        if(f.exists()){
            pro.load(new FileInputStream(f));
        }else{
            pro.setProperty("apple", "Reflect.Apple");
            pro.setProperty("orange", "Reflect.Orange");
            pro.store(new FileOutputStream(f), "FRUIT CLASS");
        }
        return pro;
    }
}
class Factory{
    public static fruit getInstance(String ClassName){
        fruit f=null;
        try{
            f=(fruit)Class.forName(ClassName).newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
}
class hello{
    public static void main(String[] a) throws FileNotFoundException, IOException{
        Properties pro=init.getPro();
        fruit f=Factory.getInstance(pro.getProperty("apple"));
        if(f!=null){
            f.eat();
        }
    }
}

        运行结果:Apple


IOC容器的技术剖析

        IOC中最基本的技术就是“反射(Reflection)”编程,通俗来讲就是根据给出的类名(字符串方式)来动态地生成对象,这种编程方式可以让对象在生成时才被决定到底是哪一种对象。只是在Spring中要生产的对象都在配置文件中给出定义,目的就是提高灵活性和可维护性。

        目前C#、Java和PHP5等语言均支持反射,其中PHP5的技术书籍中,有时候也被翻译成“映射”。有关反射的概念和用法,大家应该都很清楚。反射的应用是很广泛的,很多的成熟的框架,比如像Java中的Hibernate、Spring框架,.Net中NHibernate、Spring.NET框架都是把”反射“做为最基本的技术手段。

        反射技术其实很早就出现了,但一直被忽略,没有被进一步的利用。当时的反射编程方式相对于正常的对象生成方式要慢至少得10倍。现在的反射技术经过改良优化,已经非常成熟,反射方式生成对象和通常对象生成方式,速度已经相差不大了,大约为1-2倍的差距。

        我们可以把IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言提供的反射机制,根据配置文件中给出的类名生成相应的对象。从实现来看,IOC是把以前在工厂方法里写死的对象生成代码,改变为由配置文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。


使用IOC框架应该注意什么

        使用IOC框架产品能够给我们的开发过程带来很大的好处,但是也要充分认识引入IOC框架的缺点,做到心中有数,杜绝滥用框架。

        1)软件系统中由于引入了第三方IOC容器,生成对象的步骤变得有些复杂,本来是两者之间的事情,又凭空多出一道手续,所以,我们在刚开始使用IOC框架的时候,会感觉系统变得不太直观。所以,引入了一个全新的框架,就会增加团队成员学习和认识的培训成本,并且在以后的运行维护中,还得让新加入者具备同样的知识体系。

        2)由于IOC容器生成对象是通过反射方式,在运行效率上有一定的损耗。如果你要追求运行效率的话,就必须对此进行权衡。

         3)具体到IOC框架产品(比如Spring)来讲,需要进行大量的配制工作,比较繁琐,对于一些小的项目而言,客观上也可能加大一些工作成本。

        4)IOC框架产品本身的成熟度需要进行评估,如果引入一个不成熟的IOC框架产品,那么会影响到整个项目,所以这也是一个隐性的风险。

        我们大体可以得出这样的结论:一些工作量不大的项目或者产品,不太适合使用IOC框架产品。另外,如果团队成员的知识能力欠缺,对于IOC框架产品缺乏深入的理解,也不要贸然引入。最后,特别强调运行效率的项目或者产品,也不太适合引入IOC框架产品,像WEB2.0网站就是这种情况。


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

IOC的实现原理—反射与工厂模式 的相关文章

  • Unity Remote5 使用

    Unity Remote是Unity公司提供的一个移动端同步调试工具 xff0c 在Unity编辑器中以播放模式运行项目时 xff0c 该应用程序将与Unity连接 编辑器的可视输出被发送到设备的屏幕 xff0c 实时输入被发送回Unity
  • 里氏替换原则

    里氏替换原则主要是发生在父类和子类之间 xff0c 说到父类和子类 xff0c 在面向对象的语言中 xff0c 继承是必不可少的 非常优秀的语言机制 xff0c 它有如下优点 xff1a 代码共享 xff0c 减少创建类的代码量 xff0c
  • Android中的Intent

    Android中的Intent可以用来在一个组件中启动App中的另一个组件或者是启动另一个App的组件 xff0c 这里所说的组件指的是Activity Service以及Broadcast 目录 Intent的用途 Intent的类型 I
  • Android中Intent用法详细解释

    Android中一些常见的Intent的习惯用法 xff0c 比如如何通过Intent发送短信 发送邮件 启动摄像机拍照录视频 设置闹铃 打开WIFI设置界面等等 目录 发送短信 发送邮件 打电话 拍照 摄像 发送短信 发送短信的时候 xf
  • Android中的Intent的用法

    文章目录 调用拨号程序发送短信或彩信通过浏览器打开网页发送电子邮件显示地图与路径规划播放多媒体选择图片拍照获取并剪切图片打开手机应用市场安装程序卸载程序进入设置界面 调用拨号程序 span class token comment 调用拨打电
  • oracle vm virtualbox 卸载不了

    只能用很暴力的方法下载了个 Windows Install Clean Up 地址 xff1a https www baidu com s tn 61 02003390 42 hao pg amp wd 61 Windows 20Insta
  • vsftpd服务----配置

    首先安装 Linux 企业版第一张光盘中的vsftpd 2 0 1 5 i386 rpm rpm ivh media cdrom RedHat RPMS vsftpd 3 0 1 5 i386 rpm 启动vsftpd服务 service
  • 排列组合

    排列组合的基本公式为 实现A xff0c C xff0c 并把他们封装称为一个函数 xff0c 之后使用起来就会比较方便 int A int n int m int res 61 1 for int i 61 n i gt n m i re
  • vue3.0常用eslint配置详解 .eslintrc.js

    规则值 34 off 34 或者 0 xff0c 关闭 34 warn 34 或者 1 xff0c 警告 34 error 34 或者 2 xff0c 报错 eslintrc js配置 module span class token pun
  • 实际项目中使用Postsharp

    我现在的项目中使用了winform net2 0 43 asp net mvc net3 5 43 sqlserver2000 xff0c Orm使用的是Castle的ActiveRecord 客户端与服务器端通信使用的是Ice xff0c
  • 开启SELINUX真的就那么难吗?

    我们都知道Linux的安全性要高于windows xff0c 可是你明白Linux到底比windows的安全性高在哪里吗 xff1f 有人在部署环境的时候 xff0c 开局两件事关防火墙 关Selinux xff0c 请问你把Linux的这
  • SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)

    1 1 Spring Spring是一个开源框架 xff0c Spring 是于 2003 年兴起的一个轻量级的 Java 开发框架 xff0c 由 Rod Johnson 在其著作 Expert One On One J2EE Devel
  • 服务器不支持ipv6,怎么解决

    让服务器开发人员修改到上面的测试ipv6通过为止 如果服务器不会修改怎么办 找专业的人员帮忙 有可能需要购买中转服务 本解决方案的花钱找人帮忙部分有介绍 关于ipv6审核给你点借鉴 此文介绍了一些服务器如何适配ipv6 需要添加aaaa中转
  • VS2015远程连接虚拟机

    目录 一 安装VC Linux exe 二 打开VS 选择新建项目 三 配置VS 四 创建项目 一 安装VC Linux exe 下载地址 xff1a 二 打开VS 选择新建项目 三 配置VS 打开VS xff0c 菜单栏点击工具 gt 选
  • 成都富华力鼎:短视频脚本有哪些类型

    制作短视频 xff0c 一个好的脚本是成功的关键 很多小伙伴没有提前写脚本 xff0c 在拍摄的时候就会遇到各种各样的问题 xff0c 场景不适合 员不适合 临时改内容等等 短视频脚本有哪些类型 1 提纲脚本 提纲脚本 xff1a 应用在纪
  • Android开发-Android 10 的新功能及新特性

    前 言 Google 在去年 xff08 2019年 xff09 3月份首次公布了 Android 10 的测试版 xff0c 然后在去年 5 月份的 Google 年度 I O 开发者大会上展示了 Android 10 系统的几个新的功能
  • asp.net动态切换主题

    C 代码 protected void Page PreInit object sender EventArgs e if Request QueryString 34 theme 34 61 null switch Request Que
  • datatable中button

    function test 34 ruleDataTable2 34 dataTable 34 sAjaxSource 34 dbLinkUrl sqlResultexport 34 fnServerData 34 createShowin
  • 重构——使用多态替换switch

    好吧 xff0c 我这个菜鸟确实是常常在用面向过程的思想在考虑问题 xff0c 在编写程序 现在我已经摈弃了自己对java语言个人的偏见 xff0c 而是用平等公平的态度看待java和C 43 43 他们各有千秋 xff0c 各有乾坤的 好
  • HttpUtil

    package com cmb utils import com fasterxml jackson databind ObjectMapper import org apache http Header import org apache

随机推荐

  • springboot异步请求

    场景 xff1a 用户注册的时候会发送短信和邮件 xff0c 注册成功和发送短信 邮件解耦后会提高响应效率 启动类添加注解 64 EnableAsync 64 SpringBootApplication public class Appli
  • Linux安装Terminator

    大家在使用Linux系统的时候 xff0c 有很大一部分时间都是和系统的终端打交道 时间久了会不会有一种厌烦的感觉呢 xff1f xff08 我是一个始终如一的人 xff0c 怎能厌烦呢 xff1f xff09 x1f604 ubuntu下
  • 安装软件或者依赖包时显示错误:unable to locate package zliblg-dev

    在网上查了很久 xff0c 有人说需要更新一下 sudo apt get update 但是还是不行 xff0c 然后我把依赖包中的英文字母l改为阿拉伯数字1就好了 xff0c 哈哈 xff0c 就是这莫简单
  • ranger命令

    ranger命令 ranger主要用来在终端浏览文件的 使用起来也比较优于平时常用的cd命令 安装 span class token function sudo span span class token function apt get
  • firewalld 和 docker 冲突问题

    造成冲突的主要原因是 xff1a iptables的存在 firewalld 和 iptables 首先 xff0c firewalld 和 iptables 都不是防火墙 xff0c 它们只是防火墙的管理程序 xff0c 真正的防火墙是内
  • Android Studio项目中各目录的图标含义

    对初学安卓的人 xff0c 熟悉Android Studio上的各模块都要花力气 打开团队的一个工程 xff0c 对各目录上显示的图标有圆点 方块 三条柱形等等 xff0c 真的一脸茫然 所以本文记录对工程中的文件图标的含义 xff0c 方
  • base64转换

    String data 61 34 9j 4AAQSkZJRgABAQEAZABkAAD 2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8
  • Android中dispatchDraw分析

    Android中dispatchDraw分析 View中 xff1a public void draw Canvas canvas 1 Draw the background 绘制背景 2 If necessary save the can
  • fastboot flash system.img总失败

    7 0之后 system img会很大 xff0c 有时fastboot会很长时间 xff0c 甚至会报错 xff0c 可以用下面的方法 fastboot flash S 256M system system img
  • CAS新版本(6.0-RC4)使用介绍(一)

    新版本CAS介绍 xff08 6 0 RC4 xff09 简介 Central Authentication Service CAS xff0c 通常称为CAS CAS是一种针对Web的企业多语言单点登录解决方案 xff0c 并尝试成为您的
  • 彻底理解Java反射以及动态代理中对反射的应用

    反射 Reflection 是 Java 的特征之一 xff0c 它允许运行中的 Java 程序获取自身的信息 xff0c 并且可以操作类或对象的内部属性 简而言之 xff0c 通过反射 xff0c 我们可以在运行时获得程序或程序集中每一个
  • 读懂消息队列:Kafka与RocketMQ

    3月份学完了极客时间的 消息列队高手课 专栏 xff0c 专栏讲解了许多消息队列的基础知识并且对Kafka与RocketMQ两种主流消息队列有精彩的对比分析 学完专栏后将所有要点整理为笔记记录下来 xff0c 其他相关知识也搜索了大量资料
  • ubuntu20.04设置静态IP地址

    ubuntu20 04 默认使用动态IP设置 xff0c 但有时我们需要为其设置静态IP 本文将带着大家彻底搞清楚ubuntu20 04的IP设置方法 如果你是在虚拟机中使用ubuntu20 04 并对虚拟机的网络设置有疑问的话请看本人的拙
  • Centos的repos文件中的$releasever和$basearch的取值

    查看CentOS Base repo部分内容 xff0c 文件路径 etc yum repos d CentOS Base repo base baseurl 61 http mirror centos org centos release
  • 如何用Redis实现分布式锁

    为什么需要分布式锁 在聊分布式锁之前 xff0c 有必要先解释一下 xff0c 为什么需要分布式锁 与分布式锁相对就的是单机锁 xff0c 我们在写多线程程序时 xff0c 避免同时操作一个共享变量产生数据问题 xff0c 通常会使用一把锁
  • AQS与Synchronized异曲同工的加锁流程

    在并发多线程的情况下 xff0c 为了保证数据安全性 xff0c 一般我们会对数据进行加锁 xff0c 通常使用Synchronized或者ReentrantLock同步锁 Synchronized是基于JVM实现 xff0c 而Reent
  • 基于贫血模型的MVC开发模式VS领域建模开发模式

    大部分工程师都是做业务开发的 xff0c 很多业务系统都是基于MVC三层架构来开发的 xff0c 确切点说 xff0c 这是一种基于贫血模型的MVC三层架构开发模式 这种开发模式已经成为标准的Web项目开发模式 xff0c 但它却违反了面向
  • 从Servlet、Servlet容器及Web容器的演进历程总结框架设计的套路

    Web架构演进历程 早期的Web技术主要用于浏览静态页面 xff0c 首先浏览器发起HTTP请求 xff0c 请求一些静态资源 xff0c 这时候需要一个服务器来处理HTTP请求 xff0c 并且将相应的静态资源返回 这个服务器叫HTTP服
  • 信号量与生产者消费者问题

    生产者 消费者问题 生产者 消费者题型在各类考试 xff08 考研 程序员证书 程序员面试笔试 期末考试 xff09 很常见 xff0c 原因之一是生产者 消费者题型在实际的并发程序 xff08 多进程 多线程 xff09 设计中很常见 x
  • IOC的实现原理—反射与工厂模式

    反射机制概念 我们考虑一个场景 xff0c 如果我们在程序运行时 xff0c 一个对象想要检视自己所拥有的成员属性 xff0c 该如何操作 xff1f 再考虑另一个场景 xff0c 如果我们想要在运行期获得某个类的Class信息如它的属性