How to autowire Spring service with Class name? - java

I have multiple services and I want to autowire this services dynamically with using their class names. I have a method named "runCustomService" and this methods takes service's class names as input parameter (like "Service1" or "Service2"). I want to autowire these services and call its run method. Is there any way to do this?
#Service
public class Service1 extends BaseService{
#Autowired
private AnotherService anotherService;
public void run(){ .... }
}
#Service
public class Service2 extends BaseService{
#Autowired
private AnotherService anotherService;
public void run(){ .... }
}
public void runCustomService(String serviceClassName){
BaseService baseService = //Create baseService object from serviceClassName
baseService.run();
}

You could use qualifiers on your two services and get the correct bean based on the qualifier name from the ApplicationContext.
#Service
#Qualifier("Service1")
public class Service1 extends BaseService{
#Service
#Qualifier("Service2")
public class Service2 extends BaseService{
#Autowired
ApplicationContext applicationContext;
public void runCustomService(String serviceClassName){
BaseService baseService = applicationContext.getBean(serviceClassName);
baseService.run();
}

Get an instance of ApplicationContext and get bean by a class name:
#Autowired
ApplicationContext ctx;
Use the method getBean(...):
BaseService baseService = ctx.getBean(Service1.class.getName());
However, as the other answer says, I recommend you to use #Qualifier(...) to inject a certain named conditionally.

Related

How to #Autowired a concrete implementation of a service?

I have the following situation:
public interface ServiceAura extends Serializable { }
#Service
public class ServiceA implements ServiceAura {
....
}
#Service
public class ServiceB implements ServiceAura {
....
}
Now from the controller I need to call both of them by separate:
#Path("")
#Controller
public class ServiciosAuraPortalRESTfulService {
#Autowired
private ServiceAura srvA;
#Autowired
private ServiceAura srvB;
}
I have read about #Qualified, is this the only way? How can I archive this?
You're right. You can use #Qualifier("ServiceA") to specify which implementation you want to autowire.
#Path("")
#Controller
public class ServiciosAuraPortalRESTfulService {
#Autowired
#Qualifier("ServiceA")
private ServiceAura srvA;
#Autowired
#Qualifier("ServiceB")
private ServiceAura srvB;
}
On the service itself, you can use the annotation #Primary to specify which one is the default implementation that you want.
Alternatively, you can use the application context to retrieve a specific bean. You'll need to autowire the ApplicationContext class and then retrieve it with ServiceAura srvA = context.getBean(ServiceA.class);
There are two ways to do this.
The first way is using #Qualifier annotation as you've stated.
#Path("")
#Controller
public class ServiciosAuraPortalRESTfulService {
#Autowired
#Qualifier("serviceA")
private ServiceAura srvA;
#Autowired
#Qualifier("serviceB")
private ServiceAura srvB;
}
Your services should be defined like this:
#Service
#Qualifier("serviceA")
public class ServiceA implements ServiceAura {
....
}
#Service
#Qualifier("serviceB")
public class ServiceB implements ServiceAura {
....
}
Another way is to create interfaces that extend interface ServiceAura
interface ServiceAInterface extends ServiceAura {
}
class ServiceA implements ServiceAInterface {}
.... // the same for service B
And then in code:
public class ServiciosAuraPortalRESTfulService {
#Autowired
ServiceAInterface serviceA;
}

Spring #Autowire another implementation of the current service

I need to have an interface and then two implementations in different maven modules. Both impl services see api modul with interface but they don't see each other.
There is a default implementation and then transactional implementation. I want transactional impl service just load and call default impl service. Like this:
package my.app.core.api;
public interface MyService {
boolean process();
}
package my.app.core.impl
#Service
public class MyServiceImpl implements MyService {
#Override
public boolean process() {
// do something cool...
}
}
package my.app.somewhere.else.impl
#Service
#Transactional
public class TransactionalMyServiceImpl implements MyService {
#Autowire
private MyService myService;
#Override
public boolean process() {
myService.process();
}
}
Is it possible or do I need to #Autowire explicitly MyServiceImpl instead of interface? Which means to add maven dependancy to my.app.somewhere.else.impl.pom.
You can give different names to your services like so:
#Service
#Qualifier("transactionalMyService")
And then when you autowire you can use the name:
#Autowired
#Qualifier("transactionalMyService")
private MyService myService;

How to autowire Spring services that inherit?

I have 2 services, EFT and Cheque that are substantially similar.
Runs fine if I mark the implementation as #service.
Otherwise I get a no such bean definition exception. No qualifying bean of type 'EftPaymentService'.
Top level interface.
public interface PaymentService {
public void paymentsResponse();
}
Eft service interface.
#Service
public interface EftPaymentService extends
PaymentService {
public void processEft(String code) throws PaymentsException;
}
Cheque service interface
#Service
public interface ChequePaymentService extends
PaymentService {
public void processCheque(String code) throws PaymentsException;
}
Top level implementation
public abstract class PaymentServiceImpl implements PaymentService {
#Autowired
protected SessionFactory sftpSessionFactory;
#Autowired
protected SftpConfig.UploadGateway gateway;
public void paymentsResponse(){
}
}
Eft implementation
public class EftServiceImpl extends PaymentsServiceImpl implements EftPaymentService {
}
Cheque implementation
public class ChequeServiceImpl extends PaymentsServiceImpl implements ChequePaymentService {
}
What is going on here?
Refactor using composition?
Annotate implementations with #Service & use constructor-based injection.

Does autowiring work for classes instantiated from PerConnectionWebSocketHandler?

I can successfully read an autowired instance of HandlerSettings in the main class, so I know I have the application.properties entries correct.
#Component
#ConfigurationProperties(prefix="handler")
public class HandlerSettings {
private int timeout;
public int getTimeout(){
return timeout;
}
public void setTimeout(int timeout){
this.timeout = timeout;
}
}
I am having difficulties trying to autowire fields in the MyHandler class, which is instantiated within a PerConnectionWebSocketHandler.
#SpringBootApplication
#RestController
#EnableWebSocket
#EnableConfigurationProperties(HandlerSettings.class)
public class MyController implements WebSocketConfigurer{
#Bean
public WebSocketHandler myHandler() {
return new PerConnectionWebSocketHandler(MyHandler.class));
}
I want to autowire fields in an abstract base class of MyHandler.
#Component
public abstract class Handler implements WebSocketHandler {
#Autowired
private HandlerSettings handlerSettings;
...
}
MyHandler inherits from Handler:
public class MyHandler extends Handler
The example in the Spring documentation does not address what to do in either the case of inheritance, or the way classes are instantiated with the PerConnectionWebSocketHandler.
I have tried unsuccessfully to autowire fields in Handler. It is possible to autowire if the class is instantiated by PerConnectionWebSocketHandler? If so, is there something special I have to do to autowire the base class, but not the classes that extend it?
As per the Source Codes unless you set the PerConnectionWebSocketHandler.setBeanFactory in will instantiate a Handler without the Injected Beans.
#SpringBootApplication
#RestController
#EnableWebSocket
#EnableConfigurationProperties(HandlerSettings.class)
public class MyController implements WebSocketConfigurer {
#Autowired
private BeanFactory beanFactory;
#Bean
public WebSocketHandler myHandler() {
PerConnectionWebSocketHandler perConnectionWebSocketHandler = new PerConnectionWebSocketHandler(MyHandler.class);
perConnectionWebSocketHandler.setBeanFactory(beanFactory);
return perConnectionWebSocketHandler;
}
}

Create instance of call with autowire

I have to create a instance of a class, that have autowired elements, for test.
public class MyClass extends SomeOtherClass {
#Autowired
public MyClass(OtherClass1 one, OtherClass2 two){
super(one, two)
}
}
How can i in code create instance of this class, with the arguments wired in though spring?
Your test can be made Spring-aware if you use the SpringJUnit4ClassRunner to read in your Spring Context to be used in the test. For instance:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"the-config.xml"})
public final class MyClassTests {
#Autowired
private MyClass testee;
#Test
public void testSomething() {
assertThat(testee).doesSomethingExpected();
}
}
Note that you should reuse as much of your production config as possible and not create a parallel Spring Context config that mirrors it.
Instead of passing the other elements in as constructor arguments, you Autowire them as properties. Spring will then inject the objects.
public class MyClass extends SomeOtherClass {
#Autowired
private OtherClass1 one;
#Autowired
private OtherClass2 two
public MyClass(){
super(one, two)
}
}
Edit: Based on http://www.mkyong.com/spring/spring-auto-wiring-beans-with-autowired-annotation/, adding #Autowired to the constructor is also valid.
If you want to Autowire MyClass, you must annotate it with #Component or a similar annotation such as #Service.
#Component
public class MyClass extends SomeOtherClass
Then, you can use it in other classes
public class ClassThatUsesMyClass {
#Autowire
private MyClass myClass;
}

Categories

Resources