Spring的IOC

发布于:2025-03-23 ⋅ 阅读:(28) ⋅ 点赞:(0)

如下图,展示了Spring的大体框架。本文将详细介绍Spring框架中的IOC(控制反转)机制及其应用。

依赖注入就是给对象赋值,依赖注入是通过容器为对象动态赋值的一种设计模式

IOC(控制反转)将对象的创建与管理交由Spring框架处理,其底层机制依赖于反射技术。

AOP(面向切面编程)无需改动原有代码即可增强功能,提升系统的模块化和可维护性,其底层机制依赖于代理技术。

引言

下图展示了代码的文件夹结构截图,其中Animal和User是类,Config在下文的纯注解方案里使用,ATest和UserTest是两个测试类分别测试Animal和User,Spring.xml文件中包含相关XML配置语句。

下图展示了在IntelliJ IDEA中创建Spring.xml文件的简单步骤:

基于xml配置的形式

创建对象

在Spring.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-->
    <!--id:类的唯一标识符 class:类的全路径名-->
    <bean id="user" class="com.qcby.entity.User"/>
    <bean id="animal" class="com.qcby.entity.Animal"/>
    <!--Class clazz=Class.forName("全类名")-->

<!--Spring.xml文件是Spring框架的配置信息-->
</beans>

在UserTest文件:

package com.qcby;

import com.qcby.entity.Animal;
import com.qcby.entity.User;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserTest {

//传统创建对象方法
    @Test
    public void test(){
        User user=new User();
        user.run();
    }
//Spring方式
    @Test
    public void test1(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("Spring.xml");
        User user= (User) ac.getBean("user");
        user.run();
    }
    @Test
    public void test2(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("Spring.xml");
        Animal animal= (Animal) ac.getBean("animal");
        animal.flay();
    }
}

在Spring框架中,对象的创建可以通过两种方式实现:使用BeanFactoryApplicationContext

  1. BeanFactory:采用延迟加载机制,即在加载配置文件时不会立即创建对象,只有在调用getBean()方法获取对象时才会进行实例化。例如:

    BeanFactory bf = new ClassPathXmlApplicationContext("Spring.xml");  
    Animal animalBF = (Animal) bf.getBean("animal");  

    这种方式适合资源有限的环境,但首次获取对象时可能会有性能开销。

  2. ApplicationContext:在加载配置文件时立即创建并初始化所有单例对象,无需等待getBean()调用。例如:

    ApplicationContext ac = new ClassPathXmlApplicationContext("Spring.xml");  
    Animal animal = (Animal) ac.getBean("animal");  

    这种方式在应用启动时完成对象的创建,适合大多数场景,能够提高运行时性能。

总结来说,BeanFactory延迟加载,适合资源敏感场景;ApplicationContext预加载,适合需要高性能的应用。

依赖注入

依赖注入(赋值)的实现方式主要有两种:

通过setter和getter方法:在类中定义setter方法,Spring容器调用该方法为属性赋值。

通过构造方法:在类中定义带参数的构造方法,Spring容器通过构造方法直接注入依赖对象。

通过set和get

Spring.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="user" class="com.qcby.entity.User">
        <property name="age" value="18"/>
        <property name="name" value="Lee"/>
        <property name="animal" ref="animal"/>
    </bean>

    <bean id="animal" class="com.qcby.entity.Animal">
        <property name="strs">
            <array>
                <value>ZhangSan</value>
                <value>LiSi</value>
                <value>WangWu</value>
                <value>ZhaoLiu</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>XiaoBai</value>
                <value>XiaoHong</value>
                <value>XiaoLv</value>
            </list>
        </property>
        <property name="map">
            <map>
                <entry key="1" value="aa"/>
                <entry key="2" value="bb"/>
                <entry key="3" value="cc"/>
            </map>
        </property>
    </bean>

</beans>

ATest:

package com.qcby;

import com.qcby.entity.Animal;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ATest {

    @Test
    public void a(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("Spring.xml");
        Animal animal= (Animal) ac.getBean("animal");
        System.out.println(animal.toString());
    }
}

通过构造器

Spring.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="user" class="com.qcby.entity.User">
        <constructor-arg name="age" value="18"/>
        <constructor-arg name="name" value="Lee"/>
        <constructor-arg name="animal" ref="animal"/>
    </bean>

    <bean id="animal" class="com.qcby.entity.Animal">
        <constructor-arg name="strs">
            <array>
                <value>ZhangSan</value>
                <value>LiSi</value>
                <value>WangWu</value>
                <value>ZhaoLiu</value>
            </array>
        </constructor-arg>
        <constructor-arg name="list">
            <list>
                <value>XiaoBai</value>
                <value>XiaoHong</value>
                <value>XiaoLv</value>
            </list>
        </constructor-arg>
        <constructor-arg name="map">
            <map>
                <entry key="1" value="aa"/>
                <entry key="2" value="bb"/>
                <entry key="3" value="cc"/>
            </map>
        </constructor-arg>
    </bean>

</beans>

基于注解的形式

Spring框架为Bean管理提供了多种注解,用于标识不同层次的组件并创建Bean实例:

@Component:通用的注解,用于标注普通的类,将其作为Bean注册到Spring容器中。

@Controller:专门用于表现层(如MVC模式中的控制器),标识该类为Web层的组件。

@Service:用于业务逻辑层,标识该类包含业务逻辑,是服务层的组件。

@Repository:用于持久层,通常标注在数据访问对象(DAO)类上,标识该类负责数据库操作。

虽然这四个注解的功能相同,都可以创建Bean实例,但通过不同的注解可以更清晰地划分代码层次,增强代码的可读性和可维护性。在实际开发中,应根据类的职责选择合适的注解。

创建对象

Spring.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 开启注解扫描,扫描 com.qcby.entity 包中的所有类 -->
<context:component-scan base-package="com.qcby.entity" />

</beans>

User:

package com.qcby.entity;

import org.springframework.stereotype.Component;

@Component
public class User {

    public void run(){
        System.out.println("human run fast");
    }
}

UserTest:

package com.qcby;

import com.qcby.entity.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserTest {

    @Test
    public void test1(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("Spring.xml");
        User user= (User) ac.getBean("user");
        user.run();
    }
}

实现注入

@Value 用于注入普通类型(String,int,double等类型)
@Autowired 默认按类型进行自动装配(引用类型)
@Qualifier 不能单独使用必须和@Autowired一起使用,强制使用名称注入
@Resource Java提供的注解,也被支持。使用name属性,按名称注入

纯注解方案

这种方法不需要xml

Config.java:

package com.qcby.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(value = "com.qcby.entity")
public class Config {

}

UserTest:

package com.qcby;

import com.qcby.config.Config;
import com.qcby.entity.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserTest {

    @Test
    public void test1(){
        ApplicationContext ac=new AnnotationConfigApplicationContext(Config.class);
        User user= (User) ac.getBean("user");
        user.run();
    }
}