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

从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步
}

}
类加载检查:

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

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

内存分配:

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

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

堆内存中划分对象空间

零值初始化:

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

引用类型置null

对象头设置:

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

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

初始化执行:

初始化块(按代码顺序)

构造函数(显式初始化)

1.2 反射创建:灵活背后的代价
通过反射API创建对象的典型流程:

Class clazz = Class.forName("com.example.UserService"); Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
UserService instance = (UserService) constructor.newInstance();
执行步骤:

类加载器加载目标类

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

通过Unsafe类分配内存

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

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

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

二、Spring IoC容器对象创建全解析
一样的,先来手王炸:Spring IoC容器对象创建

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

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

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

但更准确的说法是:

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

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

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

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

为什么说"不只是IoC"?
单纯IoC:只是"不用你自己new"(控制权反转)。

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

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

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

第1阶段:图纸审批(加载配置元数据)
现实场景:向城建局提交房屋设计图(XML/注解/JavaConfig)

技术实现:

扫描 @ComponentScan 指定的包路径

解析 @Configuration 类中的 @Bean 方法

读取 XML 中的 定义

处理 @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 的"三级缓存"开始运作:

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

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

精装房交付(一级缓存 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处理)
现实场景:消防检查(前置处理)和环保认证(后置处理)

代码示例:

public interface BeanPostProcessor {
// 装修前检查(如@PostConstruct处理)
default Object postProcessBeforeInitialization(Object bean, String name) { return bean; }

// 装修后验收(如AOP代理包装)
default Object postProcessAfterInitialization(Object bean, String name) { return bean; }

}
开发中经常遇到的情况处理

AutowiredAnnotationBeanPostProcessor 处理自动装配

CommonAnnotationBeanPostProcessor 解析 @PostConstruct

AbstractAdvisingBeanPostProcessor 准备AOP代理

第5阶段:精装修(初始化方法执行)
现实场景:安装智能家居系统(初始化逻辑)

执行顺序:

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

代码演示:

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注解

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

singletonFactories(三级)

earlySingletonObjects(二级)

singletonObjects(一级)

阶段3:初始化(Initialization)

public class UserService implements InitializingBean {
@PostConstruct
public void customInit() {
// 注解方式初始化
}

@Override
public void afterPropertiesSet() {
    // 接口方式初始化
}

public void xmlInit() {
    // XML配置的初始化方法
}

}
初始化顺序:

@PostConstruct

InitializingBean接口

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.2 7.1
反射创建 18.7 25.3
Spring单例获取 42.3 55.9
Spring原型创建 4832.6 5214.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原生扩展方式:

继承

组合

SPI机制

Spring扩展方式:

BeanPostProcessor

BeanFactoryPostProcessor

ImportSelector

条件化配置

4.3 现代编程趋势影响
响应式编程对对象创建的影响(Project Reactor的延迟创建)

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

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

五、做个总结
理解两种创建方式的本质差异,我们可以:

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

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

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

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

posted @ 2025-04-01 13:41  痛打落水狗一万  阅读(67)  评论(0)    收藏  举报