Spring代理底层原理:自定义BeanPostProcessor代理实现
自定义BeanPostProcessor代理与后续处理器链的问题解答
一、直接返回代理会破坏BPP链吗?
是的,直接返回代理对象确实会影响后续BPP的执行。后续处理器拿到的是动态生成的代理类而非原始Bean实例,代理类不会继承原始类的所有注解、字段元数据,那些依赖原始类信息(比如扫描特定注解)的后续BPP自然无法正常工作。
二、避免破坏BPP链的实用技巧
- 延迟代理创建时机:让自定义BPP实现
Ordered接口,重写getOrder()方法返回Ordered.LOWEST_PRECEDENCE,将其放到处理器链的最后执行。这样前面所有BPP都能先处理原始Bean,再生成代理就不会干扰前置逻辑。 - 让代理保留原始类信息:如果用Spring的
ProxyFactory创建代理,调用proxyFactory.copyProxyTargetClass(true)生成CGLIB代理(而非JDK动态代理),代理类会继承原始类结构,部分元数据能被后续BPP读取。若需读取注解,可使用Spring的AnnotationUtils.findAnnotation()工具类,它能自动穿透代理读取原始类的注解。 - 让代理支持原始Bean访问:确保生成的代理实现
Advised接口(Spring的ProxyFactory默认会实现),后续BPP可通过((Advised) proxy).getTargetSource().getTarget()获取原始Bean实例,从而访问完整的类元数据。不过这需要后续处理器兼容这种方式,Spring自身的处理器大多支持。
三、Spring自身处理多注解代理的方式
Spring内部处理@Transactional、@Async这类代理需求时,不会让每个注解对应独立的BPP,而是通过统一的代理创建逻辑(核心是AbstractAutoProxyCreator及其子类)来处理:
- 一次性生成复合代理:所有需要对Bean进行的增强逻辑(事务、异步等)会被收集到同一个代理中,不会多次替换Bean实例,避免了元数据丢失的问题。
- 保留原始Bean的访问通道:Spring生成的代理都实现了
Advised接口,任何需要获取原始Bean的逻辑都能通过该接口拿到目标对象,读取原始类的元数据。 - 严格的处理器排序:
AbstractAutoProxyCreator默认的执行顺序是Ordered.LOWEST_PRECEDENCE - 1,比绝大多数自定义BPP靠后,确保所有前置处理器都处理完原始Bean后,再生成最终的代理对象。
内容的提问来源于stack exchange,提问作者Flo Pec
相关产品推荐
相关产品推荐

