当前位置:首页 > 技术 > 正文内容

Spring IOC 容器核心概念与高级特性详解

访客 技术 2026年6月28日 2

概述

在前文中,我们探讨了Spring IOC的基本使用方式,本文将深入讲解Spring容器的高级特性,包括Bean的作用域、生命周期回调、工厂模式实现、容器后置处理器等核心概念。这些知识对于理解Spring框架的内部运行机制至关重要。

一、Bean的核心属性配置

1.1 Bean的作用域

Spring容器中的Bean可以具有不同的作用域,决定了Bean实例的创建方式和生命周期范围。

作用域类型:

  • singleton:单例模式,容器仅创建唯一一个实例,默认作用域
  • prototype:原型模式,每次获取Bean时都会创建新实例
  • request:HTTP请求级别,仅在Web应用中使用有效
  • session:HTTP会话级别,仅在Web应用中使用有效
  • globalSession:全局会话级别,适用于Portlet环境

XML配置方式:

<bean id="userService" class="com.example.service.UserService" 
      scope="prototype">
    <property name="name" value="Test"/>
</bean>

注解方式:

@Component
@Scope("prototype")
public class UserService {
    
}

1.2 Bean的延迟加载

默认情况下,单例Bean在容器启动时就会被实例化。通过延迟加载配置,可以让Bean在首次使用时才进行初始化。

XML配置:

<bean id="dataService" class="com.example.service.DataService" 
      lazy-init="true"/>

注解方式:

@Component
@Lazy
public class DataService {
    
}

1.3 Bean的生命周期回调

Spring允许在Bean初始化和销毁时执行特定的回调方法。

实现方式一:注解方式

package com.example.lifecycle;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class ProductService {
    
    public ProductService() {
        System.out.println("构造函数执行");
    }
    
    @PostConstruct
    public void initMethod() {
        System.out.println("初始化方法执行");
    }
    
    @PreDestroy
    public void destroyMethod() {
        System.out.println("销毁方法执行");
    }
}

实现方式二:接口方式

package com.example.lifecycle;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class OrderService implements InitializingBean, DisposableBean {
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean初始化回调");
    }
    
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean销毁回调");
    }
}

XML配置方式:

<bean id="orderService" class="com.example.lifecycle.OrderService"
      init-method="customInit" destroy-method="customDestroy"/>

执行顺序说明:

构造函数 → 接口初始化方法 → 自定义初始化方法 → 自定义销毁方法 → 接口销毁方法

二、使用工厂模式创建Bean

2.1 构造器方式

这是最常用的Bean创建方式,Spring通过调用类的构造方法实例化Bean。

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

2.2 实例工厂方法

使用已有的工厂Bean来创建目标Bean实例。

定义产品接口

package com.example.factory;

public interface IProduct {
    void display();
}

实现具体产品

package com.example.factory;

public class Computer implements IProduct {
    @Override
    public void display() {
        System.out.println("这是一台电脑");
    }
}

public class Phone implements IProduct {
    @Override
    public void display() {
        System.out.println("这是一部手机");
    }
}

创建工厂类

package com.example.factory;

public class ProductFactory {
    public IProduct createProduct(String type) {
        if ("computer".equals(type)) {
            return new Computer();
        } else if ("phone".equals(type)) {
            return new Phone();
        }
        throw new IllegalArgumentException("不支持的产品类型");
    }
}

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    
    <bean id="productFactory" class="com.example.factory.ProductFactory"/>
    
    <bean id="computer" factory-bean="productFactory" factory-method="createProduct">
        <constructor-arg value="computer"/>
    </bean>
    
    <bean id="phone" factory-bean="productFactory" factory-method="createProduct">
        <constructor-arg value="phone"/>
    </bean>
</beans>

测试代码

package com.example.factory;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class FactoryTest {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("factory.xml");
        IProduct computer = (IProduct) ctx.getBean("computer");
        IProduct phone = (IProduct) ctx.getBean("phone");
        computer.display();
        phone.display();
    }
}

2.3 静态工厂方法

通过调用类的静态方法来创建Bean,无需先创建工厂实例。

package com.example.staticfactory;

public class StaticProductFactory {
    public static IProduct getProduct(String type) {
        if ("computer".equals(type)) {
            return new Computer();
        } else if ("phone".equals(type)) {
            return new Phone();
        }
        throw new IllegalArgumentException("不支持的产品类型");
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans">
    <bean id="computer" class="com.example.staticfactory.StaticProductFactory" 
          factory-method="getProduct">
        <constructor-arg value="computer"/>
    </bean>
    <bean id="phone" class="com.example.staticfactory.StaticProductFactory" 
          factory-method="getProduct">
        <constructor-arg value="phone"/>
    </bean>
</beans>

2.4 两种工厂方式的对比

对比项实例工厂静态工厂
是否需要配置工厂Bean需要不需要
使用属性factory-beanclass
factory-method必需必需
构造函数参数通过constructor-arg指定通过constructor-arg指定

三、FactoryBean与BeanFactory的区别

3.1 FactoryBean特性

FactoryBean是一种特殊的Bean实现接口后,通过getBean获取的不是该Bean本身,而是其getObject()方法的返回值。

package com.example.fb;

import org.springframework.beans.factory.FactoryBean;

public class MessageFactoryBean implements FactoryBean<String> {
    private String prefix;
    private String suffix;
    
    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }
    
    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }
    
    @Override
    public String getObject() throws Exception {
        return prefix + "Hello World" + suffix;
    }
    
    @Override
    public Class<?> getObjectType() {
        return String.class;
    }
    
    @Override
    public boolean isSingleton() {
        return true;
    }
}
<bean id="messageBean" class="com.example.fb.MessageFactoryBean">
    <property name="prefix" value="【"/>
    <property name="suffix" value="】"/>
</bean>
ApplicationContext ctx = new ClassPathXmlApplicationContext("fb.xml");
// 获取的是MessageFactoryBean的getObject()返回值
String message = (String) ctx.getBean("messageBean");  
// 获取FactoryBean本身,需要在id前加&
MessageFactoryBean factory = (MessageFactoryBean) ctx.getBean("&messageBean");

3.2 BeanFactory接口

BeanFactory是Spring容器的核心接口,提供了获取Bean的基本方法。

public interface BeanFactory {
    Object getBean(String name);
    <T> T getBean(Class<T> requiredType);
    <T> T getBean(String name, Class<T> requiredType);
    boolean containsBean(String name);
    Class<?> getType(String name);
}

ApplicationContext是BeanFactory的子接口,提供了更丰富的企业级功能。

四、容器后置处理器

4.1 Bean后置处理器

Bean后置处理器允许在Bean初始化前后执行自定义逻辑,常用于生成代理对象。

package com.example.bpp;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class TimingBeanPostProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) 
            throws BeansException {
        if ("userService".equals(beanName)) {
            System.out.println("UserService初始化前处理");
        }
        return bean;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) 
            throws BeansException {
        if ("userService".equals(beanName)) {
            System.out.println("UserService初始化后处理");
        }
        return bean;
    }
}

使用ApplicationContext时会自动检测并注册BeanPostProcessor。使用BeanFactory需要手动注册:

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions("config.xml");

TimingBeanPostProcessor processor = factory.getBean(TimingBeanPostProcessor.class);
factory.addBeanPostProcessor(processor);

4.2 容器后置处理器

容器后置处理器在容器本身初始化时执行,用于修改BeanDefinition。

package com.example.bfp;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 
            throws BeansException {
        System.out.println("容器后处理器执行");
    }
}

五、容器感知接口

5.1 BeanFactoryAware

让Bean获取创建它的BeanFactory容器引用。

package com.example.aware;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;

public class PaymentService implements BeanFactoryAware {
    private BeanFactory container;
    
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.container = beanFactory;
    }
    
    public void process() {
        // 可以通过容器获取其他Bean
        ValidationService validator = container.getBean(ValidationService.class);
        validator.validate();
    }
}

5.2 BeanNameAware

让Bean获取其在容器中的名称。

package com.example.aware;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;

public class CacheService implements BeanNameAware {
    private String beanName;
    
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("当前Bean名称: " + name);
    }
}

5.3 ApplicationContextAware

让Bean获取ApplicationContext容器引用。

package com.example.aware;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class EventPublisher implements ApplicationContextAware {
    private ApplicationContext context;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) 
            throws BeansException {
        this.context = applicationContext;
    }
    
    public void publish(String message) {
        context.publishEvent(new MessageEvent(context, message));
    }
}

六、ApplicationContext事件机制

Spring的事件机制基于观察者模式,由事件源、事件和监听器三部分组成。

6.1 自定义事件

package com.example.event;

import org.springframework.context.ApplicationContext;
import org.springframework.context.event.ApplicationContextEvent;

public class OrderEvent extends ApplicationContextEvent {
    private String orderId;
    
    public OrderEvent(ApplicationContext source, String orderId) {
        super(source);
        this.orderId = orderId;
    }
    
    public String getOrderId() {
        return orderId;
    }
}

6.2 定义事件监听器

package com.example.event;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

public class OrderListener implements ApplicationListener<OrderEvent> {
    
    @Override
    public void onApplicationEvent(OrderEvent event) {
        System.out.println("收到订单事件,订单号: " + event.getOrderId());
        // 处理订单逻辑
    }
}
package com.example.event;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

public class LogListener implements ApplicationListener {
    
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("记录日志: " + event.getClass().getSimpleName());
    }
}

6.3 发布事件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans">
    <bean id="orderListener" class="com.example.event.OrderListener"/>
    <bean id="logListener" class="com.example.event.LogListener"/>
    <bean id="orderService" class="com.example.event.OrderService"/>
</beans>
package com.example.event;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class OrderService implements ApplicationContextAware {
    private ApplicationContext context;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.context = applicationContext;
    }
    
    public void createOrder(String orderId) {
        System.out.println("创建订单: " + orderId);
        context.publishEvent(new OrderEvent(context, orderId));
    }
}
package com.example.event;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class EventTest {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("event.xml");
        OrderService orderService = ctx.getBean(OrderService.class);
        orderService.createOrder("ORD-001");
    }
}

6.4 事件执行流程

当ApplicationContext发布事件时,所有实现ApplicationListener接口的Bean都会收到通知。容器在初始化时会自动发布ContextRefreshedEvent事件。

七、总结

本文深入介绍了Spring IOC容器的高级特性,涵盖了Bean的多种配置方式、工厂模式的应用、容器后置处理器的工作原理以及事件驱动机制。理解这些核心概念有助于更好地掌握Spring框架的内部运行原理,为开发复杂的企业级应用奠定基础。后续将继续探讨Spring AOP面向切面编程的相关内容。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。