zoukankan      html  css  js  c++  java
  • Spring IoC02

         IoC顾名思义为“控制反转”,就是反转资源获取的方向,容器主动将资源注入到它所管理的组件里,组件所要做的工作仅仅是选择一种合适的方式接受资源。而传统的思维方式是:当一个组件需要外部资源时,组件会向容器发送查找资源的请求,容器再将找到的资源传送给该组件。由此开来IoC的优势是组件不需要知道如何获取资源,只需要选择接受资源的方式,从而降低的模块之间的耦合度,也是体现出这种设计原则优点。

        说道IoC就不得不说DI(依赖注入),其实他们的设计思想是相同的,不过DI是IoC的一个良好的实现。下面来说说DI所做的工作:

        在DI模式下,容器全权负责组件的装配工作,容器会将一些之前定义好的方式(如setter方法或构造函数)将匹配的资源注入到每个组件里。

        .setter注入     setter注入会存在一些问题,1.容易出现忘记调用setter方法注入组件所需要的依赖,将会导致NullPointetException异常。2.代码会存在安全问题,第一次注入后,不能阻止再次调用setter,除非添加额外的处理工作。

        .构造器注入     构造器注入能够一定程度上解决setter注入的问题。但是该注入方式也会带来一些问题,如果组件有很多的依赖,则构造函数的参数列表将会变得冗长,会降低代码的可读性。

        .接口注入        该注入的方式使用的非常少,它要求组件必须实现某个接口,容器是透过这个接口实现注入依赖的。接口注入的缺点比较明显,使用接口注入需要实现特定的接口,而接口又特定与容器,所以组件对容器产生依赖,一旦脱离容器,组件不能重用。这是一种“侵入式”注入。

         由此可见常用到的注入方式是:setter和构造器注入

    /*生成报表的通用接口*/
    public interface ReportBuilder
    {
        public void build(String data);
    }
    
    /*生成HTML格式报表*/
    public class ReportHtmlBuilder implements ReportBuilder {
        @Override
        public void build(String data) {
            /*示意代码*/
            System.out.println("build html report!");
        }
    }
    
    /*生成PDF格式报表*/
    public class ReportPdfBuilder implements ReportBuilder {
        @Override
        public void build(String data) {
            System.out.println("build pdf report!");
        }
    }
    
    /*报表服务类*/
    public class ReportService 
    {
        /*依赖"ReportBuilder"*/
        private ReportBuilder builder;
        
        public ReportBuilder getBuilder()
        {
            return builder;
        }
        
        /*setter注入*/
        public void setBuilder(ReportBuilder builder)
        {
            this.builder = builder;
        }
    
        public void builderYearReport(int year)
        {
            this.builder.build("data");
        }
    }
    
    //IoC容器配置文件"component.properties"
    
    pdfBuilder=com.beliefbitrayal.ioc.inter.imp.ReportPdfBuilder
    htmlBuilder=com.beliefbitrayal.ioc.inter.imp.ReportHtmlBuilder
    reportService=com.beliefbitrayal.ioc.server.ReportService
    reportService.builder=htmlBuilder
    
    //IoC容器
    public class Container
    {
        /*用于储存Component的容器*/
        private Map<String, Object> repository = new HashMap<String, Object>();
    
        public Container()
        {
            try
            {
                /*读取容器配置文件"component.properties"*/
                Properties properties = new Properties();
                properties.load(new FileInputStream("src/component.properties"));
                
                /*获取配置文件的每一行信息*/
                for(Map.Entry<Object, Object> entry : properties.entrySet())
                {
                    String key = (String)entry.getKey();
                    String value = (String)entry.getValue();
                    
                    /*处理配置文件的每一行信息*/
                    this.handler(key, value);
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
        
        private void handler(String key,String value) throws Exception
        {
            /*
             * reportService=com.beliefbitrayal.ioc.server.ReportService
             * reportService.builder=htmlBuilder
             * 第一种情况,key值中间没有"."说明为一个新组件。对它的处理为创建它的对象,将其对象放入Map中。
             * 第二种情况,key值中间出现"."说明这个属性条目是一个依赖注入。根据"."的位置将这个key值划分为两部分,第一部分为组件的名字,第二部分为
             * 该组件需要设置的属性。
             */
            String[] parts = key.split("\\.");
            
            /*情况1*/
            if(parts.length == 1)
            {
                /*通过反射的方式创建组件的对象*/
                Object object = Class.forName(value).newInstance();
                
                this.repository.put(key, object);
            }
            else
            {
                /*对于情况2,首先用key值的第一部分(组件名)获取组件*/
                Object object = this.repository.get(parts[0]);
                
                /*再使用value值指定的组件名从Map对象中获取依赖*/
                Object reference = this.repository.get(value);
                
                /*将获取的依赖注入到指定的组件的相应属性上,"PropertyUtils"类属于Apache下Commons BeanUtil第三方类库,
                 * 要使用它还需要下载Commons Logging第三方类库
                 */
                PropertyUtils.setProperty(object, parts[1], reference);
            }
        }
    
        public Object getComponent(String key)
        {
            return this.repository.get(key);
        }
    }
    
    //根据配置文件,我们在场景类中使用的报表应该是HTML格式的:
    public class Client
    {
        public static void main(String[] args)
        {
            /*创建容器*/
            Container container = new Container();
            
            /*从容器中获取"报表服务类"*/
            ReportService reportService = (ReportService)container.getComponent("reportService");
            
            /*显示报表*/
            reportService.builderYearReport(0);
        }
    }
    
  • 相关阅读:
    星空雅梦
    星空雅梦
    星空雅梦
    星空雅梦
    星空雅梦
    星空雅梦
    星空雅梦
    星空雅梦
    lambda表达式
    VIM--保存和退出等命令
  • 原文地址:https://www.cnblogs.com/GenghisKhan/p/2342300.html
Copyright © 2011-2022 走看看