Spring注入存储库与构造函数中的普通属性混合

问题描述

我有 Service 类和 Repository 接口(Spring Data)。我也有一个抽象类:

public abstract class TestingMethod {
    public TestingMethod() {
        timeSum = 0;
    }
    protected long timeSum;
}

以及扩展它的类:

@Component
public class LimitTestingMethod extends TestingMethod {

    @Autowired
    private GeoTestDataRepository geoTestDataRepository;

    private final int limitSize;

    public LimitTestingMethod(int limitSize) {
        super();
        this.limitSize = limitSize;
    }
}

在我的 Service 中,我想创建 LimitTestingMethod 的实例并设置其参数 limitSize。 类似的东西:

LimitTestingMethod ltm3 = new LimitTestingMethod(3);
LimitTestingMethod ltm10 = new LimitTestingMethod(10);

但是我遇到了错误

说明:构造函数中的参数0 com.exence.postgiscma.testingMethod.LimitTestingMethod 需要一个 bean 无法找到“int”类型。行动:考虑定义一个 配置中类型为“int”的 bean。

这有可能实现我想要的东西吗?

一切顺利!

//编辑

正如我在评论中看到的那样,这是一种糟糕的方法。所以也许有人会给我建议如何更好地规划这个? 这是在构造函数中将 repo 作为参数传递的好方法吗(我想不是,但我不知道如何做得更好)?

LimitTestingMethod ltm3 = new LimitTestingMethod(3,geoTestDataRepository);

有没有好的优雅的解决方案?

解决方法

当您在 Spring 范围之外创建实例时,您当前的解决方案将不起作用。该错误来自于您使用 @Component 对其进行了注释,它会在启动时检测到它并尝试创建一个 bean,但失败了。

要解决这个问题,您可以做 2 件事中的 1 件事。

  1. 让 Spring 通过使用 ApplicationContext 作为工厂来处理 bean 的创建,提供额外的参数使 bean 原型具有范围。
  2. 在您使用 ApplicationContext 手动创建实例后让 Spring 处理注入。

使用ApplicationContext作为工厂

首先让你的 bean 成为原型,以便在需要时构造它。

@Component
@Scope(
ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class LimitTestingMethod extends TestingMethod { ... }

现在启动时不会创建实例。在您的服务中注入 ApplicationContext 并使用 getBean 方法获取所需的实例。

public class Service {

  @Autowired
  private ApplicationContext ctx;


  public void yourMethod() {

    LimitTestingMethod ltm3 = ctx.getBean(LimitTestingMethod.class,3);
    LimitTestingMethod ltm10 = ctx.getBean(LimitTestingMethod.class,10);

  }
}

这将让 Spring 使用为构造函数传入的值创建实例并执行自动装配。

创建后注入

另一种解决方案是手动创建实例,然后让 Spring 处理自动连接。这样做你将失去 AOP 能力,只会得到自动布线。

首先从您的 @Component 中删除 LimitTestingMethod 注释,这样它就不会在启动过程中被检测到。

public class LimitTestingMethod extends TestingMethod { ... }

现在在您的服务中自动装配 ApplicationContext 并在创建您的 bean 后使用它来注入依赖项。

public class Service {

  @Autowired
  private ApplicationContext ctx;


  public void yourMethod() {

    LimitTestingMethod ltm3 = new LimitTestingMethod(3);
    LimitTestingMethod ltm10 = new LimitTestingMethod(10);

    ctx.getAutowireCapableBeanFactory().autowireBean(lmt3);
    ctx.getAutowireCapableBeanFactory().autowireBean(lmt10);

  }
}

两者都将实现您想要的,但是,现在您的代码直接依赖于 Spring API。因此,与其这样做,您可能最好使用另一种选择,即通过构造函数注入 LimitTestingMethod 的所有内容并自己传递存储库。

使用构造函数创建实例

public class LimitTestingMethod extends TestingMethod {

    private final GeoTestDataRepository geoTestDataRepository;
    private final int limitSize;

    public LimitTestingMethod(int limitSize,GeoTestDataRepository geoTestDataRepository) {
      this.limitSize=limitSize;
      this.geoTestDataRepository=geoTestDataRepository;
    }
}

然后您可以简单地在您的服务类中自动装配存储库并根据需要创建实例(或创建一个包含创建此对象的复杂性的工厂)。

public class Service {

  @Autowired
  private GeoTestDataRepository repo;


  public void yourMethod() {

    LimitTestingMethod ltm3 = new LimitTestingMethod(3,repo);
    LimitTestingMethod ltm10 = new LimitTestingMethod(10,repo);

  }
}