I am working in Spring Boot, and in MyService class
I got a class name as String and i want to initialize that object and get back returned values.
but I have no much more idea about it, I think it achieved by Dependency injection. but, how ?
Suppose I have classes A.java, B.java, C.java
and Service class MyService.java
@Component
public class A{
public String wish(int timeHr){
//some logic of time based wish
return "Hello A"+" good morning";
}
}
@Component
public class B{
public String wish(int timeHr){
//some logic of time based wish
return "Hello B"+" good morning";
}
}
@Component
public class C{
public String wish(int timeHr){
//some logic of time based wish
return "Hello C"+" good morning";
}
}
@Service
public class MyService{
// i get here A class name as String like,
String classNameString = "A"; // or "B", or "C"
int timrHr = new Date().getHours();
//how to here i will initialize above class and get method wist(param) returned wish msg.
//like, a.wish(timeHr); and it gives "Hello A good morning"
}
I expect the output of returned by wish().
Can any one suggest me how do I achieved it ?
Thanks.
3 Answers 3
I can think of two ways here. First way is to name the class (after @Component) and using context, try to get the bean. You can also name the bean using @Qualifier
@Component("A")
public class A{
public String wish(int timeHr){
//some logic of time based wish
return "Hello A"+" good morning";
}
@Component("B")
public class B{
public String wish(int timeHr){
//some logic of time based wish
return "Hello B"+" good morning";
}
}
@Component("C")
public class C{
public String wish(int timeHr){
//some logic of time based wish
return "Hello C"+" good morning";
}
}
@Service
public class MyService{
@Autowired
private ApplicationContext context;
void myMethod() {
A a = (A) context.getBean("A");
System.out.println(a.wish(123));
}
}
Second way is to make all your wisher classes implement an interface and iterate through all the implementing beans of this interface and find the correct bean
@Component
public class A implements Wisher{
public String wish(int timeHr){
//some logic of time based wish
return "Hello A"+" good morning";
}
@Component
public class B implements Wisher{
public String wish(int timeHr){
//some logic of time based wish
return "Hello B"+" good morning";
}
}
@Component
public class C implements Wisher{
public String wish(int timeHr){
//some logic of time based wish
return "Hello C"+" good morning";
}
}
public interface Wisher{ public String wish(int time); }
@Service
public class MyService{
@Autowired
private List<Wisher> wishers;
void myMethod() {
String requiredClassName = "A";
Wisher requiredWisher = null;
for (int i = 0; i < wishers.length(); i++) {
Wisher w = wishers.get(i);
if (w.getClass().getName().equals(requiredClassName)) {
requiredWisher = w;
break;
}
System.out.println(w.wish(123));
}
}
}
-
Thanks your 1st way is work for me. But i have a doubt, Is it a good practice to Autowired ApplicationContext in service class and it have any disadvantage of it ?programmer420– programmer4202019年08月02日 13:04:43 +00:00Commented Aug 2, 2019 at 13:04
-
1@programmer420 I don't see any adv/disadv of using it. We are using it in production code itself. You can try using ApplicationContextAware interface as said in stackoverflow.com/questions/4914012/…Praveen E– Praveen E2019年08月02日 13:10:21 +00:00Commented Aug 2, 2019 at 13:10
String is not a manageable bean by Spring IoC framework, but instances of classes A
, B
and C
are your beans.
What you should do is to declare the classes A
, B
and C
as implement of the common interface and inject a corresponding bean by this type:
interface Wisher {
String wish(int timeHr);
}
@Component
public class A implements Wisher {
public String wish(int timeHr){
//some logic of time based wish
return "Hello A"+" good morning";
}
}
@Component
public class B implements Wisher {
public String wish(int timeHr){
//some logic of time based wish
return "Hello B"+" good morning";
}
}
@Component
public class C implements Wisher {
public String wish(int timeHr){
//some logic of time based wish
return "Hello C"+" good morning";
}
}
@Service
public class MyService{
@Autowired
private Wisher a; // instance of "A" or "B", or "C"
void myMethod() {
int timrHr = new Date().getHours();
wisher.wish(timrHr);
}
}
-
Thanks to replying here, But to we instance here A, B, or C . when i have String of Component class like String s ="A" or "B" or "C".programmer420– programmer4202019年08月02日 11:02:31 +00:00Commented Aug 2, 2019 at 11:02
-
you can declare your strings as beans:
@Bean String stringA() { return "Hello A"+" good morning";}
in a class annotated with@Configuration
and inject them, but does it make any sense?)))star67– star672019年08月02日 11:11:36 +00:00Commented Aug 2, 2019 at 11:11 -
i get class name as a String from request to Controller and Service, it must initialise this class here and returned the particular wish().programmer420– programmer4202019年08月02日 11:21:14 +00:00Commented Aug 2, 2019 at 11:21
-
1what about having a
Map<String, Wisher> wishers
inMyService
where names are mapped toA
,B
andC
? when you receive a request with a name you can retrieve a correspondingWisher
from the map and callwisher.wish()
.star67– star672019年08月02日 11:24:28 +00:00Commented Aug 2, 2019 at 11:24 -
2@star67 , your autowiring of Wisher interface will not work. Spring will not understand which bean among A or B or C to Autowire. In such cases, you have to use Qualifier annotation. Please see my answer below.Praveen E– Praveen E2019年08月02日 12:35:39 +00:00Commented Aug 2, 2019 at 12:35
Considering you are using Spring for implementation all your beans will be Singleton and these will be initialized at the start of App(when ApplicationContext is loaded) and then at that time application has no way to check which implementation to inject.
So there is no way you can conditionally inject bean at runtime with Dependency injection
instead you can use other design like below -
@Service
public class MyService{
private Wisher wisher;
public Wisher setupWisher(String class){
if (class.equals("A")) {
wisher = new A();
}else if(class.equals("B")){
wisher = new B();
}else if(class.equals("C")){
wisher = new C();
}
}
void myMethod(String requestString) {
int timrHr = new Date().getHours();
setupWisher(requestString).wish(timrHr);
}
}
-
thanks for replying your answer is a good idea . i have a question , what is disadvantage when we go here with ApplicationContext (above answer by Praveen E) ?programmer420– programmer4202019年08月02日 13:08:04 +00:00Commented Aug 2, 2019 at 13:08
-
1there is no such disadvantage.. nowadays developers use applicationcontext by autowired just as below. it all boils down to design which you think should be selected for implementation. I will prefer the one i suggested as i don't want A,B,C to be spring bean within applicationcontext because it does nothing extra to qualify as spring beanpsi– psi2019年08月03日 09:45:29 +00:00Commented Aug 3, 2019 at 9:45
@Autowire
in yourMyService
? Like@Autowire A a;