java构造函数默认值_Java程序员必须掌握的Spring依赖管理原理

40be1b98aea0f80925979c912d8b019f.png

Spring依赖注入

依赖注入(Dependency Injection)的意思就是对象通过构造器函数参数,工厂方法的参数,或者成员属性,定义了对象的依赖对象;容器在创建该对象时会负责注入这些依赖。这个过程是控制反转的,即不是由即将创建的对象来管理自己的依赖的发现和实例化,而是有Spring容器来实现。

在Spring中依赖注入有两种形式,第一种就是基于构造函数的注入,即通过调用构造函数,传入参数,也就是依赖来完成整个依赖注入流程;第二种就是基于setter方法的注入

构造函数的参数的匹配,要避免歧义,如指定类型,指定参数的次序等。如果是按照参数名字匹配,则必须开启debug模式进行编译,否则参数名字是不保留的。如果不想开启debug模式编译,则可以使用@ConstructorProperties注解

setter方法注入是先调用没有参数的默认构造函数构建对象,或者没有参数的静态工厂方法,实例化bean后,调用setter方法来将该对象注入。

通过使用依赖注入,可以使代码更简洁,更好地实现对象之间解耦。另外,通过依赖注入管理的的对象是POJO类,可以更好地进行测试。

如何选择合适的依赖注入方法?

最佳实践是通过构造器方法注入主要依赖对象,通过setter方法注入可选的依赖对象。虽然可以在setter方法上加上@Required注解来实现主要依赖对象注入,但一般还是推荐使用构造器注入必须的依赖。

使用构造器注入,可以使得应用的组件作为不可变的对象,而且可以保证注入依赖是非null的。另外,构造器注入返回的是一个完整的初始状态的实例。但是,一般不推荐大量使用构造方法注入,如果出现这种情况,则说明代码需要重构。

setter方法适合注入可选的依赖,这些依赖可能有默认值,而且在其他位置使用这些依赖时务必要进行null值检查。使用setter方法的一个好处是可以修改或者重新配置,或者需要时再注入。如基于JMX MBean的管理。

Spring依赖解析流程

首先ApplicationContext会被创建和初始化,会加载包括描述所有bean的元数据。这些配置元数据可以通过XML,Java代码或者注解来指定。

对于每一个bean,它的依赖表现形式是成员属性,构造器参数,或者静态工厂方法的参数。在bean真正创建时,Spring容器会提供这些依赖的对象。这些参数可能是需要设置的默认值,也可能是另外一个bean的引用。

Spring容器会验证每个bean的配置信息。并且在bean真正创建时才设置设置属性值或者参数值。

在Spring中,单例作用域的bean会提前初始化,在Spring容器创建时就进行了实例化。对于其他的作用域的bean,则只在需要时才进行创建。之所以单例作用域的bean会被提前初始化,主要是为了解决依赖检查的问题,下文的循环依赖一节会详细说明。

在Spring内部会构建一个创建bean的依赖图,按照这依赖关系来创建Bean。

循环依赖解决

如果使用构造函数注入,则不能有循环依赖的情况。如A构造器依赖B,同时B也构造器依赖A。Spring IoC容器会在运行时检测到循环依赖,抛BeanCurrentlyInCreationException异常。一种解决办法是通过setter方法来解决循环依赖的情况。

Spring会在容器加载时检测配置问题,如引用不存在或者循环依赖。Spring会在必要时才解析依赖,即尽可能晚的来解析依赖关系。延迟解析依赖可能导致后期请求获取对象时报错,如抛出一个异常,如丢失指定对象或者属性。这种配置的延迟的可见性导致的问题使得ApplicationContext的实现要求单例作用域的bean提前记性初始化。虽然会耗费内存和时间,因为并不是按需创建这些单例作用域的bean,但是可以在ApplicationContext创建时就可以发现配置问题。

下文会介绍通过指定bean的可以通过配置来覆盖默认的行为,使得单例作用域的bean也是延迟初始化。

如果没有循环依赖存在,则在注入依赖对象时,这些依赖的对象就已经初始化完成了。即如果A依赖B,则在A初始化时,B已经初始化完成了。也就是说,Bean是在相关依赖设置完成,并且相关的生命周期方法调用完毕后,才算是完成了初始化。

bean的延迟初始化

默认情况下ApplicationContext是提前初始化单例作用域的bean,作为ApplicationContext初始化的一部分。这样可以尽快的发现配置问题。可以通过指定bean的lazy-init="true",让bean在需要时才被初始化。

自动注入依赖

在Spring中可以自动注入依赖,可以减少指定属性或者构造器参数,还可以随着配置对象的变化来更新注入的对象。

自动注入依赖的模式有:通过名称注入,通过类型注入,和通过构造器注入

总结

本文总结了Spring中的依赖管理的基本原理和常见的问题,具体的依赖注入配置语法还需要参考Spring的官方文档来进行。


文末彩蛋

针对于上面所涉及到的知识点我总结出了有1到5年开发经验的程序员在面试中涉及到的绝大部分架构面试题及答案做成了文档和架构视频资料免费分享给大家(包括Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术资料),希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习,也可以关注我一下以后会有更多干货分享。

资料获取方式:后台私信“资料”即可

7358f0dd8f73a8e6843aeda8394d15b6.png
ab615047f98b648f05df8378637a360a.png
512745bdda85dc385776b5e3e6af5e79.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于Java中的构造函数,我们不能像普通方法一样直接使用Clone方法进行克隆,因为构造函数是在创建对象时自动调用的。但是,我们可以使用Javassist库来实现静态构造函数的克隆。 Javassist是一个用于在运行时修改字节码的Java库。我们可以使用Javassist创建一个新的类,并将原始类的所有方法和字段复制到新类中。然后,我们可以在新类中修改构造函数的实现,以实现克隆。 以下是一个示例代码,演示如何使用Javassist创建静态构造函数的克隆: ``` import javassist.*; public class ConstructorClone { public static void main(String[] args) throws Exception { ClassPool pool = ClassPool.getDefault(); CtClass origClass = pool.get("com.example.OriginalClass"); CtClass newClass = pool.makeClass("com.example.NewClass"); // Copy all fields and methods from original class to new class newClass.setSuperclass(origClass); CtField[] fields = origClass.getDeclaredFields(); for (CtField field : fields) { newClass.addField(field); } CtMethod[] methods = origClass.getDeclaredMethods(); for (CtMethod method : methods) { newClass.addMethod(method); } // Clone constructor CtConstructor origConstructor = origClass.getDeclaredConstructor(new CtClass[]{}); CtConstructor newConstructor = CtNewConstructor.copy(origConstructor, newClass, null); newClass.addConstructor(newConstructor); // Modify constructor implementation newConstructor.setBody("{ super(); }"); // Create instance of new class Object newObject = newClass.toClass().newInstance(); } } ``` 在上面的代码中,我们首先获取了原始类的CtClass对象,并创建了一个新的CtClass对象。然后,我们将原始类的所有字段和方法复制到新类中。接下来,我们使用CtNewConstructor.copy方法克隆原始类的构造函数,并将其添加到新类中。最后,我们修改新构造函数的实现,以调用原始构造函数并执行其他操作。 请注意,这只是一个示例代码,实际应用中可能需要更复杂的处理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值