注入(Injection)是:

  Java EE提供了注入机制,使您的对象能够获取对资源和其他依赖项的引用,而无需直接实例化它们。通过使用将字段标记为注入点的注释之一来装饰字段或方法,可以在类中声明所需的资源和其他依赖项。然后容器在运行时提供所需的实例。注入简化了代码并将其与依赖项的实现分离。

注入(Injection)的用处:

  依赖注入:

    控制反转用于解耦,解的究竟是谁和谁的耦?这是我在最初了解依赖注入时候产生的第一个问题。

          下面我引用Martin Flower在解释介绍注入时使用的一部分代码来说明这个问题。

public class MovieLister {
    private MovieFinder finder;

    public MovieLister() {
        finder = new MovieFinderImpl();
    }
    
    public Movie[] moviesDirectedBy(String arg) {
        List allMovies = finder.findAll();
        for (Iterator it = allMovies.iterator(); it.hasNext();) {
            Movie movie = (Movie) it.next();
            if (!movie.getDirector().equals(arg)) it.remove();
        }
        return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
    }
    ...
}
public interface MovieFinder {
    List findAll();
}

    我们创建了一个名为MovieLister的类来提供需要的电影列表,它moviesDirectedBy方法提供根据导演名来搜索电影的方式。真正负责搜索电影的是实现了MovieFinder接口的MovieFinderImpl,我们的MovieLister类在构造函数中创建了一个MovieFinderImpl的对象。

    目前看来,一切都不错。但是,当我们希望修改finder,将finder替换为一种新的实现时(比如为MovieFinder增加一个参数表明Movie数据的来源是哪个数据库),我们不仅需要修改MovieFinderImpl类,还需要修改我们MovieLister中创建MovieFinderImpl的代码。

    这就是依赖注入要处理的耦合。这种在MovieLister中创建MovieFinderImpl的方式,使得MovieLister不仅仅依赖于MovieFinder这个接口,它还依赖于MovieListImpl这个实现。 这种在一个类中直接创建另一个类的对象的代码,和硬编码(hard-coded strings)以及硬编码的数字(magic numbers)一样,是一种导致耦合的坏味道,我们可以把这种坏味道称为硬初始化(hard init)。同时,我们也应该像记住硬编码一样记住,new(对象创建)是有毒的。

    Hard Init带来的主要坏处有两个方面:1)上文所述的修改其实现时,需要修改创建处的代码;2)不便于测试,这种方式创建的类(上文中的MovieLister)无法单独被测试,其行为和MovieFinderImpl紧紧耦合在一起,同时,也会导致代码的可读性问题(“如果一段代码不便于测试,那么它一定不便于阅读。”)。

  资源注入:

    通过资源注入,您可以将JNDI名称空间中可用的任何资源注入任何容器管理的对象,例如servlet,企业bean或托管bean。例如,您可以使用资源注入来注入JNDI名称空间中可用的数据源,连接器或自定义资源。用于引用注入实例的类型通常是一个接口,它将您的代码与资源的实现分离。

  例如,以下代码注入一个数据源对象,该对象提供与GlassFish Server附带的默认Apache Derby数据库的连接:

public class MyServlet extends HttpServlet {
    @Resource(name="java:comp/DefaultDataSource")
    private javax.sql.DataSource dsc;
    ...
}

   除了前面示例中的基于字段的注入之外,您还可以使用基于方法的注入注入资源:

public class MyServlet extends HttpServlet {
    private javax.sql.DataSource dsc;
    ...
    @Resource(name="java:comp/DefaultDataSource")
    public void setDsc(java.sql.DataSource ds) {
        dsc = ds;
    }
}

  要使用基于方法的注入,setter方法必须遵循属性名称的JavaBeans约定:方法名称必须以set,以void返回类型开头,并且只有一个参数。的@Resource注释是在javax.annotation包装和在JSR 250(通用注解用于Java平台)被定义。资源注入按名称解析,因此它不是类型安全的:资源对象的类型在编译时是未知的,因此如果对象的类型及其引用不匹配,则可能会出现运行时错误。