spring注入的对象和new的对象到底有啥区别

本文探讨了Spring Boot中对象注入及初始化顺序的问题,重点分析了注解注入对象与new对象的区别,解释了为何注解注入的对象属性为默认值,并提供了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在使用springboot过程中,想使用jdbc模板,就是直接在service层注入一个jdbcTemplate属性,然后直接使用,但是又想封装一下,就创建一个类,类中有jdbcTemplate属性,然后再service中调用我封装的jdbc,刚开始没有封装方法的情况下,想在service中直接想注入我的类,然后调用我的类中的jdbc,什么注解都标注好了,结果一直空指针异常,还以为不好使呢,其实这里面有个很大的问题,就是注解注入的对象和new的对象到底有啥区别;

我们知道,new一个对象的时候,初始化顺序是,父类静态块>子类静态块> 父类属性(先系统默认值,后直接你赋予的值) >父类构造器>子类属性>子类构造器

但是当有个注解在属性上的时候,会是啥情况呢?

 


 
  1. @Repository

  2. public class A {

  3. /**

  4. * 属性初始化的顺序是在构造器之前,编译器也会先设置默认值,然后赋予指定值

  5. * 但是当该类的实例是spring注解的注入方式,那么被指定的值不会被赋值

  6. */

  7. public int aa=1;//定义到C的前面,会被先于C初始化

  8. public String as;//如果该类的对象是springMVC注解注入的方式,那么这个属性默认是null,即使赋值,也是空

  9. @Resource

  10. public C c ; //不会被初始化 如果 = new C(); 会先于aa和aaa初始化

  11. public int aaa=2;//定义到C的后面,但是 C不会被初始化

  12. public void run(){

  13. System.out.println("aaaaa");

  14. c.foo();

  15. }

  16. }

  17.  
  18. @RestController

  19. public class B {

  20. @Resource

  21. public A a = new A();

  22. @RequestMapping("/B")

  23. public void test1() {

  24.  
  25. System.out.println(a.as);//如果是注解注入A对象,注意此时A的初始化 只是简单的调用A的空构造函数,A中的属性默认都是默认值(int是0,类属性是null),A中的属性如果自定义了赋值,也不会被使用。

  26. System.out.println(a.aa);

  27. //a.c.foo();

  28. System.out.println(a.c);

  29. System.out.println(a.aaa);

  30. }

  31. }

  32.  
  33. @Component

  34. public class C {

  35. public C() {

  36. System.out.println("C..init..");

  37. }

  38. public void foo(){

  39. System.out.println("cccc");

  40. }

  41. }

结论:注入的对象,只会调用空参构造函数,且这个对象的所有属性都是默认值,自己手动赋予的值不会被使用,

 

所以在A中的C类,在B中调用A的时候,创建的A对象的属性都是默认值,所以A对象虽然有了,但是A的属性C却是null,所以在B中直接this.a.c.method()是会报null指针异常的,且是c是null的发生原因。

解决方式:C在A中添加get方法,然后B中使用a.getC()即可获得c的对象,且c的对象也是spring注入的。

 

备注:以上结论和说明,只是个人总结,包括new一个对象初始化顺序,可能不严谨,没有时间验证,以后会完善

### Spring 框架中依赖注入的作用原因 #### 作用 依赖注入的核心目的是 **降低程序模块间的耦合度**,从而提高系统的可测试性灵活性。通过将对象的创建依赖关系的管理交给 Spring 容器完成,开发者可以专注于业务逻辑的实现[^3]。 具体来说,依赖注入的主要作用如下: - **减少硬编码**:传统的开发方式通常会直接在代码中实例化对象(如 `new` 关键字),这种方式使得代码难以修改扩展。而依赖注入允许外部配置决定哪些类被实例化以及如何组装它们[^1]。 - **增强可维护性**:由于依赖关系由容器管理而非手动编写,因此当需求发生变化时,只需调整配置即可改变行为,无需大量改动源码[^2]。 - **支持单元测试**:借助 DI 技术,可以在测试阶段轻松替换实际的服务实现为模拟版本(Mock Objects)。这有助于隔离待测组件并验证其独立功能。 #### 原因 采用依赖注入的原因主要基于软件工程的最佳实践原则——高内聚低耦合的设计理念: 1. **促进松散耦合架构** 如果每个类都要自行负责初始化自己的协作伙伴,则必然导致紧密联系;反之如果这些关联能够从外界传入而不是内部构建的话就可以显著削弱两者之间相互制约的程度。 2. **简化复杂系统结构** 对于大型应用程序而言,可能存在成百上千个互相依存的对象网络。如果没有某种机制帮助理清这种错综复杂的连接模式,那么整个项目很快就会变得混乱不堪难以驾驭。IOC/DI 提供了一种优雅解决方案来应对这一挑战。 3. **提升代码重用率与适应变化能力** 当某个特定接口有多重可能的具体实现形式可供选择的时候(比如生产环境下的真实数据访问层 versus 开发调试期间使用的内存数据库代理版),利用反射技术动态加载指定类型的策略显然要比固定写死某单一选项更加灵活高效。 以下是简单的 Java 配置示例展示如何使用 @Configuration @Bean 注解来进行依赖注入: ```java // 使用Java配置定义Beans @Configuration public class AppConfig { @Bean public MyService myService() { return new MyServiceImpl(); } } ``` 上述代码片段展示了通过编程方式声明 bean 并将其注册到 spring 应用上下文中的一种方法。这里 `myService()` 方法返回了一个具体的 service 实现类实例作为该名称对应的 singleton scope 下唯一可用的选择项之一。 --- #### 总结 总之,在现代企业级 java web 开发领域里广泛采纳 spring framework 正是因为它内置了强大而又易用的 ioc container 及 di feature set, 这些特性共同助力开发者打造更健壮稳定同时也更容易演化的高质量软件产品.
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值