springIOC创建对象的方式--spring容器中的注入

Spring IOC 本质:IOC = Inversion of Control,控制反转

spring容器=bean

把对象的创建、依赖管理、生命周期控制权,从程序员自己手动 new,交给 Spring 容器统一管理。

传统写法(正控:程序员掌控一切)

c 复制代码
// 自己手动new对象
UserService service = new UserService();
// 自己手动给属性赋值、创建依赖对象
UserDao dao = new UserDao();
service.setDao(dao);

控制权在你代码手里:你想什么时候 new、怎么赋值、什么时候销毁,全由代码硬编码决定。

IOC 写法(反转:容器接管控制权)

你只在配置 / 注解里告诉 Spring:需要哪些类、谁依赖谁。

Spring 容器自动:

创建实例对象

自动装配依赖(自动 set 注入 / 构造注入)

管理对象单例 / 多例、初始化、销毁

对象生命周期的控制权,反转交给了 IoC 容器,这就是控制反转。

  1. 核心两大核心职能,就是 IOC 容器的本体
    ① 实例化:Bean 工厂
    容器就是一个超大 Map 容器:Map<bean名称, 实例对象>
    启动时扫描所有组件,提前创建好对象存入 Map,后续你用 getBean() 直接从容器里取,不用自己 new。
    ② 依赖注入 DI(IOC 最核心落地手段)
    DI = Dependency Injection 依赖注入
    IOC 是思想,DI 是实现 IOC 的具体方式。
    容器自动把一个类需要的其他对象,自动注入进去,不用手动编码装配依赖
    Spring IoC 创建 Bean 对象的 5 种常用方式:

传统的创建对象方式

1、new User();//通过无参构造实例化化对象

2、new User(name);//通过有参构造实例化化对象

spring容器(bean)创建对象(实例化对象)

一、无参构造方法创建(默认最基础方式)

规则

Spring 会默认调用类无参构造函数实例化对象,XML / 注解方式默认都是此方式。

clike 复制代码
<!-- 只指定类,底层自动调用无参构造 -->
<bean id="user" class="com.pojo.User"/>

前提:类必须存在无参构造,如果只写了有参构造、没写无参,直接报错。

二、有参构造器创建(构造注入)

方式 1:下标索引赋值

csharp 复制代码
<bean id="user" class="com.pojo.User">
    <!-- index 对应构造方法参数位置,从0开始 -->
    <constructor-arg index="0" value="张三"/>
    <constructor-arg index="1" value="18"/>
</bean>

方式 2:参数名匹配

bash 复制代码
<constructor-arg name="username" value="李四"/>

方式 3:参数类型匹配

c 复制代码
<constructor-arg type="java.lang.String" value="王五"/>

依赖注入

1、构造器注入

2、set方式注入(重点)

XML:set 注入、构造注入;

注解:@Autowired按类型、@Resource按名称、@Value注入配置;

DI 本质:容器帮你给类的依赖属性赋值。

三、DI 依赖注入(Dependency Injection)超全详解

DI = Dependency Injection 依赖注入

IOC 是思想(控制反转):把对象创建、依赖管理交给容器;

DI 是 IOC 的具体实现手段:容器主动将当前类需要的依赖对象,自动赋值注入进去,不用自己new依赖。

二、Spring 4 种主流注入方式

  1. Setter 注入(标签,最常用)
    条件
    类中必须提供 setXxx () 方法,Spring 通过反射调用 set 方法赋值。
bash 复制代码
<!-- 1. 普通基本类型/字符串 -->
<bean id="user" class="com.pojo.User">
    <property name="username" value="张三"/>
    <property name="age" value="18"/>
</bean>

<!-- 2. 注入容器中其他Bean对象(ref引用) -->
<bean id="userDao" class="com.dao.UserDao"/>
<bean id="userService" class="com.service.UserService">
    <!-- name对应setDao,ref指向另一个bean的id -->
    <property name="dao" ref="userDao"/>
</bean>
  1. 构造器注入()
    条件
    类提供带参数构造方法,容器实例化 Bean 时直接通过构造方法传参创建对象。
cpp 复制代码
<bean id="user" class="com.pojo.User">
    <!-- 方式1:按构造参数下标(从0开始) -->
    <constructor-arg index="0" value="李四"/>
    <!-- 方式2:按参数名匹配 -->
    <constructor-arg name="age" value="22"/>
    <!-- 方式3:按参数类型匹配 -->
    <constructor-arg type="int" value="22"/>
    <!-- 注入其他Bean -->
    <constructor-arg name="dao" ref="userDao"/>
</bean>
c 复制代码
 <!--p命令空间注入,直接注入属性值对比传统的set注入 -->
    <bean id="user2" class="com.cn.User" p:name="p标签写法" p:gae="20"/>
    <!--c命令空间注入,通过构造器注入属性值对比传统的构造注入-->
    <bean id="user1" class="com.cn.User" c:name="构造器" c:gae="30"/>

两种对比:

c 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
    1、语法:p:属性名="值"

    <bean id="student" class="com.cn.Student"
          p:name="张三"
          p:age="20"/>
    等价写法

    <bean id="student" class="com.cn.Student">
        <property name="name" value="张三"/>
        <property name="age" value="20"/>
    </bean>

    2、 引用其他 Bean 对象(对象依赖)
    p:属性名-ref="目标beanId"

    <bean id="address" class="com.cn.Address" p:city="乌鲁木齐"/>

    <bean id="student" class="com.cn.Student"
          p:name="李四"
          p:address-ref="address"/>

等价写法
<property name="address" ref="address"/>
    -->
    <!--1、传统写法-->

    <bean id="adder" class="com.cn.Adderss"/>
    <bean id="user" class="com.cn.User">
        <property name="name" value="传统写法"/>
        <property name="gae" value="20"/>
    </bean>

    <!--p:写法
    1、语法:p:属性名="值"
reference:ref==引用

    <bean id="student" class="com.cn.Student"
          p:name="张三"
          p:age="20"/>-->

    <!--p命令空间注入,直接注入属性值对比传统的set注入 -->
    <bean id="user2" class="com.cn.User" p:name="p标签写法" p:gae="20"/>
    <!--c命令空间注入,通过构造器注入属性值对比传统的构造注入-->
    <bean id="user1" class="com.cn.User" c:name="构造器" c:gae="30"/>


    <bean id="stu" class="com.cn.User">
        <!-- 第一个参数 -->
        <constructor-arg value="小明"/>
        <!-- 第二个参数 -->
        <constructor-arg value="18"/>
    </bean>
    <bean id="stu1" class="com.cn.User">
        <!-- 第一个参数 -->
        <constructor-arg value="小明"/>
        <!-- 第二个参数 -->
        <constructor-arg value="18"/>
    </bean>
    <bean id="stu2" class="com.cn.User">
        <constructor-arg index="0" value="小红"/>
        <constructor-arg index="1" value="20"/>
    </bean>
</beans>
  1. 字段注入(注解开发主流,直接给成员变量赋值)
    不需要 set / 构造方法,直接在属性上加注解,底层反射暴力赋值。
    ① @Autowired(Spring 原生,按类型 byType 注入)
c 复制代码
@Service
public class UserService {
    // 直接注入,不需要set方法
    @Autowired
    private UserDao userDao;
}

③ @Value 注入普通字面量 / 配置文件值

bash 复制代码
// 直接写死值
@Value("小明")
private String name;
// 读取properties配置文件
@Value("${db.url}")
private String url;
相关推荐
名字还没想好☜16 小时前
Go 的 time.Ticker 陷阱:定时任务里被忽略的内存泄漏与正确关闭
java·数据库·golang·go·定时器
音符犹如代码16 小时前
后端视角看 EventBus:发布订阅总线的原理、场景与用法
java·spring boot·guava
前端炒粉16 小时前
手撕小汇总
java·前端·javascript
唐青枫17 小时前
Java Kafka 实战指南:从 Topic、分区到 Spring Boot 可靠消息处理
java
脱胎换骨-军哥17 小时前
C++零成本抽象理论深度拆解:现代C++如何在不牺牲性能的前提下提供高级语法封装
java·开发语言·c++
我是唐青枫18 小时前
Java Netty 实战指南:从 NIO 线程模型到 TCP 编解码和心跳机制
java·tcp/ip·nio
小白说大模型18 小时前
从向量嵌入到复杂 Agent:LLM、LangChain、LangGraph 完整科普
java·开发语言·人工智能·gpt·深度学习·langchain
zhanghaha131419 小时前
Python语言基础:4_数据类型转换
java·前端·python
Devin~Y20 小时前
互联网大厂Java面试实战:Spring Boot、MyBatis、Redis、Kafka、JWT、Spring Cloud 与 AI 场景追问
java·spring boot·redis·spring cloud·kafka·mybatis·spring security