Spring AOP 代理对象

6

我现在正在阅读一本韩语编写的Spring书籍,但是我的英语很差。请您理解。

在这本书中,它说如果使用接口,Spring的AOP将使用动态代理来初始化类,如果不使用接口,则使用CGLIB来初始化类。我不太明白这是什么意思。你能帮我理解其深层含义吗?

我不知道这个问题是否愚蠢。但我只是好奇。谢谢。

2个回答

15
一个代理是客户端和对象之间的中介者,它实现了该对象的非最终方法。代理一个接口相对简单,因为接口只是需要被实现的方法列表,便于拦截方法调用。
在Java中,Proxy类是一个在运行时实现一系列接口的类。然后,代理与InvocationHandler相关联,将在代理上进行的方法调用委托给被代理的对象。它充当了一层间接性,使得方法不会直接在对象本身上调用,而是在其代理上调用。 InvocationHandler仅有一个需要实现的方法:
public Object invoke(Object proxy, Method method, Object[] args)

与此同时,调用该方法的客户端无法区分代理和其底层对象表示之间的区别,也不应该关心。

为类创建动态代理,而不是接口,不太简单。虽然 Java 的 Proxy 只是一个实现接口或一组接口的运行时实现,但对象并不一定要实现接口。因此,代理类需要字节码生成,这就是像 cglib 这样的库发挥作用的地方。cglib 提供了对代理类的支持,因为它可以动态生成字节码(即类文件),这意味着它可以在运行时以 Java 的 Proxy 可以在运行时实现接口的方式扩展类。

代理有许多用途。其中一个用途是延迟加载。延迟加载允许对象图中的对象只在需要时加载。我们可以在需要访问它们时按需加载它们,而不是立即将它们全部加载到内存中,这可能会很昂贵且消耗资源。这可以通过使用代理来实现。代理表示惰性加载的对象。该对象本身可能是从数据库加载的,在其代理上调用方法之前不会加载该对象。拦截方法调用的代理将加载对象到内存中并将方法调用委托给它。

这是延迟加载实现的示例:

public abstract class LazilyLoadedObject implements InvocationHandler {

    private Object target;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (target == null) {
            target = loadObject();
        }
        return method.invoke(target, args);
    }

    /**
     * Loads the proxied object. This might be an expensive operation
     * or loading lots of objects could consume a lot of memory, so
     * we only load the object when it's needed.
     */
     protected abstract Object loadObject();

}
以上的InvocationHandler将被传递给代理对象,以便代理对象上调用的方法将由InvocationHandler处理。该处理程序会检查对象是否已加载。如果没有加载,它将调用loadObject(),这可能是一些检索对象的数据库查询。
代理非常强大,因为它们允许拦截方法调用。这在AOP中是如此。

我认为这部分代码(return method.invoke(target, args);)会造成无限循环。 - Patrick Jeon
1
不行,因为InvocationHandler正在调用target上的方法,这是实际对象,而不是代理。如果我改为调用return method.invoke(proxy, args),那么就会出现无限循环。 - Tyler Treat
迄今为止我遇到的最好的代理解释。 - Ashish Shetkar

2
Java动态代理”是Java语言的反射元素,允许用户在运行时创建接口的代理。作为反射包的一部分,它是Java的一部分,并随JRE/JDK一起发布。
CGLIB”是一个代码生成库,具有在运行时扩展Java类的能力。因此,Spring利用这个功能为其AOP库代理非接口。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接