Spring IOC 容器核心概念与高级特性详解
概述
在前文中,我们探讨了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-bean | class |
| 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面向切面编程的相关内容。