Redian新闻
>
请停止使用 @Autowired 注入对象...

请停止使用 @Autowired 注入对象...

公众号新闻

在 Spring Boot 依赖项注入的上下文中,存在关于注入依赖项最佳实践的争论:字段注入、Setter注入和构造函数注入。

在本文中,我们将通过一些案例,来重点讨论字段注入的缺陷。

当使用 IDEA 开发的时候,工具也会出现提醒,根据他的提示操作,也会自动将注入方式转换为构造方法注入

什么是字段注入?

字段注入涉及直接用 @Autowired 注释类的私有字段。这是一个例子:

@Component
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;
    
    public Order findOrderById(Long id) {
        return orderRepository.findById(id);
    }
}

为什么应该停止使用字段注入

1. 可测试性

字段注入使组件的单元测试变得复杂。由于依赖项直接注入到字段中,因此我们无法在 Spring 上下文之外轻松提供模拟或替代实现。

让我们以 sameOrderService 类为例。

如果我们希望对 OrderService 进行单元测试,那么在模拟 OrderRepository 时会遇到困难,因为它是一个私有字段。下面是对 OrderService 进行单元测试的方法:

@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. 不变性

字段注入使我们的 Bean 在构建后可变。而通过构造函数注入,一旦构造了一个对象,它的依赖关系就会保持不变。

微信搜索公众号:架构师指南,回复:架构师 领取资料 。

举例来说:

字段注入类:

@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 字段可以声明为最终字段,在构造完成后,就会一直保持不变。

3.与Spring更紧密的耦合

字段注入使我们的类与 Spring 耦合更紧密,因为它直接在我们的字段上使用 Spring 特定的注释 ( @Autowired)。这可能会在以下场景中出现问题:

  • 「不使用 Spring 的情况」:假设我们正在构建一个不使用 Spring 的轻量级命令行应用程序,但我们仍然想利用 UserService 的逻辑。在这种情况下,@Autowired 注释没有任何意义,不能用于注入依赖项。我们就必须重构该类或实现繁琐的解决方法才能重用UserService.
  • 「切换到另一个 DI 框架」:如果我们决定切换到另一个依赖注入框架,比如 Google Guice,Spring 特定的框架 @Autowired 就会成为一个障碍。那时我们必须重构使用 Spring 特定注释的每一个地方,这会是十分繁琐的。
  • 「可读性和理解性」:对于不熟悉 Spring 的开发人员来说,遇到 @Autowired 注解可能会感到困惑。他们可能想知道如何解决依赖关系,从而增加学习成本(ps:虽然不熟悉 Spring 开发的Java程序员可能很少了)。

4. 空指针异常

当类利用字段注入并通过其默认构造函数实例化时,依赖字段保持未初始化。

举例来讲:

@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上下文之外手动初始化这些字段的唯一方法是使用反射,反射机制的语法比较繁琐且易错,在程序可读性方面存在一定问题,所以不建议这样做。

5. 循环依赖

字段注入可能会掩盖循环依赖问题,使它们在开发过程中更难被发现。

举例来讲:

模拟两个相互依赖的服务AService和BService:

@Service
public class AService {
    @Autowired
    private BService bService;
}

@Service
public class BService {
    @Autowired
    private AService aService;
}

以上的对象注入,但从代码层面上,并没有任何问题。

但是,只要Spring启动,就会立即抛出 BeanCurrentlyInCreationException 的循环依赖异常。不过,要解决循环依赖问题,可以使用@Lazy延迟加载其中一个依赖项即可。

结论

虽然字段注入可能看起来更简洁,但它的缺点远远超过了它的简洁性。构造函数注入在应用程序的可测试性、不变性和整体稳健性方面提供了明显的优势。

它与 SOLID 原则非常一致,确保我们的 Spring Boot 应用程序可维护且不易出错。

所以,建议大家停止在 Spring Boot 中使用字段注入!

译自:https://medium.com

-END-

PS:如果觉得我的分享不错,欢迎大家随手点赞、在看。

 关注公众号:Java后端编程,回复下面关键字 


要Java学习完整路线,回复  路线 

缺Java入门视频,回复 视频 

要Java面试经验,回复  面试 

缺Java项目,回复: 项目 

进Java粉丝群: 加群 


PS:如果觉得我的分享不错,欢迎大家随手点赞、在看。

(完)




加我"微信获取一份 最新Java面试题资料

请备注:666不然不通过~


最近好文


1、不好意思,Mybatis Plus 该换了!

2、MySQL中update“经典”的坑,这样写语句,直接劝退!

3、SpringBoot:一个注解就能帮你下载任意对象

4、Controller 层代码就该这么写,简洁又优雅!

5、一台服务器最大能支持多少条 TCP 连接



最近面试BAT,整理一份面试资料Java面试BAT通关手册,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。
获取方式:关注公众号并回复 java 领取,更多内容陆续奉上。
明天见(。・ω・。)ノ

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
部分旧版Chase Freedom用户被强制“暖心升级”成Chase Freedom Unlimited加州官宣: 这4种食品添加剂禁止使用这一广泛应用于澳洲新房的建筑材料,容易导致肺部疾病,或将被全面禁止使用!How a Red-Haired Chatbot Became China’s Favorite English TutorRedis实战 | 使用Redis 的有序集合(Sorted Set)实现排行榜功能,和Spring Boot集成请停止刷《投行400问》!这本哈佛推荐的171页指南让我面试秒过检出“禁止使用的药物”!知名生鲜超市:下架,换供应商请停止小红书的无效种草数万人纽约游行,呼吁停止使用导致气候变暖化石燃料部分中国政府机关禁止使用苹果手机?外交部回应请停止刷《投行400问》!这本哈佛推荐的171页面试指南更高效“性交猝死”的人,都有这些规律!请停止在这7个危险的边缘试探请停止刷《投行400问》!UBS、德银面试官透露这300道真题更实用加州颁布新法!恐含危险致癌成分,人工草坪或被禁止使用(图)近1000只鸟撞向一栋大楼后死亡,请停止制造「致命建筑」女孩请停止自我 PUA突发!加拿大政府禁止使用微信!这些设备严禁下载!美国FDA提议禁止使用直发药剂,加拿大尚未跟进实施!龚俊代言的服饰华人立即停止使用!近百万件高压锅被召回 已致多人烫伤 BestBuy已收到31起事故报告,其中包括17起烧伤报告禁令来了!尔湾或将于明年起禁止使用塑料袋和一次性饭盒,您同意吗?Troubled Singing Reality Show Accused of Mistreating Coco Lee立即停止使用!近百万件华人神锅被召回 随时会爆炸 已致多人烫伤无聊的星期天How the BRI Reshaped China’s Medical Aid Spending注意!澳洲热销婴儿玩具召回,恐造成窒息死亡风险,宝爸宝妈遭促停止使用娱乐圈,请停止这种闹剧走进400年历史的洋葱头教堂低年级进入对冲基金!Arrowstreet Capital (US)实习开启终面In China, AI Clones Are Putting Human Livestreamers Out of Work登上TODS2022年度财报的唯一全球品牌代言人--龚俊注意!澳洲这款热门太阳能电池板召回,存制造缺陷将造成过热起火,消费者遭促立即停止使用中国政府机构禁止使用苹果手机?!China’s Pneumonia Outbreak Recedes, but Flu Awaits361集团-2023中期业绩报告
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。