我正在使用 Spring-Boot,使用类名字符串动态初始化一个类并获取返回值
Posted
技术标签:
【中文标题】我正在使用 Spring-Boot,使用类名字符串动态初始化一个类并获取返回值【英文标题】:I am using Spring-Boot, initialize a class dynamically using string of class name and get the returned values 【发布时间】:2019-08-02 10:44:47 【问题描述】:我在 Spring Boot 中工作,在 MyService class
中,我得到了一个作为 String 的类名,我想初始化该对象并取回返回值。
但是我对它没有更多的想法,我认为它是通过依赖注入实现的。但是,如何?
假设我有课程A.java, B.java, C.java
和服务课程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"
我希望wish()返回的输出。
谁能建议我如何实现它?
谢谢。
【问题讨论】:
为什么不在MyService
中使用@Autowire
?喜欢@Autowire A a;
@arnonuem 但是当我们有类名的字符串时,我们如何决定自动装配,例如`String classNameString = "A" or "B" or "C"`。感谢回复。
可能会有所帮助***.com/questions/5725222/…
【参考方案1】:
我可以在这里想到两种方法。第一种方法是命名类(在@Component 之后)并使用上下文,尝试获取 bean。您还可以使用 @Qualifier 命名 bean
@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));
第二种方法是让你所有的wisher类都实现一个接口,并遍历这个接口的所有实现bean并找到正确的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));
【讨论】:
感谢您的第一种方式对我有用。但我有一个疑问,在服务类中使用 Autowired ApplicationContext 是一个好习惯吗?它有什么缺点吗? @programmer420 我没有看到任何使用它的建议/反对意见。我们在生产代码本身中使用它。您可以尝试使用 ***.com/questions/4914012/… 中所述的 ApplicationContextAware 接口【参考方案2】:String 不是 Spring IoC 框架可管理的 bean,但类 A
、B
和 C
的实例是您的 bean。
你应该做的是声明类A
,B
和C
作为公共接口的实现,并通过这种类型注入对应的bean:
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);
【讨论】:
感谢在此回复,但我们这里以 A、B 或 C 为例。当我有组件类的字符串时,例如 String s =“A”或“B”或“C”。 你可以将你的字符串声明为 bean:@Bean String stringA() return "Hello A"+" good morning";
在一个用 @Configuration
注释的类中并注入它们,但这有什么意义吗?)))
我从对控制器和服务的请求中获取类名作为字符串,它必须在这里初始化这个类并返回特定的wish()。
在MyService
中有一个Map<String, Wisher> wishers
,其中名称映射到A
、B
和C
怎么样?当您收到带有名称的请求时,您可以从地图中检索相应的Wisher
并调用wisher.wish()
。
@star67 ,您的 Wisher 界面自动装配将不起作用。 Spring 不会理解 A 或 B 或 C 中的哪个 bean 到 Autowire。在这种情况下,您必须使用 Qualifier 注释。请在下面查看我的答案。【参考方案3】:
考虑到您使用 Spring 进行实现,所有 bean 都将是 Singleton,并且这些 bean 将在 App 启动时初始化(加载 ApplicationContext 时),然后应用程序无法检查要注入的实现。
因此,您无法在运行时使用依赖注入有条件地注入 bean
相反,您可以使用以下其他设计 -
@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);
【讨论】:
感谢您的回答是个好主意。我有一个问题,当我们与 ApplicationContext 一起去这里时有什么缺点(Praveen E 的回答以上)? 没有这样的缺点.. 现在开发人员通过 autowired 使用 applicationcontext,如下所示。这一切都归结为您认为应该选择实施的设计。我会更喜欢我建议的那个,因为我不希望 A、B、C 成为 applicationcontext 中的 spring bean,因为它没有做任何额外的事情来获得 spring bean 的资格以上是关于我正在使用 Spring-Boot,使用类名字符串动态初始化一个类并获取返回值的主要内容,如果未能解决你的问题,请参考以下文章
Spring-boot 使用环境变量使用破折号/连字符配置属性
如何使用 Selenium 和 VBA 识别包含特殊字符的元素类名
“类名必须是有效的对象或字符串”在没有 Composer 的情况下安装 PHPSecLib