美文网首页聊技术
Java 依赖注入总结

Java 依赖注入总结

作者: 半夜菊花茶 | 来源:发表于2017-11-03 22:09 被阅读0次

    最近在研读Hive社区版本的源码,发现其中多处用到了Java依赖注入,这里简单总结一下依赖注入的几种实现方法。在谈java依赖注入之前,有必要先回顾一下设计模式中的Proxy模式。

    其实每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法。先来看看关系图:

    image.png

    根据上文的阐述,代理模式就比较容易的理解了,我们看下代码:

    public interface Sourceable {
        public void method();
    }
    
       @Override
        public void method() {
            System.out.println("the original method!");
        }
    
     public class Proxy implements Sourceable {
    
        private Source source;
        public Proxy(){
            super();
            this.source = new Source();
        }
        @Override
        public void method() {
            before();
            source.method();
            atfer();
        }
        private void atfer() {
            System.out.println("after proxy!");
        }
        private void before() {
            System.out.println("before proxy!");
        }
    }
    

    测试类

    public class ProxyTest {
    
        public static void main(String[] args) {
            Sourceable source = new Proxy();
            source.method();
        }
    
    }
    

    输出:

    before proxy!
    the original method!
    after proxy!

    代理模式的应用场景:

    如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:

    1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。

    2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。

    使用代理模式,可以将功能划分的更加清晰,有助于后期维护!

    下面我们要说的Java依赖注入可以说就是proxy模式的一种应用,这里总结一下常用的三种依赖注入方法

    1. 接口注入

    我们常常借助接口来将调用者与实现者分离。如:

    public class ClassA {
    private InterfaceB clzB;
    public init() {
        Ojbect obj =
        Class.forName(Config.BImplementation).newInstance();
        clzB = (InterfaceB)obj;
    }
    ……
    }
    

    上面的代码中,ClassA依赖于InterfaceB 的实现,如何获得InterfaceB 实现类的实例?传统的方法是在代码中创建InterfaceB 实现类的实例,并将起赋予clzB。而这样一来,ClassA在编译期即依赖于InterfaceB 的实现。为了将调用者与实现者在编译期分离,于是有了上面的代码,我们根据预先在配置文件中设定的实现类的类名,动态加载实现类,并通过InterfaceB 强制转型后为ClassA所用。
    这就是接口注入的一个最原始的雏形。而对于一个接口注入型IOC容器而言,加载接口实现并创建其实例的工作由容器完成,如J2EE开发中常用的Context.lookup(ServletContext.getXXX),都是接口注入型IOC的表现形式。
    Apache Avalon是一个典型的Type1型IOC容器。

    2. 构造子注入

    构造子注入,即通过构造函数完成依赖关系的设定,如:

     public class DIByConstructor {
    private final DataSource dataSource;
    private final String message;
    public DIByConstructor(DataSource ds, String msg) {
        this.dataSource = ds;
        this.message = msg;
    }
    ……
    }
    

    可以看到,在Type2类型的依赖注入机制中,依赖关系是通过类构造函数建立,容器通过调用类的构
    造方法,将其所需的依赖关系注入其中。
    PicoContainer(另一种实现了依赖注入模式的轻量级容器)首先实现了Type2类型的依赖注入模式。

    3. 设置注入

    这种方式广泛应用在Spring框架的参数配置中,客户代码仅仅面向接口编程,而无需知道实现类的具体名称。同时,我们可以很简单的通过修改配置文件来切换具体的底层实现类。下面我们抛开Spring框架本身,使用一个简单的例子来实现类似Spring的依赖注入
    
    public class ActionFactory {
        public static Action getAction(String actionName) {
          Properties pro = new Properties();
          try {
            pro.load(new FileInputStream("config.properties"));
            String actionImplName = (String) pro.get(actionName);
            String actionMessage = (String) pro.get(actionName + "_msg");
            Object obj = Class.forName(actionImplName).newInstance();
    
            // BeanUtils是Apache Commons BeanUtils提供的辅助类
            BeanUtils.setProperty(obj, "message", actionMessage);
            return (Action) obj;
          } catch (FileNotFoundException e) {
            e.printStackTrace();
          } catch (IOException e) {
            e.printStackTrace();
          } catch (ClassNotFoundException e) {
            e.printStackTrace();
          } catch (InstantiationException e) {
            e.printStackTrace();
          } catch (IllegalAccessException e) {
            e.printStackTrace();
          } catch (InvocationTargetException e) {
            e.printStackTrace();
          }
          return null;
        }
      }
    

    配置文件则采用最简单的properties文件形式:
    TheAction=net.xiaxin.spring.qs.UpperAction
    TheAction_msg=HeLLo

    测试类:

    public void testFactory(){
        Action action = ActionFactory.getAction("TheAction");
        System.out.println(action.execute("Rod Johnson"));
    }
    

    上面的例子中,我们通过设置注入,在运行期动态将字符串“HeLLo” 注入到Action实现类的Message属性中。用同样的方法,我们可以通过修改配置文件让程序调用不同的实现方法,从而实现灵活的依赖注入。在Hive源码中,HiveDriverRunHook类也是使用这种方式实现注入的

    相关文章

      网友评论

        本文标题:Java 依赖注入总结

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