【问题标题】:What does CGLib's intercept actually return?CGLib 的拦截实际上返回了什么?
【发布时间】:2017-10-20 19:22:00
【问题描述】:

我正在尝试使用 CGLib 创建自己的延迟加载实现,但我遇到了一些我无法解释的奇怪行为。

这就是我正在做的事情。
正在创建代理实例,如下所示:

public static <T> T newInstance(Long sourceId, SourceMapper<T> sourceMapper) {

    Class<?> proxyTargetType = sourceMapper.getType();
    //mapper will use provided sourceId in order to load real object from the DB
    Function<Long, T> mapper = sourceMapper.getMapper();

    return (T) Enhancer.create(proxyTargetType,
                               new DynamicProxy<>(sourceId, mapper));
}

下面是上面代码的用法:

Order order = new Order();
     try {
          //heavy object is being proxied
          long customerTariffId = rs.getLong("customer_tariff_id");
          order.setCustomerTariff(DynamicProxy
                          .newInstance(customerTariffId, CUSTOMER_TARIFF_MAPPER)); 
        }

只有当它的任何方法被调用时才应该加载重对象:

public Object intercept(Object obj, Method method, Object[] args,
                        MethodProxy methodProxy) throws Throwable {
    T source = this.getSource(); // loads real object using sourceId and mapper
    if(source == null) return null;
    return method.invoke(source, args);
}

如果this.getSource() 加载某个对象,它会完美运行。

但是如果我们假设order.getCustomerTariff() 应该返回nullthis.getSource() 将返回null),我会得到什么

LOG.debug("{}", order.getCustomerTariff());          //null    (1)
LOG.debug("{}", order.getCustomerTariff() != null);  //true    (2)

我假设,出于某种原因,toString() 在第 (2) 行被调用,所以我得到的是 String null 而不是文字 null。这就是为什么它不等于比较子句中的文字 null
您如何看待,有没有办法在第 (2) 行返回常规 null 并接收正确的值 false检查期间?

编辑
被代理的类看起来像这样:

public class CustomerTariff extends DomainEntity {

    private Customer customer;
    //some other similar fields
    private Tariff tariff;

    public CustomerTariff() {
    }

    public CustomerTariff(Customer customer
                          Tariff tariff) {
        this.customer = customer;
        this.tariff = tariff;
    }

    public CustomerTariff(Long id, Customer customer,
                          Tariff tariff) {
        super(id);
        this.customer = customer;
        this.tariff = tariff;
    } 
    //getters and setters

    @Override
    public String toString() {
    return "CustomerTariff{" +
            "customer=" + customer +
            ", tariff=" + tariff +
            "} " + super.toString();
    }
}

public abstract class DomainEntity {

    private Long id;

    public DomainEntity() {}

    public DomainEntity(Long id) {
       this.id = id;
    }

    @Override
    public String toString() {
       return "DomainEntity{" +
               "id=" + id +
                '}';
       }
    }

【问题讨论】:

  • 你所做的似乎是正确的。您是否检查了返回值的类型?您是否在拦截器中设置了断点来检查返回的正确值?
  • @RafaelWinterhalter 从调试会话中我了解到,Enhancer.create(...) 生成以下值obj = {CustomerTariff$$EnhancerByCGLIB$$d66ba677} "null",该值被设置为customerTariff 字段。此值与第 (2) 行的null 进行比较。我不明白引用的 null 是什么意思,但问题是 "null" != null 产生 true
  • 我假设有一些构造函数定义了一个值,该值成为toString 表示的一部分。我假设您调用了构造函数,但不初始化正在读取的某些字段。你能提供被代理的类吗?
  • @RafaelWinterhalter 是的,我可以提供课程。我已经编辑了我的问题

标签: java proxy tostring cglib


【解决方案1】:

我假设您正在从您的拦截器中拦截您的 toString 方法,并且您没有得到您期望的拦截链。指定一个方法过滤器,只命中你想要拦截的方法,你应该得到预期的结果。

【讨论】:

    猜你喜欢
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-21
    相关资源
    最近更新 更多