对象注入时候使用构造注入还是@Autowired?

使用Spring开发时,我们通常有两种依赖注入的方式,基于构造函数或基于setter的依赖注入。

日常开发时候,我们一般使用注解@Autowired注入,但是细心点的小伙伴会发现,使用注解@Autowired注入有一个警告:

Inspection info: Spring Team recommends: "Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies".

翻译成中文:
spring 团队建议:“在bean中始终使用基于构造函数的依赖注入,始终使用断言来强制依赖”。

为什么spring团队会这样建议呢?

首先,使用注解@Autowired注入,可能会报空指针异常错误。

TestPojo.java:

@Data
public class TestPojo {
    private String property;

    public void run(){
        System.out.println("runOne -- run --");
    }
}

 Test.java:

public class Test {
    @Autowired
    private TestPojo testPojo;

    public void testRun(){
        testPojo.run();
    }

    public static void main(String[] args) {
        Test test = new Test();
        test.testRun();
    }
}

 运行后报错:

Exception in thread "main" java.lang.NullPointerException
    at cn.bywin.scmp.web.api.test.Test.testRun(Test.java:15)
    at cn.bywin.scmp.web.api.test.Test.main(Test.java:20)

Process finished with exit code 1

 出现这种问题的关键在于,Test允许创建无状态的对象,也就是说在构建Test时允许TestPojo 为空,此时调用TestPojo.run(),自然就报空指针错误了。对Test.java做下修改,使用构造注入+final的方式进行注入:

public class Test {

    private final TestPojo testPojo;

    public Test(TestPojo testPojo) {
        this.testPojo = testPojo;
    }

    public void testRun(){
        testPojo.run();
    }

    public static void main(String[] args) {
        Test test = new Test(new TestPojo());
        test.testRun();
    }
}

为何使用这种方式,查阅spring官方文档:

翻译成中文:

                                                                                                                               基于构造函数或基于setter的DI?

由于可以混合使用基于构造函数的DI和基于setter的DI,因此,将构造函数用于强制性依赖项,将setter方法或配置方法用于可选性依赖项是一个很好的经验法则。请注意, 在setter方法上使用@Required批注可用于使属性成为必需的依赖项。

Spring团队通常提倡构造函数注入,因为它使人们能够将应用程序组件实现为不可变对象,并确保不存在必需的依赖项null。此外,注入构造函数的组件总是以完全初始化的状态返回到客户端(调用)代码。附带说明一下,大量的构造函数自变量是一种不好的代码味道,这表明该类可能承担了太多的职责,应该对其进行重构以更好地解决关注点的分离问题。

Setter注入主要应仅用于可以在类中分配合理的默认值的可选依赖项。否则,必须在代码使用依赖项的任何地方执行非空检查。setter注入的一个好处是,setter方法使该类的对象在以后可以重新配置或重新注入。因此,通过JMX MBean进行管理是用于setter注入的引人注目的用例。

使用最适合特定班级的DI风格。有时,在处理您没有源代码的第三方类时,将为您做出选择。例如,如果第三方类未公开任何setter方法,则构造函数注入可能是DI的唯一可用形式。

由文档中可知,使用构造器注入的好处:

1、在创建Test对象的时候,强制依赖TestPojo对象,确保创建Test对象时每个对象都是有效状态,且不可变

2、构造器中可以添加对象初始化的校验逻辑

3、可以清楚的区分对象是通过setter方法注入的(非final对象)还是通过强制依赖注入的(final对象)

日常开发中我们虽然使用@Autowired的自动装配会让依赖对象变得很容易,但是随着项目的迭代,自动注入的对象可能会变得很多,文档中也提到使用构造器注入可能使代码变得臃肿,但是spring官方文档中提到“附带说明一下,大量的构造函数自变量是一种不好的代码味道,这表明该类可能承担了太多的职责,应该对其进行重构以更好地解决关注点的分离问题。”,故而应该考虑的是拆分或者重构代码了。

 

上面提到的使用构造注入代码臃肿问题,我们可以结合Lombok来解决构造注入样板代码的问题

@AllArgsConstructor
public class Test {

    private final TestPojo testPojo;

    public void testRun(){
        testPojo.run();
    }

    public static void main(String[] args) {
        Test test = new Test(new TestPojo());
        test.testRun();
    }
}

使用@AllArgsConstructor注解,会在编译过程中,将所有的对象作为参数添加到构造器中。

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值