闽公网安备 35020302035485号

@Component
public class OrderService {
@Autowired
private OrderRepository orderRepository;
public Order findOrderById(Long id) {
return orderRepository.findById(id);
}
}
二为什么应该停止使用字段注入@RunWith(SpringJUnit4ClassRunner.class)
public class OrderServiceTest {
private OrderService orderService;
@Mock
private OrderRepository orderRepository;
@Before
public void setUp() throws Exception {
orderService = new OrderService();
// This will set the mock orderRepository into orderService's private field
ReflectionTestUtils.setField(orderService, "orderRepository", orderRepository);
}
...
}
尽管可以实现,但使用反射来替换私有字段并不是一个很好的设计。它违背了面向对象的设计原则,使测试难以阅读和维护。但是,如果我们使用构造函数注入:@Component
public class OrderService {
private final OrderRepository orderRepository;
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
}
我们可以在测试期间轻松提供模拟 OrderRepository:OrderRepository mockRepo = mock(OrderRepository.class); OrderService orderService = new OrderService(mockRepo);2. 不变性
@Component
public class UserService {
@Autowired
private UserRepository userRepository;
}
这里,userRepository 在创建对象后可以重新分配引用,这就打破了不变性原则。@Component
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
该 usrRepository 字段可以声明为最终字段,在构造完成后,就会一直保持不变。「可读性和理解性」:对于不熟悉 Spring 的开发人员来说,遇到 @Autowired 注解可能会感到困惑。他们可能想知道如何解决依赖关系,从而增加学习成本(ps:虽然不熟悉 Spring 开发的Java程序员可能很少了)。
@Component
public class PaymentGateway {
@Autowired
private PaymentQueue paymentQueue;
public void initiate (PaymentRequest request){
paymentQueue.add(request);
...
}
}
public class PaymentService {
public void process (PaymentRequest request) {
PaymentGateway gateway = new PaymentGateway();
gateway.initiate(request);
}
}
通过上面的代码,我们不难看出,如果在运行时以这种状态访问PaymentGateway,则会发生 NullPointerException。在Spring上下文之外手动初始化这些字段的唯一方法是使用反射,反射机制的语法比较繁琐且易错,在程序可读性方面存在一定问题,所以不建议这样做。@Service
public class AService {
@Autowired
private BService bService;
}
@Service
public class BService {
@Autowired
private AService aService;
}
以上的对象注入,但从代码层面上,并没有任何问题。但是,只要Spring启动,就会立即抛出 BeanCurrentlyInCreationException 的循环依赖异常。不过,要解决循环依赖问题,可以使用@Lazy延迟加载其中一个依赖项即可。