繁体   English   中英

春季注入的豆在嵌套类中为空

[英]Spring injected beans null in nested class

我有一个带有2个静态嵌套类的类,它们对2种不同的泛型类型执行相同的操作。

我像平时一样将这两个类公开为bean,并为构造函数添加了@Autowired。

这是基本设置

abstract class <T> Parent implements MyInterface<T> {
   private final Service service;
   Parent(Service service){ this.service = service; }

   @Override public final void doInterfaceThing(T thing){
     T correctedT = map(thing);
     service.doTheThing(correctedT);
   }

   protected abstract T map(T t);

   @Service
   public static class ImplA extends Parent<A> {
     @Autowired ImplA (Service service){ super(service); }
     A map(A a){ //map a }
   }

   @Service
   public static class ImplB extends Parent<B> {
     @Autowired ImplB (Service service){ super(service); }
     B map(B b){ //map b }
   }

}

在另一堂课上

@Service
public class Doer {
   private final List<MyInterface<A>> aImpls;
   @Autowired public Doer(List<MyInterface<A>> aImpls){ this.aImpls = aImpls; }
   public void doImportantThingWithA(A a){
     aImpls.get(0).doInterfaceThing(a);
   }
}

当我运行该应用程序时,所有内容似乎都已正确注入,并且当我在ImplA和ImplB构造函数中添加断点时,“服务”的值不为null。 我在Doer的aImpls列表中也有一个ImplA bean。

但是,当我调用doImportantThingWithA(a)时,ImplA中的“服务”为空,因此我显然死了。

我不确定这怎么可能,因为:

  1. 我在服务的构造函数中看到一个非空值,这是一个最终字段。
  2. 如果spring将ImplA和ImplB注入另一个类,则它应该已经将Service注入了ImplA或ImplB,或者在bean初始化时引发了异常。 我没有设置延迟加载的任何内容,并且需要所有bean依赖项。

嵌套类的原因是因为这两个实现之间唯一发生变化的是map()函数。 尝试避免1行变化代码的额外类。

更多信息:当我在Parent.doInterfaceThing()中添加断点时,如果在“服务”上添加监视,则该值将为null。 如果我添加一个getService()方法,然后调用getService()而不是直接引用this.service,我将获得正确的服务bean。 我不知道这意味着什么,但是代理似乎有些奇怪。

看起来是引起问题的原因是Parent.doInterfaceThing();。

如果我从方法签名中删除final,则正确填充“服务”字段,并且代码按预期工作。

我根本不理解为什么更改方法签名会影响类中final字段的注入值...但现在可以使用。

我对“使用映射器”评论的意思是这样的:

class MyInterfaceImpl implements MyInterface {
   @Autowired
   private final Service service;

   @Override public final <T> void doInterfaceThing(T thing, UnaryOperator<T> mapper){
     T correctedT = mapper.apply(thing);
     service.doTheThing(correctedT);
   }

   // new interface to allow autowiring despite type erasure
   public interface MapperA extends UnaryOperator<A> {
     public A map(A toMap);
     default A apply(A a){ map(a); }
   }
   @Component
   static class AMapper implements MapperA {
       public A map(A a) { // ... }
   }

   public interface MapperB extends UnaryOperator<B> {
     public B map(B toMap);
     default B apply(B b){ map(b); }
   }
   @Component
   static class BMapper implements MapperB {
       public B map(B a) { // ... }
   }
}

这确实比原始行多了几行,但并不多。 但是,您确实有更好的关注点分离。 我确实想知道自动装配如何在具有泛型的代码中工作,它看起来确实会引起问题。

您的客户看起来像这样:

@Service
public class Doer {
   private final List<MapperA> aMappers;
   private final MyInterface myInterface;
   @Autowired public Doer(MyInterface if, List<MapperA> mappers){ 
       this.myInterface = if;
       this.aImpls = mappers; }
   public void doImportantThingWithA(A a){
     aMappers.stream().map(m -> m.map(a)).forEach(myInterface::doInterfaceThing);
   }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM