Java创建对象和spring创建对象的过程和区别

news2025/4/3 14:25:23

 暮乘白帝过重山

new到IoC的演进,体现了软件工程从"怎么做"到"做什么"的思维转变。理解Java对象创建的底层机制,是写出高性能代码的基础;掌握Spring的Bean管理哲学,则是构建可维护大型系统的关键。二者如同汽车的发动机与智能驾驶系统——前者保证基础性能,后者提供高阶能力,共同推动Java生态持续发展。


从new到IoC:揭秘Java与Spring对象创建的差异与本质

一、Java原生对象创建全流程剖析

先来个王炸:Java的new关键字实际上是语法糖,其底层通过bytecode new + invokespecial两条指令协作完成。这种设计既保持了语言简洁性,又为JVM优化(如逃逸分析、栈上分配)留足了空间


1.1 new关键字背着我们都做了些什么???

当我们写下UserService service = new UserService()时,JVM会执行以下精密流程:

public class UserService {
    private int id;      // 默认0
    private String name; // 默认null
    
    {
        System.out.println("初始化块执行"); // 第1步
    }
    
    public UserService() {
        System.out.println("构造函数执行");  // 第2步
    }
}
  1. 类加载检查

    • JVM检查方法区是否已加载类元数据

    • 未加载则触发类加载机制(双亲委派模型)

  2. 内存分配

    • 计算对象大小(指针压缩影响)

    • 选择分配方式(指针碰撞/空闲列表)

    • 堆内存中划分对象空间

  3. 零值初始化

    • 所有基本类型赋默认值(int=0, boolean=false)

    • 引用类型置null

  4. 对象头设置

    • MarkWord(哈希码、GC年龄、锁状态)

    • 类型指针(指向类元数据)

  5. 初始化执行

    • 初始化块(按代码顺序)

    • 构造函数(显式初始化)

1.2 反射创建:灵活背后的代价

通过反射API创建对象的典型流程:

Class<?> clazz = Class.forName("com.example.UserService");
Constructor<?> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
UserService instance = (UserService) constructor.newInstance();

执行步骤:

  1. 类加载器加载目标类

  2. 获取构造器对象并绕过访问检查

  3. 通过Unsafe类分配内存

  4. 直接调用构造器(跳过常规初始化顺序)

1.3 其他创建方式对比

创建方式适用场景注意事项
Cloneable对象拷贝场景深拷贝/浅拷贝问题
反序列化网络传输、持久化存储绕开构造器执行
Unsafe.allocate极高性能需求可能破坏JVM内存模型

一些补充:

1.4 JavaBean规范

  1. 必须是公共类,类访问权限需为 public,以便外部访问。
  2. 提供无参公共构造方法,必须有一个 public 的无参数构造函数(默认构造方法),便于反射实例化。
  3. 属性私有化,属性(字段)必须用 private 修饰,通过公共方法访问。通过 getter/setter 访问属性,对每个 private 属性,提供标准的 getXxx()setXxx() 方法(布尔属性可用 isXxx())。
  4. 实现 Serializable 接口(可选但常见),支持序列化,便于网络传输或持久化存储。

 

二、Spring IoC容器对象创建全解析

 一样的,先来手王炸:Spring IoC容器对象创建

Spring创建对象的本质是通过BeanDefinition元数据驱动IoC容器执行一套标准化的对象生命周期管理流程,在运行时动态组装、增强和管理对象依赖关系,实现控制反转和面向切面编程的统一治理

什么?你有点被炸懵了?那我换种说法

Spring创建对象的核心机制就是IoC(控制反转)容器在运作

但更准确的说法是:

"Spring创建对象 = IoC容器管理 + 依赖注入 + 扩展增强"

通俗说就是:

  1. IoC容器是"工厂":它负责根据你的配置(注解/XML)生产对象(比如@Service标注的类)。

  2. 依赖注入是"自动装配":对象需要的其他组件(比如@Autowired的成员),Spring会自动塞进去。

  3. 扩展增强是"增值服务":AOP代理、生命周期回调等(比如@Transactional事务控制)。

为什么说"不只是IoC"?

  1. 单纯IoC:只是"不用你自己new"(控制权反转)。

  2. Spring的完整流程:还包括依赖注入(DI)、AOP、作用域管理(单例/原型)等,比传统IoC更强大。

(就像网购:IoC是"商家替你发货",而Spring是"发货+送货上门+七天无理由+赠品"一套完整服务)


 

2.1 Bean生命周期全景图

Spring Bean 的创建过程之所以远比直接 new 对象复杂,是因为它在底层构建了一套完整的对象生命周期管理体系。让我们通过一个生活中的比喻来理解这个精密过程:想象我们现在要建造房子(Bean),而 Spring 容器就像一个全能的建筑管理局,不仅负责砖瓦堆砌(对象创建),还要统筹水电布线(依赖注入)、安全监控(AOP)、装修验收(生命周期回调)等全套流程。OK,我们说一说建房子的一套简单流程


第1阶段:图纸审批(加载配置元数据)

  • 现实场景:向城建局提交房屋设计图(XML/注解/JavaConfig)

  • 技术实现

    1. 扫描 @ComponentScan 指定的包路径

    2. 解析 @Configuration 类中的 @Bean 方法

    3. 读取 XML 中的 <bean> 定义

    4. 处理 @Import 导入的其他配置

  • 关键机制:兄弟们记住:BeanDefinitionReader 任务就是将不同格式的配置统一转化为内存中的 Bean 然后能进行下一步


第2阶段:地基浇筑(也就是实例化Bean)

  • 现实场景:我们花钱请来一批施工队,然后施工队的任务是不是就是根据图纸打地基?(调用构造方法)

  • 技术细节

    // AbstractAutowireCapableBeanFactory
    protected Object createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        // 构造器推断算法:智能匹配参数最多的构造器
        Constructor<?> constructorToUse = determineConstructor(beanName, mbd);
        
        // 通过反射实例化或CGLIB动态生成子类
        return instantiateBean(beanName, mbd, constructorToUse, args);
    }
  • 我说一下,有种特殊特殊场景:记住是spring!!!
    当遇到循环依赖(A依赖B,B又依赖A)时,Spring 的"三级缓存"开始运作:

    1. 施工许可证公示(三级缓存 singletonFactories):提前暴露半成品对象

    2. 毛坯房展示(二级缓存 earlySingletonObjects):存放未装修的原始对象

    3. 精装房交付(一级缓存 singletonObjects):最终成品


第3阶段:毛坯的人生,精装的朋友圈,房子一样,毛坯房建好了,接下俩就是请水电师傅,叫他们水电安装(也就是属性填充)

  • 现实场景:给房屋安装水管(@Autowired)和电线(@Value)

  • 技术流程

    // 处理自动装配的核心逻辑
    for (PropertyValue pv : mbd.getPropertyValues().getPropertyValues()) {
        // 1. 解决依赖:在容器中查找匹配的Bean
        Object resolvedValue = resolveDependency(pv);
        
        // 2. 反射注入:通过Field.set()或setter方法
        ReflectionUtils.makeAccessible(field);
        field.set(beanInstance, resolvedValue);
    }
  • 智能处理

    • 遇到 @Lazy 注解时延迟加载

    • 对 @Qualifier 指定的 Bean 进行精确匹配

    • 处理 @Primary 标注的优先候选对象


第4阶段:最后要叫人来看看房子达不达标,也就是安全验收(BeanPostProcessor处理)

  1. 现实场景:消防检查(前置处理)和环保认证(后置处理)

  2. 代码示例

    public interface BeanPostProcessor {
        // 装修前检查(如@PostConstruct处理)
        default Object postProcessBeforeInitialization(Object bean, String name) { return bean; }
        
        // 装修后验收(如AOP代理包装)
        default Object postProcessAfterInitialization(Object bean, String name) { return bean; }
    }
  3. 开发中经常遇到的情况处理

    1. AutowiredAnnotationBeanPostProcessor 处理自动装配

    2. CommonAnnotationBeanPostProcessor 解析 @PostConstruct

    3. AbstractAdvisingBeanPostProcessor 准备AOP代理


第5阶段:精装修(初始化方法执行)

  1. 现实场景:安装智能家居系统(初始化逻辑)

  2. 执行顺序

    1. @PostConstruct 标注的方法 → 2. InitializingBean 接口的 afterPropertiesSet() → 3. XML 中配置的 init-method

  3. 代码演示

    public class SmartHomeService implements InitializingBean {
        @PostConstruct
        public void connectIoT() {
            System.out.println("连接智能设备...");
        }
        
        @Override
        public void afterPropertiesSet() {
            System.out.println("启动环境监测系统...");
        }
        
        public void initSceneMode() {
            System.out.println("配置情景模式...");
        }
    }


第6阶段:安防系统部署(AOP代理)

  • 现实场景:安装监控摄像头(切面逻辑)

  • 代理策略

    public DefaultAopProxyFactory createAopProxy(AdvisedSupport config) {
        // 条件判断:目标类是否有接口?是否是CGLIB代理?
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            return new ObjenesisCglibAopProxy(config);
        } else {
            return new JdkDynamicAopProxy(config);
        }
    }

  • 动态代理示例

    // JDK代理示例
    public class $Proxy12 extends Proxy implements UserService {
        public final void saveUser() {
            // 1. 执行@Before advice
            // 2. 调用target.saveUser()
            // 3. 执行@After advice
        }
    }


第7阶段:房产登记(注册单例池)

  • 现实场景:将房屋信息录入不动产登记中心

  • 最终存储

    // DefaultSingletonBeanRegistry
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    
    protected void addSingleton(String beanName, Object singletonObject) {
        synchronized (this.singletonObjects) {
            this.singletonObjects.put(beanName, singletonObject);
            this.singletonFactories.remove(beanName);
            this.earlySingletonObjects.remove(beanName);
        }
    }

2.2 核心阶段详解

阶段1:实例化(Instantiation)

  • 通过反射或CGLIB创建原始对象

  • 构造器解析策略:构造器参数匹配算法

阶段2:属性填充(Population)

  • 处理@Autowired/@Value注解

  • 解决循环依赖的三级缓存机制:

    1. singletonFactories(三级)

    2. earlySingletonObjects(二级)

    3. singletonObjects(一级)

阶段3:初始化(Initialization)

public class UserService implements InitializingBean {
    @PostConstruct
    public void customInit() {
        // 注解方式初始化
    }
    
    @Override
    public void afterPropertiesSet() {
        // 接口方式初始化
    }
    
    public void xmlInit() {
        // XML配置的初始化方法
    }
}

初始化顺序:

  1. @PostConstruct

  2. InitializingBean接口

  3. XML配置的init-method

2.3 代理与包装阶段(了解)

AOP代理的两种实现方式:

  • JDK动态代理:基于接口(生成$Proxy类)

  • CGLIB代理:基于继承(生成Enhancer子类)

代理时机选择:

// AbstractAutoProxyCreator
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        return bean;
    }
    // 创建代理逻辑...
}

三、核心差异对比与选型指南

3.1 核心机制对比表

维度Java原生创建Spring Bean创建
控制权开发者直接控制容器控制(IoC)
生命周期由JVM管理完整生命周期管理
依赖注入手动设置自动装配
对象类型原始类型可能被代理包装
创建成本低(约5ns)高(约5000ns)
作用域单一实例支持多种作用域

3.2 性能对比数据

通过JMH测试(纳秒/操作):

操作平均耗时99%分位
new创建5.27.1
反射创建18.725.3
Spring单例获取42.355.9
Spring原型创建4832.65214.8

3.3 最佳实践建议

适合Java原生创建的场景:

  • 高频创建的对象(如DTO)

  • 不需要依赖管理的工具类

  • 对启动速度敏感的应用

适合Spring管理的场景:

  • 需要依赖注入的业务组件

  • 需要AOP增强的服务类

  • 需要复杂生命周期的资源对象

四、深度思考:

4.1 对象管理范式的转变

Java原生方式体现命令式编程思想:

// 开发者全权控制
DBConn conn = new MySQLConn(config);
UserDAO dao = new UserDAO(conn);
Service service = new Service(dao);

Spring IoC体现声明式编程哲学:

@Configuration
public class AppConfig {
    @Bean
    public DBConn dbConn() { /*...*/ }
    
    @Bean
    public UserDAO userDAO(DBConn conn) { /*...*/ }
    
    @Bean
    public Service service(UserDAO dao) { /*...*/ }
}

4.2 扩展机制对比

Java原生扩展方式:

  1. 继承

  2. 组合

  3. SPI机制

Spring扩展方式:

  1. BeanPostProcessor

  2. BeanFactoryPostProcessor

  3. ImportSelector

  4. 条件化配置

4.3 现代编程趋势影响

  1. 响应式编程对对象创建的影响(Project Reactor的延迟创建)

  2. Serverless环境下的轻量化需求(Spring Native)

  3. 云原生时代的配置管理(Kubernetes与Spring Cloud整合)

五、做个总结

理解两种创建方式的本质差异,我们可以:

  1. 在传统单体架构中合理选择对象管理方式

  2. 在微服务架构中优化Bean初始化顺序

  3. 在云原生环境下平衡启动速度与便利性

  4. 深度定制Spring容器满足特殊需求

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2327272.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RabbitMQ应用2

RabbitMQ应用2 一.实际业务逻辑订单系统中使用MQ&#xff08;不写订单系统逻辑&#xff09;1.项目的创建和准备2.代码实现ControllerConfigurationproperties 二.物流系统使用MQ&#xff08;不实现物流系统业务&#xff09;1.项目创建同订单&#xff08;一样&#xff09;2.代码…

Windows 实战-evtx 文件分析--笔记

Windows 取证之EVTX日志 - 蚁景网安实验室 - 博客园 一.evtx日志文件是什么 从 Windows NT 6.0&#xff08;也就是 Windows Vista 和 Windows Server 2008&#xff09;开始&#xff0c;微软引入了一种全新的日志文件格式&#xff0c;称为 evtx。这种格式取代了之前 Windows 系…

【postgresql】锁概览

常规锁 场景测试案例

子组件使用:visible.sync=“visible“进行双向的绑定导致该弹窗与其他弹窗同时显示的问题

问题描述&#xff1a;最近写代码时遇到了一个问题&#xff1a;点击A弹窗后关闭&#xff0c;继续点击B弹窗&#xff0c;这时会同时弹窗A、B两个弹窗。经过排查后发现在子组件定义时使用了:visible.sync"visible"属性进行双向的数据绑定 <template> <el-dial…

【AI产品分享】面向图片的原始位置翻译功能

1. 背景 在撰写文字材料时&#xff0c;往往需要配套图像以增强表达效果。然而&#xff0c;有时自己绘制的图可能达不到理想的质量&#xff0c;而在其他文献材料中却能发现更清晰、直观的示例。希望在“站在巨人的肩膀上”优化自己的图像时&#xff0c;通常希望在保留原始图像的…

【无标题】跨网段耦合器解决欧姆龙CJ系列PLC通讯问题案例

欧姆龙CJ系列PLC不同网段的通讯问题 一、项目背景 某大型制造企业的生产车间内&#xff0c;采用了多台欧姆龙CJ系列PLC对生产设备进行控制。随着企业智能化改造的推进&#xff0c;需要将这些PLC接入工厂的工业以太网&#xff0c;以便实现生产数据的实时采集、远程监控以及与企业…

K8S学习之基础七十二:Ingress基于Https代理pod

Ingress基于Https代理pod 1、构建TLS站点 &#xff08;1&#xff09;准备证书&#xff0c;在xianchaomaster1节点操作 cd /root/ openssl genrsa -out tls.key 2048 openssl req -new -x509 -key tls.key -out tls.crt -subj /CCN/STBeijing/LBeijing/ODevOps/CNak.lucky.com…

node.js版本管理

概述 遇到了版本升级后&#xff0c;以前项目不兼容的问题。 下载一个node.js的版本管理工具&#xff0c;官网下载地址&#xff0c;可以选择版本下载&#xff0c;我选择的1.11.1版本的。下载完成后点击安装&#xff0c;分别选择nvm安装目录和nodejs的安装目录&#xff0c;点击安…

Gartner预计2025年AI支出达6440亿美元:数据中心与服务器市场的关键驱动与挑战

根据Gartner最新预测&#xff0c;2025年全球生成式人工智能&#xff08;GenAI&#xff09;支出将达到6440亿美元&#xff0c;较2024年增长76.4%&#xff0c;其中80%的支出将集中于硬件领域&#xff0c;尤其是集成AI能力的服务器、智能手机和PC等设备。这一增长的核心驱动力来自…

重新安装VMware tools为灰色无法点击问题解决|读取电脑文件的共享文件夹方法

1.问题VMware tools为灰色 sudo systemctl status vmware-tools 显示&#xff1a;Unit vmware-tools.service could not be found. 改 检测方式 弹出&#xff08;之前没有&#xff09; 在重启的瞬间点安装 弹出&#xff1a; 双击打开 右键打开终端&#xff0c;解压 cd ~ ta…

构造超小程序

文章目录 构造超小程序1 编译器-大小优化2 编译器-移除 C 异常3 链接器-移除所有依赖库4 移除所有函数依赖_RTC_InitBase() _RTC_Shutdown()__security_cookie __security_check_cookie()__chkstk() 5 链接器-移除清单文件6 链接器-移除调试信息7 链接器-关闭随机基址8 移除异常…

Outlook客户端无法连接到服务器,添加账户显示“无网络连接,请检查你的网络设置,然后重试。[2603]”

1、先切换一下到手机热点或者其他网络&#xff0c;判断是不是现在所连接的网络的问题。如果有VPN代理软件&#xff0c;网银软件&#xff0c;加密软件在后台运行&#xff0c;麻烦退出一下。 2、打开电脑上的 控制面板——网络和Internet——Internet选项——高级——先点击还原…

LlamaIndex实现RAG增强:融合检索(Fusion Retrieval)与混合检索(Hybrid Search)

&#x1f9e0; 向所有学习者致敬&#xff01; “学习不是装满一桶水&#xff0c;而是点燃一把火。” —— 叶芝 我的博客主页&#xff1a; https://lizheng.blog.csdn.net &#x1f310; 欢迎点击加入AI人工智能社区&#xff01; &#x1f680; 让我们一起努力&#xff0c;共创…

蓝桥杯冲刺:一维前缀和

系列文章目录 蓝桥杯系列&#xff1a;一维前缀和 文章目录 系列文章目录前言一、暴力的写法&#xff1a;二、一维前缀和的模板&#xff1a; 具体实现&#xff1a; 三、具体例题&#xff1a;求和 1.题目参考&#xff1a;2.以下是具体代码实现&#xff1a; 总结 前言 上次我介绍…

Ubuntu24.04-中文输入法的切换

Ubuntu24.04在安装后自带中文全拼输入法。。 根据官方的说明&#xff0c;需使用 shift super 空格 切换输入法&#xff0c;但在之前使用windows或者ubuntu的早些版本&#xff0c;多使用 Ctrl 空格 的方式切换输入法&#xff0c;本文就介绍如何进行输入法快捷键切换的配置&a…

技术回顾day3

1.获取文件信息、获取视频信息 走的都是同一个方法&#xff1a;baseController里面的getFile。 在getFile方法里面进行判断文件的类型&#xff0c;判断是不是m3u8类型或者ts类型做一些额外的处理。 获取信息底层就是读取文件&#xff0c;然后写入response的OutputStream ou…

埃文科技企业AI大模型一体机——昇腾体系+DeepSeek+RAG一站式解决方案

面对企业级市场海量数据资产与复杂业务场景深度耦合的刚需&#xff0c;埃文科技重磅推出基于华为昇腾算力DeepSeek大模型的企业一体机产品&#xff0c;提供DeepSeek多版本大模型一体机选择&#xff0c;为企业提供本地昇腾算力DeepSeek大模型RAG知识库的一体化解决方案&#xff…

JavaWeb开发基础知识-Servlet终极入门指南(曼波萌新版)

(✪▽✪)曼波~~~~&#xff01;欢迎来到Servlet新手村&#xff01;准备好开启Web开发的奇妙冒险了吗&#xff1f;让曼波用最有趣的方式带你飞~ &#x1f680; &#x1f308; 第①章 什么是Servlet&#xff1f; // 本质就是一个Java类&#xff01; public class HelloServlet e…

游戏引擎学习第198天

回顾并为今天的内容设定 今天我们有一些代码需要处理。昨天我们进行了一些调试界面的整合工作&#xff0c;之前我们做了一些临时的、粗糙的操作&#xff0c;将一些东西读进来并放到调试界面中。今天&#xff0c;我们并不打算进行大规模的工作&#xff0c;更多的是对之前的代码…

Walrus 基金会启动 RFP 计划,推动生态发展

Walrus 基金会正式推出 Walrus RFP 提案申请计划&#xff0c;为推动和支持 Walrus 生态的项目提供资金支持。该计划旨在助力构建符合协议使命的解决方案&#xff0c;解锁去中心化和可编程存储的潜力。 无论项目是开发新工具、探索集成&#xff0c;还是提出创新用例&#xff0c…