BeanPostProcessor使用心得

本文介绍了一种使用Spring的BeanPostProcessor实现对项目中所有Bean进行代理的方法,通过自定义BeanPostProcessor来监控Bean的方法调用情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

出处:http://guoliangqi.iteye.com/blog/635826

最近想对项目中的所有bean进行一个代理。然后监控bean得方法的使用情况。


        刚开始想的方法是:重写项目的beanFactory,然后再getBean的使用,对结果object进行一个代理,达到我的目的。但是发现重写getBean的方法,无法对bean中的依赖注入的bean(set进来的bean)进行代理。

       正好看到了beanPostProcessor的使用方法。可以在spring的xml的配置一个BeanPostProcessor,然后对所有的bean进行一个代理处理,正好可以满足我的需求!

BeanPostProcessor代码如下:
Java代码   收藏代码
  1. import java.lang.reflect.Proxy;  
  2. import java.util.Map;  
  3. import java.util.concurrent.ConcurrentHashMap;  
  4.   
  5. import org.springframework.beans.BeansException;  
  6. import org.springframework.beans.factory.config.BeanPostProcessor;  
  7.   
  8. import com.alibaba.common.logging.Logger;  
  9. import com.alibaba.common.logging.LoggerFactory;  
  10.   
  11. public class MyBeanPostProcesser implements BeanPostProcessor {  
  12.     private Map map = new ConcurrentHashMap(100);  
  13.     private static final Logger log = LoggerFactory.getLogger("myBeanPostProcesser");  
  14.   
  15.     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  
  16.         MyProxy proxy = new MyProxy();  
  17.   
  18.         if (beanName.contains("DB")) {  
  19.             return bean;  
  20.         }  
  21.   
  22.         if (bean.toString().contains("Proxy")) {  
  23.             log.info(beanName + "为代理类,不进行再次代理!");  
  24.             return bean;  
  25.         }  
  26.         if (beanName.contains("TransactionTemplate")) {  
  27.             log.info(beanName + "为TransactionTemplate类,不进行再次代理!该类为:" + bean);  
  28.             return bean;  
  29.         }  
  30.   
  31.         if (map.get(beanName) != null) {  
  32.             log.info(beanName + "已经代理过,不进行再次代理!");  
  33.             return map.get(beanName);  
  34.         }  
  35.         proxy.setObj(bean);  
  36.         proxy.setName(beanName);  
  37.         Class[] iterClass = bean.getClass().getInterfaces();  
  38.         if (iterClass.length > 0) {  
  39.             Object proxyO = Proxy.newProxyInstance(bean.getClass().getClassLoader(), iterClass, proxy);  
  40.             map.put(beanName, proxyO);  
  41.             return proxyO;  
  42.         } else {  
  43.             log.info(beanName + "么有接口不进行代理!");  
  44.             return bean;  
  45.         }  
  46.     }  
  47.   
  48.     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {  
  49.         return bean;  
  50.     }  
  51.   
  52. }  
 

代理类Proxy代码如下:
Java代码   收藏代码
  1. import java.lang.reflect.InvocationHandler;  
  2. import java.lang.reflect.Method;  
  3.   
  4. import com.alibaba.common.logging.Logger;  
  5. import com.alibaba.common.logging.LoggerFactory;  
  6.   
  7. import sun.reflect.Reflection;  
  8.   
  9. public class MyProxy implements InvocationHandler {  
  10.     private static final Logger log = LoggerFactory.getLogger("myself");  
  11.   
  12.     private Object obj;  
  13.   
  14.     private String name;  
  15.   
  16.     public String getName() {  
  17.         return name;  
  18.     }  
  19.   
  20.     public void setName(String name) {  
  21.         this.name = name;  
  22.     }  
  23.   
  24.     public Object getObj() {  
  25.         return obj;  
  26.     }  
  27.   
  28.     public void setObj(Object obj) {  
  29.         this.obj = obj;  
  30.     }  
  31.   
  32.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  33.         System.out.println("begin================" + "bean 名称为【" + name + "】方法为【" + method.getName() + "】========="  
  34.                 + obj.getClass());  
  35.         log.error("begin================" + "bean 名称为【" + name + "】方法为【" + method.getName() + "】========="  
  36.                 + obj.getClass());  
  37.         return method.invoke(obj, args);  
  38.     }  
  39.   
  40.     public void printDetail(String detail) {  
  41.         log.error(detail);  
  42.     }  
  43.   
  44. }  
 
感觉还是比较好使的!记录一下。以后再有监控的需求,可以考虑使用这种方式了!

<think>好的,我需要回答用户关于BeanPostProcessor在业务场景中的使用方式的问题。首先,我需要回顾一下BeanPostProcessor的基本概念。根据引用[1],BeanPostProcessorSpring中的一个扩展点,允许在bean初始化前后执行自定义逻辑。用户可能想知道具体在哪些业务场景下会用到它,以及实际案例。 接下来,我应该考虑常见的应用场景。比如,代理对象的生成,这在AOP中很常见。引用[3]提到了ApplicationContextAwareProcessor,这个类用来注入IOC容器到组件中,这也是一个使用场景。另外,引用[2]提到了各种PostProcessor,如InstantiationAwareBeanPostProcessor,这可能涉及属性处理或初始化前后的操作。 然后,我需要将这些场景具体化,给出实际案例。例如,实现Aware接口的注入,日志增强,属性校验,动态代理等。每个案例都需要简要说明实现方式,并引用相关的参考资料。比如,在AOP中,BeanPostProcessor可能用于生成代理对象,这里可以参考引用[1]和[3]。 还要注意用户提到的业务场景,所以需要强调这些案例在业务中的实际应用,比如日志记录、权限检查、数据校验等。同时,可能需要提到如何自定义BeanPostProcessor,并确保注册到Spring容器中,如引用[2]中的例子。 最后,需要检查是否有遗漏的场景,并确保回答结构清晰,分点列出,每个场景都有案例和引用支持。同时,按照用户的要求,生成相关问题,帮助用户进一步了解。</think>### Spring BeanPostProcessor 使用场景及案例分析 BeanPostProcessorSpring 框架中实现 **扩展性** 的核心接口,作用于 Bean 初始化前后,常用于以下业务场景: --- #### 1. 实现 Aware 接口的底层支持 **场景**:为 Bean 注入 Spring 容器底层对象(如 ApplicationContext、BeanFactory) **案例**: Spring 内置的 `ApplicationContextAwareProcessor` 实现了该逻辑。通过 `postProcessBeforeInitialization` 方法,检测 Bean 是否实现了 `ApplicationContextAware` 接口,并注入 ApplicationContext: ```java public Object postProcessBeforeInitialization(Object bean, String beanName) { if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); } return bean; } ``` **业务价值**:允许业务组件直接访问容器资源[^3]。 --- #### 2. AOP 动态代理生成 **场景**:为 Bean 创建代理对象以实现切面编程 **案例**: `AbstractAutoProxyCreator`(AOP 核心类)继承自 BeanPostProcessor,在 `postProcessAfterInitialization` 中通过判断切点匹配度,决定是否用代理对象替换原始 Bean: ```java public Object postProcessAfterInitialization(Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); // 生成代理 } } return bean; } ``` **业务价值**:实现日志记录、事务管理等横切关注点[^1][^3]。 --- #### 3. 属性校验与增强 **场景**:在 Bean 初始化后校验或修改属性 **案例**: 自定义 BeanPostProcessor 实现属性格式校验: ```java public class ValidationPostProcessor implements BeanPostProcessor { public Object postProcessAfterInitialization(Object bean, String beanName) { if (bean instanceof User) { User user = (User) bean; if (!isValidEmail(user.getEmail())) { throw new IllegalStateException("邮箱格式错误"); } } return bean; } } ``` **业务价值**:统一校验逻辑,避免分散在业务代码中。 --- #### 4. 自定义注解解析 **场景**:通过注解驱动 Bean 行为 **案例**: 解析自定义注解 `@RoutingDataSource`,动态切换数据源: ```java public Object postProcessBeforeInitialization(Object bean, String beanName) { if (bean instanceof DataSource && bean.getClass().isAnnotationPresent(RoutingDataSource.class)) { // 根据注解配置初始化路由逻辑 return createRoutingDataSource(bean); } return bean; } ``` **业务价值**:简化多数据源配置,提升可维护性。 --- #### 5. 生命周期监控 **场景**:记录 Bean 初始化耗时或状态 **案例**: 统计 Bean 初始化时间并输出日志: ```java public Object postProcessBeforeInitialization(Object bean, String beanName) { long startTime = System.currentTimeMillis(); // 存储开始时间到上下文 return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) { long endTime = System.currentTimeMillis(); log.info("Bean {} 初始化耗时: {}ms", beanName, endTime - startTime); return bean; } ``` --- ### 使用注意事项 1. **执行顺序**:多个 BeanPostProcessor 可通过 `Ordered` 接口或 `@Order` 注解控制执行顺序[^2]。 2. **作用范围**:影响容器中所有 Bean,需通过条件判断(如 bean 类型)限制处理范围。 3. **注册方式**:需通过 `@Component` 或 XML 配置显式注册到 Spring 容器[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值