添加自定义BeanPostProcessor后按实现类获取Bean抛出No qualifying bean异常
异常产生原因
你当前使用的是JDK动态代理实现代理逻辑,JDK动态代理的核心特性是生成的代理对象仅实现目标类的所有接口,与目标实现类本身无继承关系。
你在CustomBeanProcessor的postProcessAfterInitialization方法中,将Spring原生生成的OrderImpl类型Bean直接替换为了JDK动态代理对象,此时Spring容器中存储的对应Bean实际类型为代理类,仅匹配Order接口类型,无法匹配OrderImpl实现类类型,因此调用context.getBean(OrderImpl.class)时会抛出NoSuchBeanDefinitionException异常。
解决方案
方案1(推荐):遵循面向接口编程规范
始终通过Order接口类型获取、注入Bean,无需修改现有代理逻辑,符合接口与实现分离的设计原则。
方案2:替换为CGLIB动态代理
如果必须通过OrderImpl实现类类型操作Bean,可以将JDK动态代理替换为CGLIB动态代理:
CGLIB代理通过继承目标实现类的方式生成代理对象,生成的代理类是OrderImpl的子类,可以匹配OrderImpl类型的查找。
你可以直接使用Spring内置的ProxyFactory简化改造,修改CustomBeanProcessor的postProcessAfterInitialization方法逻辑如下:
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { // 仅对标注了@Time注解的类/方法生成代理,可按需调整过滤逻辑 List<Method> annotatedMethods = getAnnotatedMethods(bean.getClass().getMethods(), Time.class); if (annotatedMethods.isEmpty()) { return bean; } ProxyFactory proxyFactory = new ProxyFactory(bean); // 开启CGLIB代理,强制代理目标类而非接口 proxyFactory.setProxyTargetClass(true); proxyFactory.addAdvice((MethodInterceptor) invocation -> { long timeBeforeInvoking = System.nanoTime(); Object result = invocation.proceed(); if (annotatedMethods.stream().anyMatch(m -> m.getName().equals(invocation.getMethod().getName()))) { System.out.println(System.nanoTime() - timeBeforeInvoking); } return result; }); return proxyFactory.getProxy(bean.getClass().getClassLoader()); }
注意:CGLIB无法代理
final修饰的类和final修饰的方法,使用前需确认目标实现类符合要求。
内容的提问来源于stack exchange,提问作者DozezQuest
相关产品推荐
相关产品推荐

