Reputation: 3640
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
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
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
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