Spring AOP CGLIB代理的字段为空 [英] Spring AOP CGLIB proxy's field is null
问题描述
使用 vlcj 组件,自定义组件由于AOP代理对象为空而显示。
Using the vlcj component, the custom component appears as a result of the AOP proxy object null.
public class MediaList {
private libvlc_media_list_t mediaListInstance;
public MediaList(LibVlc libvlc, libvlc_instance_t instance, libvlc_media_list_t mediaListInstance) {
this.libvlc = libvlc;
this.instance = instance;
createInstance(mediaListInstance);
}
private void createInstance(libvlc_media_list_t mediaListInstance) {
logger.debug("createInstance()");
if(mediaListInstance == null) {
mediaListInstance = libvlc.libvlc_media_list_new(instance);
}
else {
libvlc.libvlc_media_list_retain(mediaListInstance);
}
this.mediaListInstance = mediaListInstance; // <- assignment
logger.debug("mediaListInstance={}", mediaListInstance);
mediaListEventManager = libvlc.libvlc_media_list_event_manager(mediaListInstance);
logger.debug("mediaListEventManager={}", mediaListEventManager);
registerEventListener();
}
public final libvlc_media_list_t mediaListInstance() {
return mediaListInstance; // <- proxy object return null, if use aop
}
}
< h1>自定义MediaList类
Custom MediaList Class
public class TestMediaList extends MediaList {
public TestMediaList(LibVlc libvlc, libvlc_instance_t instance) {
super(libvlc, instance);
}
public void xTest(String test){
System.out.println(test);
}
}
Spring配置类
Spring Configuration Class
@Configuration
public class PlayerBeanConfig {
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Resource
public TestMediaList testMediaList(LibVlc libvlc, libvlc_instance_t instance) {
return new TestMediaList(libvlc, instance);
}
}
AOP配置类
AOP Configuration Class
@Aspect
public class MediaListAspect {
@Pointcut("execution(* TestMediaList.xTest(..))")
private void anyMethod() {
}
@Around("anyMethod()")
public Object lockAndUnlock(ProceedingJoinPoint joinPoint) throws Throwable {
Object object = joinPoint.proceed();
return object;
}
}
测试代码
Test Code
public static void main(String[] args) {
boolean b = new NativeDiscovery().discover();
if (b) {
springContext = new AnnotationConfigApplicationContext(PlayerBeanConfig.class);
String[] kkk = new String[]{};
TestMediaList list = springContext.
getBean(TestMediaList.class, LibVlc.INSTANCE, LibVlc.INSTANCE.libvlc_new(kkk.length, kkk));
System.out.println(list.mediaListInstance()); // <- proxy object return null
} else {
logger.error("Cannot find vlc lib, exit application");
}
}
我尝试单步跟踪,当TestMediaList构建时完成了。方法的MediaListInstance()返回正常值,但是当spring返回到代理对象时,返回null。同时,如果您不使用AOP,我也会尝试正确返回值。
因此,我确定了AOP动态代理中的基本问题,但我不知道为什么,之前没有遇到过这样的情况。
I try to single step tracking, when TestMediaList the build is complete. MediaListInstance () of the method to return to normal values, but when the spring returns to the proxy object, null is returned. At the same time, I also try to return the value correctly if you don't use AOP. Therefore, I determine the basic problem in AOP dynamic proxy, but I don't know why, did not previously encountered such a situation.
包中的所有类: vod.demo
public class TargetClass {
private String returnValue;
public TargetClass() {
this.returnValue = "Hello World";
}
public final String test() {
System.out.println("TargetClass.test();");
return returnValue;
}
}
Aspect Class
Aspect Class
@Aspect
public class AspectClass {
@Pointcut("execution(* vod.demo.TargetClass.*(..))")
private void targetMethod() {
}
@Around("targetMethod()")
public Object aroundTarget(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("AspectClass.aroundTarget();");
return joinPoint.proceed();
}
}
Spring Config Class
Spring Config Class
@Configuration
@EnableAspectJAutoProxy
@Import(AspectClass.class)
public class SpringConfig {
@Bean
public TargetClass target() {
return new TargetClass();
}
}
客户等级
Client Class
public class Client {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
TargetClass target = context.getBean(TargetClass.class);
System.out.println("Client invoke:" + target.test()); // <- output null
}
}
推荐答案
这是潜在意外行为的组合。首先,Spring使用CGLIB为AOP代理您的bean。 CGLIB代理是类的动态子类型的实例,它将所有方法调用委托给类的实际实例。但是,即使代理是子类型,也不会初始化其字段(即,不调用 TargetClass
超级构造函数)。可以在此处找到更长的解释。
This is a combination of potentially unexpected behaviors. First, Spring uses CGLIB to proxy your beans for AOP. CGLIB proxies are instances of a dynamic subtype of your class that delegate all method calls to a real instance of your class. However, even though the proxy is of a subtype, its fields are not initialized (ie. your TargetClass
super constructor is not invoked). A lengthier explanation can be found here.
此外,您的方法
public final libvlc_media_list_t mediaListInstance() {
return mediaListInstance; // <- proxy object return null, if use aop
}
或
public final String test() {
System.out.println("TargetClass.test();");
return returnValue;
}
final
。因此CGLIB不能覆盖它们以委托给真实实例。这将在Spring日志中暗示。例如,你会看到
are final
. CGLIB therefore cannot override them to delegate to the real instance. This would be hinted at in Spring logs. For example, you would see
22:35:31.773 [main] INFO o.s.aop.framework.CglibAopProxy - Unable to proxy method [public final java.lang.String com.example.root.TargetClass.test()] because it is final: All calls to this method via a proxy will NOT be routed to the target instance.
将上述所有内容放在一起,您将得到一个代理实例,其中字段为 null
以及代理无法委托实例的方法。所以你的代码实际上会调用
Put all of the above together and you get a proxy instance where the field is null
and where the proxy cannot delegate to the real instance's method. So your code will actually invoke
public final String test() {
System.out.println("TargetClass.test();");
return returnValue;
}
对于 returnValue $ c的实例$ c>字段是
null
。
如果可以,更改您的方法,删除最终
修饰符。如果你不能,你将不得不重新考虑你的设计。
If you can, change your method, remove the final
modifier. If you can't, you'll have to rethink your design.
这篇关于Spring AOP CGLIB代理的字段为空的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!