Spring从入门到实战 IoC

本文详细介绍了Spring框架的IoC(控制反转)机制,包括其原理、使用方式、配置细节及高级特性,如依赖注入、自动装配、作用域管理等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring IoC概述

视频地址

  • Spring框架两大核心机制(IoC和AOP)

    • IoC(控制反转)/ID(依赖注入)
    • AOP(面向切面编程)
  • Spring是一个企业级开发框架,是软件设计层面的框架,优势在于可以将应用程序进行分层,开发者可以自主选择组件。

    • MVC: Struts、Spring MVC
    • OBMapping: Hibernate、MyBatis、Spring Data
  • Spring体系结构

    img

  • 什么是控制反转

    • 在传统的程序开发中,需要调用对象时,通常由调用者来创建被调用者的实例,即对象是由调用者主动new出来的
    • 但在Spring框架中创建对象的工作不再由调用者来完成,而是交给IoC容器来创建,再推送给调用者,整个流程完成反转,所以是控制反转。
  • 如何使用IoC

    • 创建Maven工程,pom.xml添加依赖
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.0.11.RELEASE</version>
            </dependency>
            <!--简化实体类的开发-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.6</version>
                <scope>provided</scope>
            </dependency>
        </dependencies>
    
    • 创建实体类Student
    package com.southwind.entity;
    import lombok.Data;
    @Data
    public class Student {
        private long id;
        private String name;
        private  int age;
    }
    
    • 传统的开发方式,手动new Student
    Student student = new Student();
    student.setId(1L);
    student.setName("张三");
    student.setAge(22);
    System.out.println(student);
    
    • 通过IoC创建对象,在配置文件中添加需要管理的对象,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-3.0.xsd">
    
            <bean id="student" class="com.southwind.entity.Student">
                    <property name="id" value="1"></property>
                    <property name="name" value="张三"></property>
                    <property name="age" value="22"></property>
            </bean>
    
    </beans>
    
    • 从IoC中获取对象,通过id获取
    //加载配置文件
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
    Student student = (Student) applicationContext.getBean("student");
    System.out.println(student);
    

配置文件

  • 通过配置bean标签来完成对象的管理

    • id:对象名
    • class:对象的模板类(所有交给IoC容器来管理的类必须有无参构造函数,因为Spring底层是通过反射机制来创建对象,调用的是无参构造)
  • 对象的成员变量通过property标签完成赋值

    • name:成员变量名
    • value:成员变量值(基本数据类型,String可以直接赋值,如果是引用类型,不能通过value赋值)
    • ref:将IoC中的另一个bean赋值给当前的成员变量(DI)
            <bean id="student" class="com.southwind.entity.Student">
                    <property name="id" value="1"></property>
                    <property name="name" value="张三"></property>
                    <property name="age" value="22"></property>
                    <property name="address" ref="address"></property>
            </bean>
            <bean id="address" class="com.southwind.entity.Address">
                    <property name="id" value="1"></property>
                    <property name="name" value="科技路"></property>
            </bean>
    

IoC底层原理

  • 读取配置文件,解析XML
  • 通过反射机制实例化配置文件中所配置的所有bean

通过运行时类获取bean

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Student student = (Student) applicationContext.getBean(Student.class);
System.out.println(student);

这种方式存在一个问题,配置文件中的一个数据类型的对象只能有一个实例,否则会抛出异常,因为没有唯一的bean。

通过有参构造创建bean

  • 在实体类中创建对应的有参构造函数
  • 配置文件
<bean id="student3" class="com.southwind.entity.Student">
        <constructor-arg name="id" value="3"></constructor-arg>
        <constructor-arg name="name" value="小明"></constructor-arg>
        <constructor-arg name="age" value="18"></constructor-arg>
        <constructor-arg name="address" ref="address"></constructor-arg>
</bean>

(通过name)或(通过下标)

<bean id="student3" class="com.southwind.entity.Student">
        <constructor-arg index="0" value="3"></constructor-arg>
        <constructor-arg index="2" value="18"></constructor-arg>
        <constructor-arg index="1" value="小明"></constructor-arg>
        <constructor-arg index="3" ref="address"></constructor-arg>
</bean>

给bean注入集合

		<bean id="student" class="com.southwind.entity.Student">
                <property name="id" value="1"></property>
                <property name="name" value="张三"></property>
                <property name="age" value="22"></property>
                <property name="addresses">
                        <list>
                                <ref bean="address"></ref>
                                <ref bean="address2"></ref>
                        </list>
                </property>
        </bean>
        
        <bean id="address" class="com.southwind.entity.Address">
                <property name="id" value="1"></property>
                <property name="name" value="科技路"></property>
        </bean>
        <bean id="address2" class="com.southwind.entity.Address">
                <property name="id" value="2"></property>
                <property name="name" value="高新区"></property>
        </bean>

spoce 作用域

  • Spring管理的bean是根据scope来生成的,表示bean的作用域,共4种,默认是singletion
    • singleton:单例,表示通过IoC容器获取的bean是唯一的
    • prototype:原型,表示通过IoC容器获取的bean是不同的
    • request:请求,表示在一次HTTP请求内有效
    • session:回话,表示在一个用户会话内有效
  • request和session只适用于Web项目,大多数情况下,使用单例和原型较多
  • prototype模式党业务代码获取IoC容器中的bean时,Spring才会去调用无参构造创建对应的bean
  • singleton模式无论业务代码是否获取IoC容器中的bean,Spring在加载spring.xml时就会创建bean

Spring的继承

  • 与java的继承不同,java是类层面的继承,子类可以继承父类的内部结构信息;Spring是对象层面的继承,子对象可以继承父对象的属性值
        <bean id="student2" class="com.southwind.entity.Student">
                <property name="id" value="1"></property>
                <property name="name" value="张三"></property>
                <property name="age" value="22"></property>
                <property name="addresses">
                        <list>
                                <ref bean="address"></ref>
                                <ref bean="address2"></ref>
                        </list>
                </property>
        </bean>
        <bean id="stu" class="com.southwind.entity.Student" parent="student2">
                <property name="name" value="李四"></property>
        </bean>

        <bean id="address" class="com.southwind.entity.Address">
                <property name="id" value="1"></property>
                <property name="name" value="科技路"></property>
        </bean>
        <bean id="address2" class="com.southwind.entity.Address">
                <property name="id" value="2"></property>
                <property name="name" value="高新区"></property>
        </bean>
  • Spring的继承关注点在于具体的对象,而不在于类,即不同的两个类的实例化对象可以完全继承,前提是子对象必须包含父对象的所有属性,同时可以在此基础上添加其他属性。

Spring的依赖

  • 与继承相似,依赖也是描述bean和bean之间的一种关系,配置依赖之后,被依赖的bean一定先创建,再创建依赖的bean,例如A依赖于B,先创建B,再创建A
<?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-3.0.xsd">

        <bean id="user" class="com.southwind.entity.User" depends-on="student"></bean>
        <bean id="student" class="com.southwind.entity.Student"></bean>
</beans>

Spring的p命名空间

  • p命名空间是对IoC/DI的简化操作,使用p命名空间可以更加方便的完成bean的配置以及bean之间的依赖注入
<?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:contest="http://www.springframework.org/schema/context"
        xmlns:p="http://www.springframework.org/schema/p"
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans
	    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
">

        <bean id="student" class="com.southwind.entity.Student" p:id="1" p:name="张三" p:age="22" p:address-ref="address"></bean>
        <bean id="address" class="com.southwind.entity.Address" p:id="2" p:name="科技路"></bean>

</beans>

Spring的工厂方法

  • IoC通过工厂模式创建bean的方式有两种

    • 静态工厂方法
    package com.southwind.entity;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    public class Car {
        private long id;
        private String name;
    }
    
    package com.southwind.factory;
    
    import com.southwind.entity.Car;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class StaticCarFactory {
        private static Map<Long, Car> carMap;
        static{
            carMap = new HashMap<Long, Car>();
            carMap.put(1L,new Car(1L,"宝马"));
            carMap.put(2L,new Car(2L,"奔驰"));
        }
        public static Car getCar(long id){
            return carMap.get(id);
        }
    }
    
    <!-- 配置静态工厂创建Car -->
    <bean id="car" class="com.southwind.factory.StaticCarFactory" factory-method="getCar">
            <constructor-arg value="2"></constructor-arg>
    </bean>
    
    • 实例工厂方法
    package com.southwind.factory;
    
    import com.southwind.entity.Car;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class InstanceCarFactory {
        private Map<Long, Car> carMap;
        public InstanceCarFactory(){
            carMap = new HashMap<Long, Car>();
            carMap.put(1L,new Car(1L,"宝马"));
            carMap.put(2L,new Car(2L,"奔驰"));
        }
        public Car gerCar(long id) {
            return carMap.get(id);
        }
    }
    
            <!-- 配置实例工厂 bean -->
            <bean id="carFactory" class="com.southwind.factory.InstanceCarFactory"></bean>
            <!-- 配置实例工厂 创建car -->
            <bean id="car2" factory-bean="carFactory" factory-method="gerCar">
                    <constructor-arg value="1"></constructor-arg>
            </bean>
    

IoC自动装载(Autowire)

  • IoC负责创建对象,DI负责完成对象的依赖注入,通过配置property标签的ref属性来完成,同时Spring提供了另外一种更加简便的依赖注入方式:自动装载,不需要手动配置property,IoC容器会自动选择bean完成注入

  • 自动装载有两种方式:

    • byName:通过属性名自动装载
            <bean id="car" class="com.southwind.entity.Car">
                    <property name="id" value="1"></property>
                    <property name="name" value="宝马"></property>
            </bean>
            <bean id="person" class="com.southwind.entity.Person" autowire="byName">
                    <property name="id" value="1"></property>
                    <property name="name" value="张三"></property>
            </bean>
    
    • byType:通过属性的数据类型自动装载

    使用时需要注意,如果同时存在两个及以上的符合条件的bean时,自动装载会抛出异常

            <bean id="car1" class="com.southwind.entity.Car">
                    <property name="id" value="1"></property>
                    <property name="name" value="宝马"></property>
            </bean>
            <bean id="person" class="com.southwind.entity.Person" autowire="byType">
                    <property name="id" value="1"></property>
                    <property name="name" value="张三"></property>
            </bean>
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值