Spring IOC:控制反转与依赖注入

一、什么是IOC?

IOC(Inversion of Control,控制反转) 是Spring框架的基石,其核心在于将对象的创建、依赖注入和生命周期管理权交给容器。传统开发中,对象间的强耦合关系会导致“牵一发而动全身”的问题,而IOC通过工厂模式+反射机制实现了彻底的解耦。例如:

// 传统方式:类A直接依赖类B
class A {
    B b = new B();
}

IOC的优势

  • 解耦:通过Spring容器统一管理对象生命周期,避免类之间的直接依赖。

  • 灵活性:修改依赖关系时无需改动源码,只需调整配置文件或注解。

二、IOC程序的入门

1.创建java工程,导入坐标依赖

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency> 
    <dependency> 
        <groupId>commons-logging</groupId> 
        <artifactId>commons-logging</artifactId> 
        <version>1.2</version> 
    </dependency> 
    <dependency> 
        <groupId>log4j</groupId> 
        <artifactId>log4j</artifactId> 
        <version>1.2.12</version> 
    </dependency> 
    <dependency> 
        <groupId>junit</groupId> 
        <artifactId>junit</artifactId> 
        <version>4.12</version> 
        <scope>test</scope> 
    </dependency> 
</dependencies>

2.编写接口和实现类,编写具体的实现方法

package com.qcby.service;
public interface UserService { 
    public void hello();
} 

package com.qcby.service; 
public class UserServiceImpl implements UserService { 
    @Override 
    public void hello() { 
        System.out.println("Hello IOC!!");
    }
}

3.编写 Spring 核心的配置文件,在 src 目录下创建 applicationContext.xml 的配置文件,名称是可以任意的,但是一般都会使用默认名称。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--IOC 管理 bean-->
    <bean id="userService" class="com.qcbyjy.service.UserServiceImpl"/>
</beans>

4.编写测试方法。

package com.qcbyjy.test;
    import com.qcbyjy.service.UserService;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Demo1 {

    @Test
    public void run1(){
        // 使用 Spring 的工厂
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 通过工厂获得类:
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.hello();
    }
}

三、依赖注入(Dependency Injection)DI

依赖注入:在 Spring 框架负责创建 Bean 对象时,动态的将依赖对象注入到 Bean 组件中

(1)属性的 set 方法注入值

编写属性,提供该属性对应的 set 方法,编写配置文件完成属性值的注入

package com.qcby.service;
    import com.qcbyjy.dao.OrderDao;
    public class OrderServiceImpl implements OrderService {
        // 编写成员属性,一定需要提供该属性的 set 方法
        private OrderDao orderDao;
        // IOC容器底层通过属性的set方法注入值
        public void setOrderDao(OrderDao orderDao) {
            this.orderDao = orderDao;
        }
        // 消息
        private String msg;
        // 年龄
        private int age;
        public void setMsg(String msg) {
            this.msg = msg;
        }
        public void setAge(int age) {
            this.age = age;
        }
        @Override
        public void saveOrder() {
            System.out.println("业务层:保存订单..."+msg+" - "+age);
            // 调用
            orderDao.saveOrder();
        }
    }
package com.qcby.dao;
public class OrderDaoImpl implements OrderDao {
    @Override
    public void saveOrder() {
        System.out.println("持久层:保存订单...");
    }
}
    <!--DI:依赖注入-->
    <bean id="os" class="com.qcbyjy.service.OrderServiceImpl">
        <property name="orderDao" ref="od" />
        <property name="msg" value="你好" />
        <property name="age" value="30" />
    </bean>
    <bean id="od" class="com.qcbyjy.dao.OrderDaoImpl"></bean>

(2)属性构造方法方式注入值

对于类成员变量,构造函数注入。

package com.qcbyjy.demo2;
    public class Car {
    // 名称
    private String cname;
    // 金额
    private Double money;
    public Car(String cname, Double money) {
        this.cname = cname;
        this.money = money;
    }
    @Override
    public String toString() {
        return "Car{" +"cname='" + cname + '\'' +", money=" + money +'}';
    }
}
    <bean id="car" class="com.qcbyjy.demo2.Car">
        <constructor-arg name="cname" value="大奔" />
        <constructor-arg name="money" value="400000" />
    </bean>

(3)数组,集合(List,Set,Map),Properties等的注入

package com.qcbyjy.demo3;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    import java.util.Properties;
public class CollectionBean {
    // 数组
    private String [] strs;
    public void setStrs(String[] strs) {
        this.strs = strs;
    }
    private List<String> list;
    public void setList(List<String> list) {
        this.list = list;
    }
    private Map<String,String> map;
    public void setMap(Map<String, String> map) {
        this.map = map;
    }
    private Properties properties;
    public void setProperties(Properties properties) {
        this.properties = properties;}
    @Override
    public String toString() {
        return "CollectionBean{" +"strs=" + Arrays.toString(strs) +", 
        list=" + list +", map=" + map +", properties=" + properties +'}';
    }
}
<!--给集合属性注入值-->
<bean id="collectionBean" class="com.qcbyjy.demo3.CollectionBean">
    <property name="strs">
        <array>
            <value>美美</value>
            <value>小凤</value>
        </array>
    </property>
    <property name="list">
        <list>
            <value>熊大</value>
            <value>熊二</value>
        </list>
    </property>
    <property name="map">
        <map>
            <entry key="aaa" value="老王"/>
            <entry key="bbb" value="小王"/>
        </map>
    </property>
    <property name="properties">
        <props>
            <prop key="username">root</prop>
            <prop key="password">123456</prop>
        </props>
</property>
</bean>

多配置文件的加载方式

//1.主配置文件中包含其他的配置文件:
<import resource="applicationContext2.xml"/>
//2.工厂创建的时候直接加载多个配置文件:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"applicationContext.xml","applicationContext2.xml");

四、IOC 注解的方式

1. 常用注解

  • @Component:通用组件标记。

  • @Controller:表现层组件。

  • @Service:业务层组件。

  • @Repository:持久层组件。

2. 使用步骤

(1) 开启注解扫描
<context:component-scan base-package="com.qcby"/>
(2) 定义Bean
package com.qcbyjy.demo2;
import org.springframework.stereotype.Component;
//在需要管理的类上添加@Component 注解,代替<beanid="us"class="com.qcbyjy.demo2.UserServiceImpl" />
@Component(value = "us")
public class UserServiceImpl implements UserService {
    @Override
    public void hello() {
        System.out.println("Hello IOC 注解...");
    }
}
(3) 属性注入

依赖注入常用注解:

  • @Value:注入基本类型值。

  • @Autowired:按类型自动装配。

  • @Qualifier:按名称装配,需与@Autowired配合。

  • @Resource Java 提供的注解,也被支持。使用 name 属性,按名称注入

对象生命周期(作用范围)注解:

  • @Scope 生命周期注解,取值 singleton(默认值,单实例)和 prototype(多例)

初始化方法和销毁方法注解(了解):

  • @PostConstruct 相当于 init-method
  • @PreDestroy 相当于 destroy-method
@Service
public class UserService {
    @Autowired
    @Qualifier("userDao")
    private UserDao userDao;
    
    @Value("${jdbc.url}")
    private String jdbcUrl;

    @PostConstruct
    public void init(){
        System.out.println("进行初始化操作");
    }
    @PreDestroy
    public void des(){
        System.out.println("执行销毁操作");
    }    
}

六、纯注解配置(Spring Boot风格)

纯注解的目的是替换掉所有的配置文件。但是需要编写配置类。

1. 核心注解

  • @Configuration:标记类为配置类。

  • @ComponentScan:指定扫描包路径。

2. 编写配置类,替换掉 applicationContext.xml 配置文件

@Configuration
@ComponentScan("com.qcby")
public class SpringConfig {
    @Bean
    public DataSource dataSource() {
        return new DruidDataSource();
    }
}

3. 测试代码

public class Test {
    @Test
        public void run1(){
            // 创建工厂,加载配置类
            ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
            // 获取到对象
            Order order = (Order) ac.getBean("order");
            System.out.println(order);
}

七、总结

  • IOC核心价值:通过解耦提升代码可维护性和扩展性。

  • XML vs 注解

    • XML:集中管理配置,适合大型项目。

    • 注解:简洁高效,适合快速开发。

  • 适用场景:微服务架构下推荐纯注解方式,传统项目可混合使用。

掌握Spring IOC是Java开发的核心技能,合理运用能显著提升代码质量!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值