2


我有一个要求,其中我在 Spring 项目中定义了一个合同,并希望在部署期间自动装配一个外部 JAR,以实现合同(接口集)。我不想强制外部 JAR 依赖于 Spring,以便它尽可能灵活。在我的 Spring 项目中,无论我在哪里使用合同接口,都不能使用外部 JAR 中的类作为自动装配替换吗?让我用一个例子来解释:

Spring project:
@Controller
public class MyController {
     @Autowired
     private MyInterface interface;
}

现在实现契约接口的JAR可能是客户端提供的,我可能事先不知道包名,甚至可能是非Spring项目,所以不能用@Component注解声明。

例如

public class CustomerClass implements MyInterface {
}

现在在我的spring项目中,有没有办法注入CustomerClass来代替MyInterface?我希望我的问题很清楚。

谢谢

4

3 回答 3

2

@Paddy,关于您是否可以通过传统的 XML 方式实现相同目标的担忧。下面是一个示例代码,展示了如何实现它。注意:接口MyInterface不能以这种方式动态,因为控制器持有对 MyInterface 的引用

Spring 应用程序上下文配置:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
   <property name="locations" value="classpath:test.properties" />
</bean>
<bean id="myInterface" class="${myinterface.impl}"></bean>

MyInterface 和两个不同的实现类

package au.net.test;

public interface MyInterface {

    public String getMessage();
}

public class MyClass1 implements MyInterface{

    public String getMessage(){
        return "message from class 1";
    }
}

public class MyClass2 implements MyInterface{

    public String getMessage() {
        return "message from class 2";
    }   
}

类路径下的 test.properties 文件(您可以使用 ant 脚本和 maven 配置文件来更改属性值)

myinterface.impl=au.net.test.MyClass2

web层控制器(可以基于动态bean候选注入实现类)

@Autowired
private MyInterface myInterface;
于 2013-02-04T11:28:45.920 回答
1

好的,我明白了。如果是这样,你的问题标题应该是如何通过 Spring Container 注入动态类型的类现在让我们谈谈解决方案。首先,您需要有某种属性来保存完全限定的类名。然后您可以在运行时将自定义 bean 注册到 spring 容器中。

ClassPathXmlApplicationContext applicationContext = new    ClassPathXmlApplicationContext("classpath:/applicationContext*");
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory();
            //register your bean at runtime 
        beanFactory.registerBeanDefinition("myClass", BeanDefinitionBuilder.rootBeanDefinition("au.net.test.DynamicClass").getBeanDefinition());
            //retrieve you bean from spring container
        Object myBean = applicationContext.getBean("myClass");
            //cast to the type of your bean class or interface (be really careful)
        System.out.println(((DynamicClass)myBean).getMessage());


package au.net.test;
//this is the bean gets looked up and injected at runtime
public class DynamicClass {
    //simple method to verify it is working
    public String getMessage(){
        return "this is testing message";
    }
}

在上面的代码中,您只需要使“au.net.test”属性值驱动而不是硬编码。

于 2013-02-04T09:09:59.310 回答
0

您可以将 factory-bean 与 factory-method 一起使用

<bean id="serviceProvider" class="package.ServiceProvider">

<bean id="myInterface"
      factory-bean="serviceProvider"
      factory-method="createMyInterfaceInstance"/>
//it might or might not to be a singleton factory, depending on your requirement.
public class ServiceProvider{
  private static MyInterface myInterface= new CustomerClass();

  private ServiceProvider() {}

  public MyInterface createMyInterfaceInstance() {
    return myInterface;
  }
}

所以基本上这里的想法是你必须创建自己的工厂类和工厂方法来创建实例,根据你的工厂,它可能会创建单例或原型。然后把剩下的工作留给弹簧容器。

于 2013-02-04T06:44:38.547 回答