实施Spring bean的最佳做法

时间:2020-02-20 06:48:52

标签: java spring design-patterns

我有一个mapper类,可以将一个pojo映射到另一个。我使映射器类成为bean,并将其连接到服务类。我本可以将mapper类也设置为静态类,但是我更喜欢使用bean,因为从可测试性的角度来看,它感觉更好,我可以通过模拟映射器来独立地测试服务和映射器。确实,也可以模拟静态类,但是我将不得不使用powermock或类似的东西。选择bean的另一个原因是,对于某些映射器,我必须使用接口,以便我可以根据某些数据条件选择映射器实现。

这种作为bean的实现在我的团队中引发了争议,建议将其实现为带有静态map方法的类,或者每次创建新的mapper对象。我们正在努力找出最佳解决方案。是否遵循任何行业标准。使用bean方法是否有权衡取舍?会对我的应用程序性能产生影响吗?想象我有一百个这样的映射器。以下是有关我的服务和映射器外观的简单Skelton。

@Service 
class CustomerService { @Autowired CustomerMapper customerMapper ...}

@Component 
class CustomerMapper { @Autowired CustomerContactMapper ..
}

interface CustomerContactMapper {}

@Component
class InternalCustomerContactMapper implements CustomerContactMapper {}

@Component
class ExternalCuatomerContactMapper implements CustomerContactMapper {}

1 个答案:

答案 0 :(得分:3)

嗯,可能有很多意见,如果您想遵循spring建议的惯例,那么您所做的一切都正确。

基本上,您的可测性点是有效的,尽管在这种情况下最好使用构造函数注入,因为在单元测试中,您可以确切地看到所需的依赖项是什么:

class CustomerService {
    private final CustomerMapper customerMapper;

    public CustomerService(CustomerMapper customerMapper) {
        this.customerMapper = customerMapper;
    }
}

旁注:如果您不喜欢构造函数的“样板”,则可以使用仍然提供“ AllArgsConstructor”的Lombok。

现在有关性能的几点: Spring在应用程序启动期间初始化bean。如果这些是易于创建的类(在创建时不会加载很多东西的类,不要去db等,只是普通的Java对象),则需要花费一秒钟的时间来初始化它们。

稍后您会进行常规的函数调用(好的,如果您使用接口,那么它是一个“虚拟”调用),但是通常它不会影响性能,换句话说,如果应用程序运行缓慢,原因是可能在其他任何地方。

关于替代方案:

我并不完全理解“作为静态类的实现”的含义,但是,如果您想每次创建一个新的映射器,这将意味着它不是线程安全的。在当前的实现中,服务是单例的,因此不会有很多实例,每个应用程序上下文只有一个实例。但是,可以同时被许多线程调用。

因此,如果您必须创建许多实例->不能从多个线程使用映射器。这个决定与Spring无关,它与您的代码以及使它成为非线程安全的决定无关(我只是在说事实,并不是说它的好坏)。

现在,如果是这种情况,那么您的解决方案在技术上是错误的。 Spring通过Provider类支持这种用法+还有其他方法可以将原型注入单例:

class CustomerService {
    private final Provider<CustomerMapper> customerMapper;

您可以阅读Here有关此方法的信息