@Specializes in Spring

时间:2014-11-13 15:33:42

标签: spring subclass cdi specialization

CDI具有Specialization的功能,我在春天的世界里寻找它。

详情。 在CDI中,@Specializes注释允许人们通过覆盖它来改变bean的行为。这对于该bean的用户是完全透明的,例如如果我们有

public class OneBean {
  public String whoAmI() { return "OneBean"; }
}

@Specializes
public class AnotherBean extends OneBean {
  @Override
  public String whoAmI() { return "AnotherBean"; }
}

我们可以

public class SomewhereElse {
  @Inject
  OneBean oneBean; // we know nothing of AnotherBean here!

  public void guessWhosThere() {
    return oneBean.whoAmI(); // yet it returns "AnotherBean"
  }
}

只要有OneBean实际使用AnotherBean,这就非常有用。例如,如果OneBean位于one.jarAnotherBean位于another.jar,我们可以通过重新配置类路径来更改bean的行为。

问题。 Spring中是否也存在类似专业化的内容?

我只能找到@Primary注释,但是它具有不同的语义:@Primary不会替换一个bean,而只会将多个备选项中的一个标记为 primary 一。特别是,正如我所理解的那样,我无法构建一个深层继承层次结构,因为它可以@Specializes

5 个答案:

答案 0 :(得分:2)

简短回答 在春季4,这是不可能的。期。尽管如此,在2016年,Spring的过时依赖注入模型仍然无法做到这一点。

答案 1 :(得分:1)

看起来春天没有类似的注释,但你可以通过@Qualifier来实现它。

豆类:

@Resource("oneBean")
public class OneBean {
  public String whoAmI() { return "OneBean"; }
}

@Resource("anotherBean")
public class AnotherBean extends OneBean {
  @Override
  public String whoAmI() { return "AnotherBean"; }
}

SomewhereElse:

public class SomewhereElse {
  @Autowired
  @Qualifier("anotherBean")
  OneBean oneBean;

  public void guessWhosThere() {
    return oneBean.whoAmI(); // returns "AnotherBean"
  }
}

<强>编辑。

您也可以开发自己的注释并在 BeanPostProcessor 中使用它,查看spring docs here

或者甚至更好地使用 CustomAutowireConfigurer ,请参阅here

答案 2 :(得分:0)

如果我们假设:

public interface BeanInterface {
  String whoAmI();
}

@Named
public class OneBean implements BeanInterface {
  @Override
  public String whoAmI() { return "OneBean"; }
}

@Named
@Primary
public class AnotherBean implements BeanInterface {
  @Inject
  OneBean oneBean;

  @Override
  public String whoAmI() {
    String oneBeanId = oneBean.whoAmI();
    return "AnotherBean calling: " + oneBeanId;
  }
}

我们可以,而不是扩展OneBean用一些额外的行为来装饰它。此解决方案的缺点是BeanInterface的每个方法都必须在AnotherBean中实施并委托给其oneBean字段。

答案 3 :(得分:0)

您可以使用@Qualifier执行此操作。

例如:

bean类:

@Component("loginMB")
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class LoginMB extends AdminSession implements Serializable {

注入点:

@Component
public class AdminFilter implements Filter {

    private static final String FACES_RESOURCES = "javax.faces.resource";
    private static final Logger log = Logger.getLogger(AdminFilter.class.getName());

    private boolean disableFilter;
    private String loginPage;
    private String errorPage;
    private String indexPage;

    @Autowired
    @Qualifier(value = "loginMB")
    AdminSession adminSession;

答案 4 :(得分:0)

使用 Spring boot,您可能会通过利用其自动配置机制获得类似的结果,例如带有 bean condition,例如 @ConditionalOnMissingBean:

public class OneBean {
  public String whoAmI() { return "OneBean"; }
}

@Configuration
public class OneConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public OneBean getBean() { return new OneBean(); }
}

@Component
public class AnotherBean extends OneBean {
  @Override
  public String whoAmI() { return "AnotherBean"; }
}

但是,如果您不确定哪些配置是专门的,则必须确保所有配置都相应地构建:

public class OneBean {
  public String whoAmI() { return "OneBean"; }
}

public class AnotherBean extends OneBean {
  @Override
  public String whoAmI() { return "AnotherBean"; }
}

public class YetAnotherBean extends AnotherBean {
  @Override
  public String whoAmI() { return "YetAnotherBean"; }
}

@Configuration
public class OneConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public OneBean getBean() { return new OneBean(); }
}

@Configuration
public class AnotherConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public AnotherBean getBean() { return new AnotherBean(); }
}

@Configuration
public class YetAnotherConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public YetAnotherBean getBean() { return new YetAnotherBean(); }
}
// and so on...