gpt4 book ai didi

java - 当我们有多个实现类时,依赖注入(inject)有何帮助?

转载 作者:行者123 更新时间:2023-12-02 01:10:12 25 4
gpt4 key购买 nike

我一直在 Spring boot 中使用 @Autowired 使用依赖注入(inject)。从我读过的所有关于依赖注入(inject)的文章中,他们提到当我们(如果)决定将来更改实现类时,依赖注入(inject)非常有用。

例如,让我们处理一个 Car 类和一个 Wheel 接口(interface)。 Car 类需要实现 Wheel 接口(interface)才能工作。因此,我们继续在这种情况下使用依赖注入(inject)

// Wheel interface
public interface Wheel{
public int wheelCount();
public void wheelName();
...
}


// Wheel interface implementation
public class MRF impements Wheel{
@Override
public int wheelCount(){
......
}...
}



// Car class
public class Car {

@Autowired
Wheel wheel;
}


现在,在上述场景中,ApplicationContext 将发现存在 Wheel 接口(interface)的实现,从而将其绑定(bind)到 Car 类。将来,如果我们将实现更改为 XYZWheel 实现类并删除 MRF 实现,那么同样的操作也应该有效。

但是,如果我们决定在应用程序中保留 Wheel 接口(interface)的实现,那么我们需要在 Autowiring 时特别提及我们感兴趣的依赖项。因此,更改如下 -

// Wheel interface
public interface Wheel{
public int wheelCount();
public void wheelName();
...
}

@Qualifier("MRF")
// Wheel interface implementation
public class MRF impements Wheel{
@Override
public int wheelCount(){
......
}...
}

// Wheel interface implementation
@Qualifier("XYZWheel")
public class XYZWheel impements Wheel{
@Override
public int wheelCount(){
......
}...
}


// Car class
public class Car {

@Autowired
@Qualifier("XYZWheel")
Wheel wheel;
}


所以,现在我必须手动定义我想要 Autowiring 的具体实现。那么,依赖注入(inject)在这里有什么帮助呢?我可以很好地使用 new 运算符来实际实例化我需要的实现类,而不是依赖 Spring 为我 Autowiring 它。

所以我的问题是,当我有多个实现类,因此我需要手动指定我感兴趣的类型时, Autowiring /依赖注入(inject)有什么好处?

最佳答案

如果您有选择地使用 @Primary@Conditional 限定符来设置您的 Bean,则不必硬连线实现。

一个现实世界的例子适用于身份验证的实现。对于我们的应用程序,我们有一个集成到另一个系统的真实身份验证服务,以及一个模拟服务,用于当我们想要在不依赖该系统的情况下进行本地测试时。

这是身份验证的基本用户详细信息服务。我们没有为它指定任何限定符,即使它可能有两个 @Service 目标:Mock 和 Real。

@Autowired
BaseUserDetailsService userDetailsService;

这个基础服务是抽象的,具有模拟和真实身份验证之间共享的方法的所有实现,以及与默认抛出异常的模拟相关的两个方法,因此我们的真实身份验证服务不会意外地被用于模拟.

public abstract class BaseUserDetailsService implements UserDetailsService {
public void mockUser(AuthorizedUserPrincipal authorizedUserPrincipal) {
throw new AuthException("Default service cannot mock users!");
}

public UserDetails getMockedUser() {
throw new AuthException("Default service cannot fetch mock users!");
}

//... other methods related to user details
}
<小时/>

从那里,我们有了扩展这个基类的真正的身份验证服务,并且是@Primary

@Service
@Primary
@ConditionalOnProperty(
value="app.mockAuthenticationEnabled",
havingValue = "false",
matchIfMissing = true)
public class RealUserDetailsService extends BaseUserDetailsService {

}

这个类可能看起来很稀疏,因为它确实如此。它实现的基本服务最初是唯一的身份验证服务,我们将其扩展为支持模拟身份验证,并让一个扩展类成为“真正的”身份验证。 真实身份验证是主要身份验证,除非启用模拟身份验证,否则始终启用。

<小时/>

我们还有模拟的身份验证服务,它有一些实际模拟的覆盖,以及一个警告:

@Slf4j
@Service
@ConditionalOnProperty(value = "app.mockAuthenticationEnabled")
public class MockUserDetailsService extends BaseUserDetailsService {

private User mockedUser;

@PostConstruct
public void sendMessage() {
log.warn("!!! Mock user authentication is enabled !!!");
}

@Override
public void mockUser(AuthorizedUserPrincipal authorizedUserPrincipal) {
log.warn("Mocked user is being created: " + authorizedUserPrincipal.toString());
user = authorizedUserPrincipal;
}

@Override
public UserDetails getMockedUser() {
log.warn("Mocked user is being fetched from the system! ");
return mockedUser;
}
}

我们在专用于模拟的端点中使用这些方法,这也是有条件的:

@RestController
@RequestMapping("/api/mockUser")
@ConditionalOnProperty(value = "app.mockAuthenticationEnabled")
public class MockAuthController {
//...
}

在我们的应用程序设置中,我们可以使用一个简单的属性来切换模拟身份验证。

app:
mockAuthenticationEnabled: true

使用条件属性,我们永远不应该准备多个身份验证服务,但即使这样做,我们也不会发生任何冲突。

  1. 出现了严重错误:没有 Real,没有 Mock - 应用程序无法启动,没有 bean。
  2. mockAuthEnabled = true:无 Real,Mock - 应用程序使用 Mock。
  3. mockAuthEnabled = false:真实,无模拟 - 应用程序使用真实。
  4. 出现了严重错误:Real AND Mock 两者 - 应用程序使用 Real bean。

关于java - 当我们有多个实现类时,依赖注入(inject)有何帮助?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59498474/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com