Java 在运行时解析实现 //在Coffee.jar中定义的接口。 界面咖啡{ void brew(); 作废作废(); } //BlackCoffee.jar中定义的实现 类黑咖啡{ @凌驾 公共空间{ System.out.println(“Brew BalckCoffee”); } @凌驾 公共作废作废(){ System.out.println(“丢弃黑咖啡”); } } //filterOffee.jar中定义的实现 类FilterOffee实现了Coffee{ @凌驾 公共空间{ System.out.println(“Brew过滤器报价”); } @凌驾 公共作废作废(){ System.out.println(“丢弃过滤器报价”); } } //Coffee.jar中的运行时类 布雷科菲级{ 公共静态void main(字符串[]args){ 咖啡=//这里有些东西; 咖啡; 咖啡。丢弃(); } }

Java 在运行时解析实现 //在Coffee.jar中定义的接口。 界面咖啡{ void brew(); 作废作废(); } //BlackCoffee.jar中定义的实现 类黑咖啡{ @凌驾 公共空间{ System.out.println(“Brew BalckCoffee”); } @凌驾 公共作废作废(){ System.out.println(“丢弃黑咖啡”); } } //filterOffee.jar中定义的实现 类FilterOffee实现了Coffee{ @凌驾 公共空间{ System.out.println(“Brew过滤器报价”); } @凌驾 公共作废作废(){ System.out.println(“丢弃过滤器报价”); } } //Coffee.jar中的运行时类 布雷科菲级{ 公共静态void main(字符串[]args){ 咖啡=//这里有些东西; 咖啡; 咖啡。丢弃(); } },java,Java,然后,想法是在不知道实现的情况下在运行时解析实现。 该应用程序将具有Coffee.jar的依赖项,以及BlackCoffee.jar或FilterCoffee.jar的依赖项。这是依赖项注入框架(如Spring)的优点之一 您对接口编写代码,而您的客户机类不知道在运行时实例化了哪个实现 你可以根据条件来选择 e、 g.在Spring中,您可以使用@Conditional属性 @ConditionalOnProperty("coffee.black") class BlackCoffee impl

然后,想法是在不知道实现的情况下在运行时解析实现。
该应用程序将具有Coffee.jar的依赖项,以及BlackCoffee.jar或FilterCoffee.jar的依赖项。

这是依赖项注入框架(如Spring)的优点之一

您对接口编写代码,而您的客户机类不知道在运行时实例化了哪个实现

你可以根据条件来选择 e、 g.在Spring中,您可以使用@Conditional属性

@ConditionalOnProperty("coffee.black")
class BlackCoffee implements Coffee 

@ConditionalOnProperty("coffee.filter")
class BlackCoffee implements Coffee 
然后有

@Component
class ClassUsingCoffee {
    private Coffee coffee;

    @Inject
    public ClassUsingCoffee(Coffee coffee) {
        this.coffee = coffee;
    }

    //use coffee as normal
}
然后在Spring的属性中,您可以定义属性“black”或“filter”来激活两个具体类实现中的一个。如果您同时定义了这两个属性,您会得到一个异常,说明存在两个Coffee实例,并且它不知道使用Coffee将哪个(依赖项注入)注入
ClassUsingCoffee

如果不深入了解Spring的细节,很难解释。但是您也可以使用
ApplicationContext
(将其视为包含Spring知道的所有类的“东西”)


在这两个示例中,您都将类耦合到
Coffee
接口,而不是特定的实现。e、 g.如果您做了
Coffee Coffee=new BlackCoffee()
,那么您的代码将耦合到Coffee的特定实现(在本例中为
BlackCoffee
),任何需要的更改都需要代码更改(与配置/属性更改相反)

这是依赖项注入框架(如Spring)的优点之一

您对接口编写代码,而您的客户机类不知道在运行时实例化了哪个实现

你可以根据条件来选择 e、 g.在Spring中,您可以使用@Conditional属性

@ConditionalOnProperty("coffee.black")
class BlackCoffee implements Coffee 

@ConditionalOnProperty("coffee.filter")
class BlackCoffee implements Coffee 
然后有

@Component
class ClassUsingCoffee {
    private Coffee coffee;

    @Inject
    public ClassUsingCoffee(Coffee coffee) {
        this.coffee = coffee;
    }

    //use coffee as normal
}
然后在Spring的属性中,您可以定义属性“black”或“filter”来激活两个具体类实现中的一个。如果您同时定义了这两个属性,您会得到一个异常,说明存在两个Coffee实例,并且它不知道使用Coffee将哪个(依赖项注入)注入
ClassUsingCoffee

如果不深入了解Spring的细节,很难解释。但是您也可以使用
ApplicationContext
(将其视为包含Spring知道的所有类的“东西”)


在这两个示例中,您都将类耦合到
Coffee
接口,而不是特定的实现。e、 g.如果您确实执行了
Coffee Coffee=new BlackCoffee()
,那么您的代码将与Coffee的特定实现相耦合(在本例中为
BlackCoffee
),并且所需的任何更改都需要代码更改(与配置/属性更改相反)

如果您希望选择接口的实现,因为类路径上存在实现的jar文件,那么您应该使用服务加载程序框架

有关更多信息,请参阅

在您的情况下,从组织代码开始,即将类放入包中:

package com.example.api;

public interface Coffee {
    ...
}
然后像这样包装:

  • com/example/api/Coffee.class
    放入文件
    Coffee.jar

  • com/example/black/BlackCoffee.class
    与文件
    META-INF/services/com.example.api.Coffee
    和内容
    com.example.black.BlackCoffee

  • com/example/filter/FilterCoffee.class
    与文件
    META-INF/services/com.example.api.Coffee
    和内容
    com.example.filter.FilterCoffee

  • com/example/BrewCoffee.class
    放入文件
    brew.jar

现在可以使用以下命令之一运行程序:

java-cp brew.jar;咖啡罐;black.jar.com.example.BrewCoffee
java-cp brew.jar;咖啡罐;filter.jar.com.example.BrewCoffee
java-cp brew.jar;咖啡罐;black.jar;filter.jar.com.example.BrewCoffee
注意:在Linux上,替换


由于
main
方法在所有实现中循环,如果您希望选择接口的实现,因为类路径上存在实现的jar文件,则第三个命令将与
BlackCoffee
FilterCoffee
一起运行,然后您应该使用服务加载器框架

有关更多信息,请参阅

在您的情况下,从组织代码开始,即将类放入包中:

package com.example.api;

public interface Coffee {
    ...
}
然后像这样包装:

  • com/example/api/Coffee.class
    放入文件
    Coffee.jar

  • com/example/black/BlackCoffee.class
    与文件
    META-INF/services/com.example.api.Coffee
    和内容
    com.example.black.BlackCoffee

  • com/example/filter/FilterCoffee.class
    与包含内容
    com的文件
    META-INF/services/com.example.api.Coffee
    放在文件
    filter.jar
    中。
    package com.example;
    
    import com.example.api.Coffee;
    
    public class BrewCoffee {
        public static void main(String[] args) {
            for (Coffee coffee : ServiceLoader.load(Coffee.class)) {
                coffee.brew();
                coffee.discard();
            }
        }
    }