Spring Boot 基于 BeanPostProcessor 结合动态代理的扩展应用(二)
上一篇我们简述了 BeanPostProcessor 自动为标注了自定义注解的 Bean 设置默认值的扩展应用, 这篇文章我们来介绍下 BeanPostProcessor 结合动态代理的扩展应用。
基本原理
BeanPostProcessor 在 Spring 容器初始化时被触发,它允许我们在 Spring 管理的 Bean 实例化后、初始化前或初始化后对 Bean 进行加工处理。通过 BeanPostProcessor 我们可以在 Spring 管理的 Bean 上创建动态代理,增强 Bean 的功能。我们将使用 Java 的 Proxy 类来创建动态代理,代理将拦截目标方法的调用,并添加日志功能。
实现步骤
- 创建接口和实现类
首先,我们定义一个简单的接口和一个实现类。
java
public interface ProcessorService {
void executor();
}
@Service
@Slf4j
public class ProcessorServiceImpl implements ProcessorService {
@Override
public void executor() {
log.info("executor service");
}
}
编写 BeanPostProcessor 动态代理类
接下来,我们编写一个 BeanPostProcessor 实现类,这个类会在 Spring 初始化 Bean 之后为 ProcessorService 类型的 Bean 创建一个代理对象。
java
@Component
@Slf4j
public class LoggingBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ProcessorService) {
// 创建动态代理
return Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(),new LoggingInvocationHandler(bean));
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
private static class LoggingInvocationHandler implements InvocationHandler {
private final Object target;
private LoggingInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 打印日志:方法调用前
log.info("before method {}", method.getName());
// 执行目标方法
Object result = method.invoke(target, args);
// 打印日志:方法调用后
log.info("after method {}", method.getName());
return result;
}
}
}
配置 Spring Boot 应用
java
@SpringBootApplication
public class ExtendApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(ExtendApplication.class, args);
ProcessorService processorService = context.getBean(ProcessorService.class);
processorService.executor();
}
}
运行结果
当我们运行这个 Spring Boot 应用时,控制台将输出类似以下内容:
text
2024-12-09 10:29:57.835 INFO 28856 --- [ main] c.s.b.e.p.LoggingBeanPostProcessor : before method executor
2024-12-09 10:29:57.836 INFO 28856 --- [ main] c.s.b.e.processor.ProcessorServiceImpl : executor service
2024-12-09 10:29:57.836 INFO 28856 --- [ main] c.s.b.e.p.LoggingBeanPostProcessor : after method executor
总结
通过实现 BeanPostProcessor,我们可以灵活地对 Spring 管理的 Bean 进行动态代理,从而在不修改 Bean 本身的代码的情况下,增强其功能。在这个示例中,我们为 ProcessorService 类型的 Bean 添加了日志记录功能,利用了 Java 的反射机制和 Proxy 类来创建代理对象。