[英]Dependency Injection with interface in Spring
我有一个MainHandler class:
@Component
class MainHandler {
//inject this
private Handler handler;
@Autowired
public MainHandler(Handler handler){
this.handler = handler;
}
public void action(String message){
//watch photo
if (message.equals("photo")){
handler.handle();
}
if(message.equals("audio")){
//play music
handler.handle();
}
if(message.equals("video")){
//play video
handler.handle();
}
}
并跟随其他带有接口的处理程序。
我可以通过仅通过接口类型处理程序启动的 Spring 注入依赖项吗?
@Component
public interface Handler {
void handle();
}
@Component
class PhotoHandler implements Handler {
public void handle(){
System.out.println("Featuring photo...");
}
}
@Component
class VideoHandler implements Handler {
public void handle(){
System.out.println("Playing video...");
}
}
@Component
class AudioHandler implements Handler {
public void handle(){
System.out.println("Playing music...");
}
}
或者我想在下面尝试这样的事情。 可能吗?
class MainHandler {
private VideoHandler videoHandler;
private AudioHandler audioHandler;
private PhotoHandler photoHandler;
@Autowired
public MainHandler(VideoHandler videoHandler,
AudioHandler audioHandler,
PhotoHandler photoHandler) {
this.videoHandler = videoHandler;
this.audioHandler = audioHandler;
this.photoHandler = photoHandler;
}
public void action(String message){
//watch photo
if (message.equals("photo")){
photoHandler.handle();
}
if(message.equals("audio")){
//play music
audioHandler.handle();
}
if(message.equals("video")){
//play video
videoHandler.handle();
}
}
}
因此,处理程序的类型取决于用户的消息。 我不知道 Spring 如何选择在这种情况下使用哪个处理程序。 有什么解决办法吗?
有两种简单的方法可以接近:
@Qualifier
注入所需的特定bean。例如
@Component
class MainHandler {
@Autowired
@Qualifier("videoHandler") // example
private Handler handler;
public void action(){
handler.message(); // this will print playing video...
}
}
ApplicationContext
。例如:
@Component
class MainHandler {
@Autowired
private ApplicationContext context;
public void action(String message){
//watch photo
if (message.equals("photo")){
((PhotoHandler) context.getBean(PhotoHandler.class)).handle();
}
if(message.equals("audio")){
//play music
((AudioHandler) context.getBean(AudioHandler.class)).handle();
}
if(message.equals("video")){
//play video
((VideoHandler) context.getBean(VideoHandler.class)).handle();
}
}
}
这种情况可以有多种解决方案。
选项1
您可以稍微调整处理程序的设计。
例如你可以引入一个方法
boolean canHandle(String message);
因此每个处理程序都可以回答是否可以处理传递的消息。
然后,您可以将所有处理程序的列表注入MainHandler
。
private List<Handler> handlers;
现在有了该列表,您可以通过消息调用每个处理程序:
public void action(String message) {
handlers.stream()
.filter(h -> h.canHandle(message))
.forEach(handler -> handler.handle());
}
完整示例:
@SpringBootApplication
public class SO62370917 {
public static void main(String[] args) {
SpringApplication.run(SO62370917.class, args);
}
@Component
static class MainHandler {
private final List<Handler> handlers;
MainHandler(List<Handler> handlers) {
this.handlers = handlers;
}
public void action(String message) {
handlers.stream()
.filter(h -> h.canHandle(message))
.forEach(Handler::handle);
}
}
@Bean
CommandLineRunner cmd(MainHandler mainHandler) {
return args -> {
mainHandler.action("video");
mainHandler.action("audio");
mainHandler.action("photo");
};
}
interface Handler {
void handle();
boolean canHandle(String message);
}
@Component
class PhotoHandler implements Handler {
public void handle(){
System.out.println("Featuring photo...");
}
@Override
public boolean canHandle(String message) {
return "photo".equals(message);
}
}
@Component
class VideoHandler implements Handler {
public void handle(){
System.out.println("Playing video...");
}
@Override
public boolean canHandle(String message) {
return "video".equals(message);
}
}
@Component
class AudioHandler implements Handler {
public void handle(){
System.out.println("Playing music...");
}
@Override
public boolean canHandle(String message) {
return "audio".equals(message);
}
}
}
选项#2
使用限定符。
您可以随意命名您的处理程序,然后将Map<String, Handler>
注入您的mainHandler
。 键是 bean 名称和值 - 实际的处理程序。 Spring 会自动处理这个问题。
@SpringBootApplication
public class SO62370917 {
public static void main(String[] args) {
SpringApplication.run(SO62370917.class, args);
}
@Component
static class MainHandler {
private final Map<String, Handler> handlers;
MainHandler(Map<String, Handler> handlers) {
this.handlers = handlers;
}
public void action(String message) {
if (handlers.containsKey(message)) {
handlers.get(message).handle();
}
}
}
@Bean
CommandLineRunner cmd(MainHandler mainHandler) {
return args -> {
mainHandler.action("video");
mainHandler.action("audio");
mainHandler.action("photo");
};
}
interface Handler {
void handle();
}
@Component("photo")
class PhotoHandler implements Handler {
public void handle() {
System.out.println("Featuring photo...");
}
}
@Component("video")
class VideoHandler implements Handler {
public void handle() {
System.out.println("Playing video...");
}
}
@Component("audio")
class AudioHandler implements Handler {
public void handle() {
System.out.println("Playing music...");
}
}
}
output:
2020-06-14 13:06:47.140 INFO 29447 --- [ main] com.example.demo.SO62370917 : Started SO62370917 in 1.356 seconds (JVM running for 1.795)
Playing video...
Playing music...
Featuring photo...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.