【问题标题】:How force BeanPostProcessor proxy to look up on classes not interfaces?如何强制 BeanPostProcessor 代理查找类而不是接口?
【发布时间】:2021-12-01 10:23:35
【问题描述】:

我不确定问题是否正确,因为我还是这方面的新手。

我想使用BeanPostProcessor 完成以下场景:


  1. 过滤所有标有@Service 注解的bean。
  2. 过滤所有带有标记注释@Refreshable 的方法。
  3. 对这些方法的返回对象执行指定的方法。

以下是我的工作示例:

@Retention(RUNTIME)
public @interface Refreshable {
}
public interface VisitServiceI {

    @Refreshable
    VisitDtoOut addVisitToPatient(UUID idPatient, VisitDtoIn visitDtoIn);

}
public interface RefreshableDto {

    void copyId();

}

@Component
public class MethodBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof VisitServiceI) {
            ProxyFactory factory = new ProxyFactory(bean);
            factory.addInterface(VisitServiceI.class);
            factory.addAdvice((AfterReturningAdvice) (returnValue, method, args, target) -> {
                if (method.isAnnotationPresent(Refreshable.class)) {
                    var refreshableDto = (RefreshableDto) returnValue;
                    if (refreshableDto != null) {
                        refreshableDto.copyId();
                    }
                }
            });
            factory.setExposeProxy(true);
            return factory.getProxy();
        }
        return bean;
    }

}

这是否可以摆脱那些无用的接口,例如:VisitServiceI 当我给他标准类而不是它们的接口时,我想强制BeanPostProcessor 以某种方式工作。

【问题讨论】:

  • Howelse 你会强制实现一个方法而不是一个接口吗?我想说这里没用的是注解而不是接口。
  • 为什么觉得注解没用?我只想代理特定的方法。通过注解,我可以明确说明需要包含哪些方法。
  • 为给定的类创建一个代理(就像 spring 一样)。此外,这看起来很容易通过使用BeanPostProcessor 的方面实现。所以不确定这比常规方面增加了什么。
  • 是的,我知道这也可以通过 Aspect 实现,但出于教育目的,我正在尝试使用 BeanPostProcessor 来实现。
  • 恕我直言,以错误的方式解决问题没有任何教育意义。在ProxyFactory 上将proxyTargetClass 设置为true 以获取类代理,或者如果您现在只是接口,只需删除addInterface,因为代理工厂已经检测到实现的接口。您的问题是您的instanceof 服务,您需要检查类上的@Service 注释(因为这是您不检查接口的要求)。

标签: java spring proxy


【解决方案1】:

抛弃BeanPostProcessor,只写一个方面,让Spring来做繁重的工作。

@Aspect
@Component
public RefreshableAspect {

 @AfterReturn("within(@Service) && @annotation(@Refreshable)", returning="retVal")
public void refresh(Object retVal) {
  if (retVal instanceof RefreshableDto) {
    ((RefreshableDto) retVal).copyId();
  }
} 

}

这样的东西可以在没有接口和额外的BeanPostProcessor 的情况下完成你所需要的。

但是如果你真的想要复杂的路线做这样的事情

@Component
public class MethodBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (AnnotationUtils.findAnnotation(bean.getClass(), Service.class) != null) {
            ProxyFactory factory = new ProxyFactory(bean);
            factory.setProxyTargetClass(true);
            factory.addAdvice((AfterReturningAdvice) (returnValue, method, args, target) -> {
                if (method.isAnnotationPresent(Refreshable.class)) {
                    var refreshableDto = (RefreshableDto) returnValue;
                    if (refreshableDto != null) {
                        refreshableDto.copyId();
                    }
                }
            });
            factory.setExposeProxy(true);
            return factory.getProxy();
        }
        return bean;
    }
}

【讨论】:

  • 谢谢,但你忘了setProxyTargetClass(true);
  • 如果您只使用接口(因为 ProxyFactory 已经检测到这些接口),则不需要。
  • 没错,但我不想要那些界面,但无论如何,非常感谢!
  • 你已经有了接口,所以不知道为什么你不想要基于接口的代理?
  • 因为在我看来这些接口不是必需的。我想摆脱他们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-27
  • 1970-01-01
  • 1970-01-01
  • 2010-09-18
  • 2012-01-05
  • 2016-12-25
  • 1970-01-01
相关资源
最近更新 更多