Spring官网阅读(二)(依赖注入及方法注入)(1)

简介: Spring官网阅读(二)(依赖注入及方法注入)(1)

依赖注入:


根据官网介绍,依赖注入主要分为两种方式

1.构造函数注入

2.Setter方法注入

官网:

微信图片_20221112145456.jpg我们分别对以上两种方式进行测试,官网上用的是XML的方式,我这边就采用注解的方式了:

测试代码如下,我们通过在Service中注入LuBanService这个过程来

public class Main02 {
  public static void main(String[] args) {
    AnnotationConfigApplicationContext ac = new 
            // config类主要完成对类的扫描
            AnnotationConfigApplicationContext(Config.class);
    Service service = (Service) ac.getBean("service");
    service.test();
  }
}
@Component
public class LuBanService {
  LuBanService(){
    System.out.println("luBan create ");
  }
}

测试setter方法注入

@Component
public class Service {
  private LuBanService luBanService;
  public Service() {
    System.out.println("service create");
  }
  public void test(){
    System.out.println(luBanService);
  }
  // 通过autowired指定使用set方法完成注入
  @Autowired
  public void setLuBanService(LuBanService luBanService) {
    System.out.println("注入luBanService by setter");
    this.luBanService = luBanService;
  }
}

输出如下:

luBan create 
service create
注入luBanService by setter  // 验证了确实是通过setter注入的
com.dmz.official.service.LuBanService@5a01ccaa

测试构造函数注入

@Component
public class Service {
  private LuBanService luBanService;
    public Service() {
    System.out.println("service create by no args constructor");
  }
    // 通过Autowired指定使用这个构造函数,否则默认会使用无参
  @Autowired
  public Service(LuBanService luBanService) {
    System.out.println("注入luBanService by constructor with arg");
    this.luBanService = luBanService;
    System.out.println("service create by constructor with arg");
  }
  public void test(){
    System.out.println(luBanService);
  }
}

输出如下:

luBan create 
注入luBanService by constructor // 验证了确实是通过constructor注入的
service create by constructor
com.dmz.official.service.LuBanService@1b40d5f0

疑问:


在上面的验证中,大家可能会有以下几个疑问:


1.@Autowired直接加到字段上跟加到set方法上有什么区别?为什么我们验证的时候需要将其添加到setter方法上?


  • 首先我们明确一点,直接添加@Autowired注解到字段上,不需要提供setter方法也能完成注入。以上面的例子来说,Spring会通过反射获取到Service中luBanService这个字段,然后通过反射包的方法,Filed.set(Service,luBanService)这种方式来完成注入
  • 我们将@Autowired添加到setter方法时,我们可以通过断点看一下方法的调用栈,如下:

微信图片_20221112145825.jpg

对于这种方式来说,最终是通过Method.invoke(object,args)的方式来完成注入的,这里的method对象就是我们的setter方法


2.@Autowired为什么加到构造函数上可以指定使用这个构造函数?


  • 我们先可以测试下,如果我们不加这个注解会怎么样呢?我把前文中的@Autowired注解注释,然后运行发现
luBan create 
service create by no args constructor  // 可以看到执行的是空参构造
null

先不急得出结论,我们再进行一次测试,就是两个函数上都添加@Autowired注解呢?

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'service': Invalid autowire-marked constructor: public com.dmz.official.service.Service(com.dmz.official.service.LuBanService). Found constructor with 'required' Autowired annotation already: public com.dmz.official.service.Service()

发现直接报错了,报错的大概意思是已经找到了一个被@Autowired注解标记的构造函数,同时这个注解中的required属性为true。后来我测试了将其中一个注解中的required属性改为false,发现还是报同样的错,最终将两个注解中的属性都改为false测试才通过,并且测试结果跟上面的一样,都是执行的无参构造。


要说清楚这一点,涉及到两个知识


  • Spring中的注入模型,下篇文章专门讲这个
  • Spring对构造函数的推断。这个到源码阶段我打算专门写一篇文章,现在我们暂且记得:

在***默认的注入模型***下,Spring如果同时找到了两个***符合要求的构造函数***,那么Spring会采用默认的无参构造进行实例化,如果这个时候没有无参构造,那么此时会报错java.lang.NoSuchMethodException。什么叫符合要求的构造函数呢?就是构造函数中的参数Spring能找到,参数被Spring所管理。


这里需要着重记得:一,默认注入模型;二,符合要求的构造函数


3.如果我们同时采用构造注入加属性注入会怎么样呢?

在没有进行测试前,我们可以大胆猜测下,Spring虽然能在构造函数里完成属性注入,但是这属于实例化对象阶段做的事情,那么在后面真正进行属性注入的时候,肯定会将其覆盖掉。现在我们来验证我们的结论

@Component
public class Service {
  private LuBanService luBanService;  
  public Service(LuBanService luBanService) {
    System.out.println("注入luBanService by constructor with arg");
    this.luBanService = luBanService;
    System.out.println("service create by constructor with arg");
  }
  public void test(){
    System.out.println(luBanService);
  }
  @Autowired
  public void setLuBanService(LuBanService luBanService) {
    System.out.println("注入luBanService by setter");
    this.luBanService = null;
  }
}

运行结果:

注入luBanService by constructor with arg  // 实例化时进行了一次注入
service create by constructor with arg   // 完成了实例化
注入luBanService by setter    // 属性注入时将实例化时注入的属性进行了覆盖
null

区别:


image.jpeg

根据上图中官网所说,我们可以得出如下结论:


1.构造函数注入跟setter方法注入可以混用

对于一些强制的依赖,我们最好使用构造函数注入,对于一些可选依赖我们可以采用setter方法注入

2.Spring团队推荐使用构造函数的方式完成注入。但是对于一些参数过长的构造函数,Spring是不推荐的


相关文章
|
27天前
|
Java Spring
在使用Spring的`@Value`注解注入属性值时,有一些特殊字符需要注意
【10月更文挑战第9天】在使用Spring的`@Value`注解注入属性值时,需注意一些特殊字符的正确处理方法,包括空格、引号、反斜杠、新行、制表符、逗号、大括号、$、百分号及其他特殊字符。通过适当包裹或转义,确保这些字符能被正确解析和注入。
|
1月前
|
Java 测试技术 程序员
为什么Spring不推荐@Autowired用于字段注入?
作为Java程序员,Spring框架在日常开发中使用频繁,其依赖注入机制带来了极大的便利。然而,尽管@Autowired注解简化了依赖注入,Spring官方却不推荐在字段上使用它。本文将探讨字段注入的现状及其存在的问题,如难以进行单元测试、违反单一职责原则及易引发NPE等,并介绍为何Spring推荐构造器注入,包括增强代码可读性和维护性、方便单元测试以及避免NPE等问题。通过示例代码展示如何将字段注入重构为构造器注入,提高代码质量。
|
1月前
|
缓存 Java Spring
源码解读:Spring如何解决构造器注入的循环依赖?
本文详细探讨了Spring框架中的循环依赖问题,包括构造器注入和字段注入两种情况,并重点分析了构造器注入循环依赖的解决方案。文章通过具体示例展示了循环依赖的错误信息及常见场景,提出了三种解决方法:重构代码、使用字段依赖注入以及使用`@Lazy`注解。其中,`@Lazy`注解通过延迟初始化和动态代理机制有效解决了循环依赖问题。作者建议优先使用`@Lazy`注解,并提供了详细的源码解析和调试截图,帮助读者深入理解其实现机制。
31 1
|
3月前
|
缓存 Java 数据库连接
Spring Boot 资源文件属性配置,紧跟技术热点,为你的应用注入灵动活力!
【8月更文挑战第29天】在Spring Boot开发中,资源文件属性配置至关重要,它让开发者能灵活定制应用行为而不改动代码,极大提升了可维护性和扩展性。Spring Boot支持多种配置文件类型,如`application.properties`和`application.yml`,分别位于项目的resources目录下。`.properties`文件采用键值对形式,而`yml`文件则具有更清晰的层次结构,适合复杂配置。此外,Spring Boot还支持占位符引用和其他外部来源的属性值,便于不同环境下覆盖默认配置。通过合理配置,应用能快速适应各种环境与需求变化。
43 0
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
163 2
|
3月前
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
|
10天前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
22 2
 SpringBoot入门(7)- 配置热部署devtools工具
|
6天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
18 2
|
1月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
54 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块