Paddy
Paddy

Reputation: 3640

How to setup autowiring for classes from external non-spring project


I have a requirement wherein I define a contract in Spring project and want to autowire an external JAR during deploy that implements the contract (set of interfaces). I do not want to enforce the external JAR to be Spring-dependent so that it is as flexible as possible. Is it not possible in my Spring project to use the classes from external JAR as autowire substitutions wherever I am using my contract interfaces? Let me explain with an example:

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

Now the JAR implementing the contract interfaces may be provided by client and I may not know the package names before hand and it could even be a non-Spring project, so it may not be declared with @Component annotation.

e.g.

public class CustomerClass implements MyInterface {
}

Now in my spring project, is there a way to inject CustomerClass in place of MyInterface? I hope my question is clear.

Thanks

Upvotes: 2

Views: 2190

Answers (3)

spiritwalker
spiritwalker

Reputation: 2257

@Paddy, Regarding to your concern about whether you can traditional XML way to achieve the same goal. The following is a sample code showing how to achieve it. Note: the interface MyInterface cannot be dynamic in this way, because the controller is holding a refernece to MyInterface .

Spring application context config :

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

MyInterface and two different implementation class

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 file under classpath(you can use ant script and maven profile to change property value)

myinterface.impl=au.net.test.MyClass2

web layer Controller (you can inject the implementation class based on dynamic bean candidate)

@Autowired
private MyInterface myInterface;

Upvotes: 2

spiritwalker
spiritwalker

Reputation: 2257

Ok, I got you point. If that is the case, your question title should be How to inject dynamic type of class by Spring Container Now let's talk about the solution. First, you need to have some kind of properties to hold fully qualified class name. And then you can register you custom bean at runtime into spring container.

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";
    }
}

In the code above, you just need make "au.net.test" property value driven rather than hard coding.

Upvotes: 1

spiritwalker
spiritwalker

Reputation: 2257

You can use factory-bean along with 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;
  }
}

So basically the idea here is that you have to create your own factory class and factory method for creating instance, depending on your factory, it might create singleton or prototype istance. And then just leave the rest of jobs to spring container.

Upvotes: 0

Related Questions