我有这样的服务:
@Service
public class SomeService {
private final ThreadLocal<SomeData> threadLocalData = new ThreadLocal<>();
@Transactional
public void someProcess() {
// некоторая логика
}
public final SomeData pull() {
SomeData data = threadLocalData.get();
threadLocalData.remove();
return data;
}
}
由于在服务中打开了事务(并且由于服务没有实现任何接口),服务被包装在 CGlib 代理中。因此,我在pull()
从其他服务调用该方法时遇到了问题,因为由于threadLocalData
代理中的字段为空而引发了 NullPointerException。
这是正常和预期的行为。但是,我对此很感兴趣:在编译 CGlib 时,最终方法究竟是如何处理的?因为这就是我想象从我的对象获得的代理的方式:
@Service
public class SomeService$$CGlibProxy extends SomeService {
SomeService someService;
@Override
public void someProcess() {
// создание транзакции
someService.someProcess();
// закрытие транзакции
}
???
}
也就是说,很明显,代理复制了父级的所有字段(虽然它们都是空的)。并且方法发生了什么也很清楚someProcess
(之前的一些逻辑,调用真正的方法,之后的一些逻辑)。
但是该方法会发生什么pull()
?是final的,但同时CGlib没有报错,而且这个方法是在proxy上调用的,也是访问threadLocalData
proxy本身的字段。
该方法是如何创建的,它pull()
在代理中是什么样的?
我没有立即猜测,原则上答案是表面上的。
由于代理继承自真实类,并且最终方法没有被覆盖,因此在这种情况下
pull()
调用父方法。但是由于在代理中所有继承的字段都是空的,所以方法调用会抛出异常。