Reputation: 746
I've a 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();
}
}
And following other handlers with interface.
Can I inject dependencies with Spring Boot by only interface type handler?
@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...");
}
}
Or I want to try something like this below. Is it possible ?
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();
}
}
}
So, type of handler depends on user's message. I don't know how Spring can choose which handler gonna be used in this context. Any solution?
Upvotes: 2
Views: 3138
Reputation: 3561
There can be multiple solution to this case.
Option #1
You can tweak a design of your handler a bit.
For instance you can introduce a method
boolean canHandle(String message);
so each handler can answer whether passed message can be handled or not.
Then you can inject a list of all handlers into your MainHandler
.
private List<Handler> handlers;
Now having that list you can call each handler by message:
public void action(String message) {
handlers.stream()
.filter(h -> h.canHandle(message))
.forEach(handler -> handler.handle());
}
Full example:
@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);
}
}
}
Option #2
Use qualifiers.
You can name your handlers however you like and then inject a Map<String, Handler>
into your mainHandler
. The key would be a bean name and the value - the actual handler. Spring will automatically take care of this.
@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...");
}
}
}
The 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...
Upvotes: 3
Reputation: 16439
There are two simple ways in which you can approach :
@Qualifier
to inject the desired particular bean.For example
@Component
class MainHandler {
@Autowired
@Qualifier("videoHandler") // example
private Handler handler;
public void action(){
handler.message(); // this will print playing video...
}
}
ApplicationContext
.For example :
@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();
}
}
}
Upvotes: 2