Spring扩展点案例

首先Spring扩展点有三个

1、BeanPostProcessor这个可以在Bean实例前后进行增强

2、BeanFactoryPostProcessor这个是用来修改Bean的元数据的

3、FactoryBean是通过java来进行初始化而不是xml

创建一个Bean的流程

  1. 我们模拟一个 “订单服务(OrderService)” 的开发场景,流程如下:

    1. FactoryBean:封装 OrderService 的复杂初始化(比如加载订单模板配置、初始化缓存)。
    2. BeanFactoryPostProcessor:在 OrderService 实例化前,动态修改其元数据(比如根据环境切换订单超时时间)。
    3. BeanPostProcessor:在 OrderService 初始化后,增强其方法(比如添加订单操作的日志记录)。

    整个项目是标准 Spring Boot 结构,靠 @SpringBootApplication 自动启动容器,无需手动创建 ApplicationContext

实际案例

1、首先有一个核心业务类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 业务类:订单服务
public class OrderService {
// 订单超时时间(单位:分钟,会被BeanFactoryPostProcessor动态修改)
private int orderTimeout;
// 订单模板(会被FactoryBean初始化时加载)
private String orderTemplate;

// Spring初始化方法(@PostConstruct替代xml的init-method)
@PostConstruct
public void init() {
System.out.println("OrderService初始化完成:超时时间=" + orderTimeout + "分钟,模板=" + orderTemplate);
}

// 核心业务方法:创建订单
public void createOrder(String orderId) {
System.out.println("创建订单:" + orderId + ",超时时间:" + orderTimeout + "分钟");
}

// getter/setter(用于注入值)
public void setOrderTimeout(int orderTimeout) { this.orderTimeout = orderTimeout; }
public void setOrderTemplate(String orderTemplate) { this.orderTemplate = orderTemplate; }
}

2、FactoryBean 实现 : OrderServiceFactoryBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 工厂Bean:封装OrderService的复杂初始化(比如加载模板、校验配置)
@Component // 注册到Spring容器(替代@Bean,更简洁)
public class OrderServiceFactoryBean implements FactoryBean<OrderService> {

// 模拟复杂初始化:加载订单模板(实际开发可能是读配置文件/数据库)
@Override
public OrderService getObject() throws Exception {
OrderService orderService = new OrderService();
// 加载模板(这里模拟从配置中心获取)
String template = loadOrderTemplateFromConfig();
orderService.setOrderTemplate(template);
// 初始超时时间(会被BeanFactoryPostProcessor覆盖)
orderService.setOrderTimeout(30);
return orderService;
}

// 模拟从配置中心加载模板
private String loadOrderTemplateFromConfig() {
System.out.println("FactoryBean:从配置中心加载订单模板");
return "标准版订单模板(含物流信息)";
}

// 明确返回的Bean类型(必须写,否则Spring无法识别)
@Override
public Class<?> getObjectType() {
return OrderService.class;
}

// 默认单例(可不重写,默认返回true)
@Override
public boolean isSingleton() {
return true;
}
}

3、BeanFactoryPostProcessor 实现:OrderMetadataProcessor(修改元数据)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 元数据处理器:在OrderService实例化前修改超时时间
@Component // 注册到Spring容器,容器启动时自动执行
public class OrderMetadataProcessor implements BeanFactoryPostProcessor, Ordered {

// 从配置文件读取环境(dev/prod,Spring Boot会自动加载application.properties)
@Value("${spring.profiles.active:dev}")
private String activeEnv;

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 1. 找到OrderService的元数据(注意:此时OrderService还没实例化,只能操作BeanDefinition)
// 因为OrderService由FactoryBean创建,所以BeanName是"orderServiceFactoryBean"
BeanDefinition factoryBeanDef = beanFactory.getBeanDefinition("orderServiceFactoryBean");

// 2. 从FactoryBean的属性中获取OrderService的初始配置(通过FactoryBean的getObject()返回)
// 这里通过"factoryBeanObjectType"拿到OrderService的类型,再动态修改超时时间
if (OrderService.class.equals(factoryBeanDef.getFactoryBeanObjectType())) {
// 开发环境超时30分钟,生产环境60分钟
int timeout = "dev".equals(activeEnv) ? 30 : 60;
// 3. 修改元数据:给OrderService的orderTimeout属性设值(覆盖FactoryBean的初始30)
// 这里通过BeanWrapper操作FactoryBean创建的对象属性
BeanWrapper wrapper = new BeanWrapperImpl(OrderService.class);
wrapper.setPropertyValue("orderTimeout", timeout);

System.out.println("BeanFactoryPostProcessor:环境=" + activeEnv + ",已修改OrderService超时时间为" + timeout + "分钟");
}
}

// 执行顺序:值越小越先执行(多个BeanFactoryPostProcessor时生效)
@Override
public int getOrder() {
return 1;
}
}

4、BeanPostProcessor 实现:OrderLogPostProcessor(增强实例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Bean后置处理器:在OrderService初始化后添加日志增强
@Component // 注册到Spring容器,容器会自动调用
public class OrderLogPostProcessor implements BeanPostProcessor, Ordered {

// 初始化前:可做参数校验
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof OrderService) {
System.out.println("BeanPostProcessor(前):OrderService即将初始化,准备校验参数");
}
return bean;
}

// 初始化后:生成代理对象,增强createOrder方法(添加日志)
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof OrderService) {
System.out.println("BeanPostProcessor(后):OrderService初始化完成,生成日志代理");

// 使用JDK动态代理增强createOrder方法
return Proxy.newProxyInstance(
OrderService.class.getClassLoader(),
new Class[]{OrderService.class},
(proxy, method, args) -> {
if ("createOrder".equals(method.getName())) {
// 增强逻辑:打印方法执行日志
System.out.println("【订单日志】开始执行createOrder,订单ID:" + args[0]);
Object result = method.invoke(bean, args); // 执行原方法
System.out.println("【订单日志】createOrder执行完成,订单ID:" + args[0]);
return result;
}
return method.invoke(bean, args); // 其他方法不增强
}
);
}
return bean;
}

// 执行顺序:值越小越先执行
@Override
public int getOrder() {
return 1;
}
}

5、启动类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Spring Boot启动类:一行注解启动容器,无需手动写main函数操作容器
@SpringBootApplication
public class OrderApplication {
// 注入OrderService(此时注入的是FactoryBean生成的实例,不是FactoryBean本身)
@Autowired
private OrderService orderService;

// 项目启动后执行(CommandLineRunner:Spring Boot提供的启动后回调)
@Bean
public CommandLineRunner testOrderService() {
return args -> {
System.out.println("\n===== 测试OrderService方法 =====");
orderService.createOrder("ORDER_20240520_001"); // 调用增强后的方法
};
}

// Spring Boot自动生成main函数(实际开发中可省略,IDE会自动补全)
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}

image-20251031183502261