美文网首页
分享一道面试题:模拟Spring IOC 控制反转实现原理,建议

分享一道面试题:模拟Spring IOC 控制反转实现原理,建议

作者: 前程有光 | 来源:发表于2021-02-26 21:27 被阅读0次

    前言

    Spring IOC控制反转是通过反射机制与工厂模式的结合,下面给大家模拟一下

    生活案例引入

    2000 年,你们家开了一家叫 “笑笑” 的包子铺 ------爸
    2002 年,你们城东新开了一家分店 “笑笑” 包子铺------妈
    2004 年,你们城西也新开了一家分店"笑笑" 包子铺-----你

    多年后,包子铺越开越多,口味难以保证

    “笑笑” 包子铺老板:以后我们几个核心班子只在一家做包子,所有分店不在做包子,直接来我们这里提货即可
    带来的好处:
    1、所有包子铺的口味一致
    2、所有包子铺不在关注做包子,只卖,做包子的过程(控制权限)–某一个工厂里面—IOC(Spring的控制反转)------>工厂模式

    代码案例

    构建纯净类

    public class Book {
        private String name;
        private String author;
        private double price;
        
        public Book (){}
        
        @Override
        public String toString() {
            return "Book{" +
                    "name='" + name + '\'' +
                    ", author='" + author + '\'' +
                    ", price=" + price +
                    '}';
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getAuthor() {
            return author;
        }
    
        public void setAuthor(String author) {
            this.author = author;
        }
    
        public double getPrice() {
            return price;
        }
    
        public void setPrice(double price) {
            this.price = price;
        }
    
        public Book(String name, String author, double price) {
            this.name = name;
            this.author = author;
            this.price = price;
        }
    }
    class AB extends Book{}
    class AC extends Book{}
    
    

    传统方式构建实例

      //1、传统方式
      //弊端:需要自己构建对象(new),若项目中有几百个类,通过该方式构建实例不可取
      Book b1 = new AB();
      Book b2 = new AC();
    
    

    纯净类的工厂类BookFactory

    
    public class BookFactory {
        //使用简单反射升级
        public static Book getBook1() throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            //1、先使用反射获取Book的Class对象
            Properties pro = new Properties();
            //2、获取配置文件信息,加载配置文件
            pro.load(new FileInputStream("D://JavaServletProject//ServletDemo//ZhenAiDemoVersionTwo//src//org//soffteem//sources//book//book.properties"));
            //3、得到配置文件里面的key值,根据key值反射得到class对象
            Class<Book> bookClass = (Class<Book>)Class.forName(pro.getProperty("className"));
            //4、获取有参构造器
            Constructor<Book> cons = bookClass.getDeclaredConstructor(String.class,String.class,double.class);
            //5、通过反射构建对象实例
            return cons.newInstance(pro.getProperty("name"),pro.getProperty("author"),Double.parseDouble(pro.getProperty("price")));
        }
    
        //如果用户过来需要书,会根据类名去构建书对象,原始方法
        public static Book getBook(String name){
            Book book = null;
            if (name.equals("AB")){
                b = new AB();
            }else if (name.equals("AC")){
                b = new AC();
            }else {
                //....如果有很多的书籍多次判定.....
            }
            return book;
        }
    }
    
    

    传统方式上升级

    //2、现在有了笑笑包子铺(纯净类工厂)
    //弊端:此时不需要构建对象,但是依然需要手动输入对象名称
     System.out.println("请您输入需要的书名");
     //....此处省略部分代码......
     Book book = BookFactory.getBook("你输入的名字");
    
    

    通过简单反射升级

    className=org.soffteem.myspring.Book
    author=王大锤
    name=倚天屠龙记
    price=38.9
    
    
    //3、不用输入就能构建对象
    //弊端:如果不是Book对象而是其他对象呐?调用该工厂的这个方法只能够返回Book对象
    System.out.println("获取书籍:" + BookFactory.getBook1());
    
    

    类似Spring IOC容器的工厂构建

    XML文件

    <?xml version="1.0" encoding="utf-8" ?>
    <beans>
        <!--书籍类-->
        <bean id="book" class="org.soffteem.myspring.Book">
            <property name="name" value="倚天屠龙记"></property>
            <property name="author" value="金庸"></property>
            <property name="price" value="25.3"></property>
        </bean>
        <!--各种其他类-->
        <!--此处的student类没有展示-->
        <bean id="student" class="org.soffteem.test.Student"></bean>
    </beans>
    
    

    类似"Spring IOC容器"类

    public class ApplicationContextUtils {
        //文档对象
        Document document;
        //1、初始化文档对象
        public ApplicationContextUtils() throws DocumentException {
            //1.1 通过dom4j的jar读取xml文件,获取文档对象
            SAXReader reader = new SAXReader();
            this.document = reader.read("D://JavaServletProject//ServletDemo//ZhenAiDemoVersionTwo//src//org//soffteem//sources//book//books.xml");
        }
    
        //2、反射 + 集合 + xml解析 获取Bean实例
        public <T>T getBean(String id,Class<T> tc) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
            //2.1 解析xml文件,获取根节点 <beans><beans>
            Element element = document.getRootElement();
            //2.2 获取根节点(<beans>)所有的子节点 <bean></bean>
            List<Element> list = element.elements();
            //3、迭代所有的<bean>节点
            for (Element e:list){
                //3.1 得到<bean>子节点中id的值
                String myId = e.attributeValue("id");
                //3.2 得到<bean>子节点中class的数值
                String className = e.attributeValue("class");
                //3.3 判定:根据用户输入的id进行指定的实例化
                //因为此处可能不只只有一个纯净类的节点配置项,要根据用户输入的id值实例化执行的配置节点
                if (myId.equals(id)){
                    //3.3.1 反射当前id对应的className的class对象
                    Class c = Class.forName(className);
                    //3.3.2 再次判定:若是父类呐?此处判断父类我是通过class对象判定的
                    if (c == tc){
                        //3.3.3 通过反射构建对象
                        T obj = tc.newInstance();
                        //3.3.4 得到当前<bean>节点中的所有<properties>子节点
                        List<Element> props = e.elements();
                        //3.3.5 得到所有的孙子节点对象<properties>
                        for (Element prop:props){
                            //3.3.5.1 得到孙子节点的每一个属性内容name与value对应的值
                            String name = prop.attributeValue("name");
                            String value = prop.attributeValue("value");
                            //3.3.5.2 将内容赋值到对象属性中
                            setAttribute(tc.getDeclaredFields(),obj,name,value);
                        }
                        //返回对象
                        return obj;
                    }
                }
            }
            return  null;
        }
    
        //封装给属性赋值的方法
        //① 需要得到所有的属性 ② 给哪个对象赋值 ③ 给哪个属性赋值 ④赋值的内容
        public <T>void setAttribute(Field[] fields,T obj,String key,String value) throws IllegalAccessException {
            //1、循环属性,得到具体的属性值
            for (Field field:fields){
                //2、要想给属性赋值,由于属性是私有的,需要设置属性的访问权限
                field.setAccessible(true);
                //3、考虑一下属性的类型:基本属性类型、对象类型
                Class type = field.getType();//获取当前属性字段field的类型
                //此处我只写了几个基本数据类型,其他类型可自行添加......
                if (key.equals(field.getName())){
                    if (type == int.class){
                        field.set(obj,Integer.parseInt(value));
                    }else if (type == double.class){
                        field.set(obj,Double.parseDouble(value));
                    }else if (type == String.class){
                        field.set(obj,value);
                    }else {
                        //若是对象类型
                        field.set(obj,value);
                    }
                }
            }
        }
    }
    
    

    模拟"Spring容器"构建实例

    //1、构建 "Spring容器" 最先实例化可通过on-load-startup属性,后期交给tomcat容器
    ApplicationContextUtils application = new ApplicationContextUtils();
    //2、通过"Spring容器"结合配置文件的Id属性值获取Book对象
    Book book = application.getBean("book",Book.class);
    //3、格式化输出对象,进行内容展示
    System.out.println(book.toString());
    
    

    模拟"Spring容器"构建实例步骤总结

    • 构建纯净类,也就是JavaBean类
    • 构建工厂类,便于JavaBean通过工厂创建实例
    • 实例化工厂,调用工厂类的方法获取实例对象
    • Spring IOC获取实例步骤总结
    • 构建纯净类
    • 构建Spring框架的配置文件
    • 将纯净类注入到配置文件中
    • 实例化Spring容器,通过getBean()方法根据Id属性值来获取对应的实例

    最后

    欢迎关注公众号:前程有光,领取一线大厂Java面试题总结+各知识点学习思维导+一份300页pdf文档的Java核心知识点总结! 这些资料的内容都是面试时面试官必问的知识点,篇章包括了很多知识点,其中包括了有基础知识、Java集合、JVM、多线程并发、spring原理、微服务、Netty 与RPC 、Kafka、日记、设计模式、Java算法、数据库、Zookeeper、分布式缓存、数据结构等等。

    相关文章

      网友评论

          本文标题:分享一道面试题:模拟Spring IOC 控制反转实现原理,建议

          本文链接:https://www.haomeiwen.com/subject/fimvfltx.html