英文:
Spring inject two implementations of an interface to use bridge design pattern
问题
Color.java
package com.example.bridge;
public interface Color {
String fill();
}
Blue.java
package com.example.bridge;
import org.springframework.stereotype.Service;
@Service("Blue")
public class Blue implements Color {
@Override
public String fill() {
return "Color is Blue";
}
}
Red.java
package com.example.bridge;
import org.springframework.stereotype.Service;
@Service("Red")
public class Red implements Color {
@Override
public String fill() {
return "Color is Red";
}
}
Shape.java
package com.example.bridge;
public abstract class Shape {
protected Color color;
public Shape(Color color){
this.color = color;
}
abstract public String draw();
}
Square.java
package com.example.bridge;
import org.springframework.stereotype.Service;
@Service
public class Square extends Shape {
public Square(Color color) {
super(color);
}
@Override
public String draw() {
return "Square drawn. " + color.fill();
}
}
Triangle.java
package com.example.bridge;
@Service
public class Triangle extends Shape {
public Triangle(Color color) {
super(color);
}
@Override
public String draw() {
return "Triangle drawn. " + color.fill();
}
}
BridgeApplication.java
package com.example.bridge;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan("com.example.bridge.*")
public class BridgeApplication {
public static void main(String[] args) {
SpringApplication.run(BridgeApplication.class, args);
}
}
Test it:
package com.example.bridge;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestBridge {
@Autowired
@Qualifier("Red")
private Red red;
@Test
public void testBridge() {
//a square with red color
Shape square = new Square(red);
assertEquals(square.draw(), "Square drawn. Color is Red");
}
}
UPDATE:
First, I have noticed I was missing 'componentScan' for the main class and after it's added now the application runs. However, the same approach is not applicable to the test. Whether I have got the component scan or not this is what I get:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.bridge.Red' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=Red)}
英文:
I have implemented a sample of bridge design pattern in my application that uses Spring boot. I was wondering how I could manage to inject different implementations of an interface. Obviously, if I try to inject them it throws the required a single bean, but 2 were found
I would appreciate it if you could help to understand how this can be achieved in conjunction with dependency injection:
Color.java
package com.example.bridge;
public interface Color {
String fill();
}
Blue.java
package com.example.bridge;
import org.springframework.stereotype.Service;
@Service("Blue")
public class Blue implements Color {
@Override
public String fill() {
return "Color is Blue";
}
}
Red.java
package com.example.bridge;
import org.springframework.stereotype.Service;
@Service("Red")
public class Red implements Color {
@Override
public String fill() {
return "Color is Red";
}
}
Shape.java
package com.example.bridge;
public abstract class Shape {
protected Color color;
public Shape(Color color){
this.color = color;
}
abstract public String draw();
}
Square.java
package com.example.bridge;
import org.springframework.stereotype.Service;
@Service
public class Square extends Shape {
public Square(Color color) {
super(color);
}
@Override
public String draw() {
return "Square drawn. " + color.fill();
}
}
Triangle.java
package com.example.bridge;
@Service
public class Triangle extends Shape {
public Triangle(Color color) {
super(color);
}
@Override
public String draw() {
return "Triangle drawn. " + color.fill();
}
}
BridgeApplication.java
package com.example.bridge;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan("com.example.bridge.*")
public class BridgeApplication {
public static void main(String[] args) {
SpringApplication.run(BridgeApplication.class, args);
}
}
Test it:
package com.example.bridge;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestBridge {
@Autowired
@Qualifier("Red")
private Red red;
@Test
public void testBridge() {
//a square with red color
Shape square = new Square(red);
assertEquals(square.draw(), "Square drawn. Color is Red");
}
}
UPDATE:
First, I have noticed I was missing 'componentScan' for the main class and after it's added now the application runs. However, the same approach is not applicable to the test. Whether I have got the component scan or not this is what I get:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.bridge.Red' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=Red)}
答案1
得分: 1
@Qualifier
是解决方案。使用 @Qualifier("unique-name")
来标记 component
,在注入 bean 时使用这个限定符。
@Service("blue")
public class Blue implements Color {
@Override
public String fill() {
return "Color is Blue";
}
}
@Service("red")
public class Red implements Color {
@Override
public String fill() {
return "Color is Red";
}
}
在自动装配时,可以这样做:
@Autowired
@Qualifier("red")
private Color red;
EDIT
在进行构造函数注入时,按照以下方式操作:
```java
@Autowired
public SomeClassConstructor(@Qualifier("red") Color red) {
...
}
```
英文:
@Qualifier
is the solution. Mark the component
with `@Qualifier("unique-name") and when injecting the bean, use this qualifier.
@Service("blue")
public class Blue implements Color {
@Override
public String fill() {
return "Color is Blue";
}
}
@Service("red")
public class Red implements Color {
@Override
public String fill() {
return "Color is Red";
}
}
When autowiring, you can do this:
@Autowired
@Qualifier("red")
private Color red;
EDIT
<hr/>
When doing a constructor injection do the following:
@Autowired
public SomeClassConstructor(@Qualifier("red") Color red) {
...
}
答案2
得分: 0
你可以尝试在你的服务中使用 @Qualifier
注解。
然后在你的 @Autowired
注解中,你必须使用相同的注解引用它们。
@Service
@Qualifier("firstImplementation")
public class fistImplementation extends MyInterface {
//doSomething
}
@Service
@Qualifier("secondImplementation")
public class secondImplementation extends MyInterface {
//doSomething
}
@Autowired
@Qualifier("firstImplementation")
MyInterface myInterface;
英文:
You can try using the @Qualifier
annotation in your services.
Then in your @Autowired
you must reference them with the same annotation.
@Service
@Qualifier("firstImplementation")
public class fistImplementation extends MyInterface {
//doSomething
}
@Service
@Qualifier("secondImplementation")
public class secondImplementation extends MyInterface {
//doSomething
}
@Autowired
@Qualifier("firstImplementation")
MyInterface myInterface;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论