Spring AOP CGLIB代理的字段为空 [英] Spring AOP CGLIB proxy's field is null

查看:254
本文介绍了Spring AOP CGLIB代理的字段为空的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 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 字段是 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆