Spring将接口的两个实现注入以使用桥接设计模式。

huangapple go评论78阅读模式
英文:

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(&quot;red&quot;) Color red) {
    ...
}

答案2

得分: 0

你可以尝试在你的服务中使用 @Qualifier 注解。
然后在你的 @Autowired 注解中,你必须使用相同的注解引用它们。

https://docs.spring.io/spring/docs/4.3.12.RELEASE/spring-framework-reference/htmlsingle/#beans-autowired-annotation-qualifiers

@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.

https://docs.spring.io/spring/docs/4.3.12.RELEASE/spring-framework-reference/htmlsingle/#beans-autowired-annotation-qualifiers

@Service
@Qualifier(&quot;firstImplementation&quot;)
public class fistImplementation extends MyInterface {
 //doSomething
}

@Service
@Qualifier(&quot;secondImplementation&quot;)
public class secondImplementation extends MyInterface  { 
//doSomething
}


@Autowired
@Qualifier(&quot;firstImplementation&quot;) 
MyInterface myInterface;

huangapple
  • 本文由 发表于 2020年4月8日 21:43:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/61102147.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定