6

我现在正在读一本用韩语写的春季书,我的英语很糟糕。请理解。

在书中,它说Spring的AOP如果使用Interface,则使用动态代理启动类,如果不使用Interface,则使用CGLIB启动类。我不太清楚这是什么意思。你能帮我理解它的深层含义吗?

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

4

2 回答 2

14

代理本质上是客户端和对象之间的中介,因此它实现了对象的非最终方法。代理接口相对简单,因为接口只是需要实现的方法列表,便于拦截方法调用。

Java 中的Proxy类是一个实现在运行时指定的接口列表的类。然后,代理有一个与之关联的InvocationHandler,它将代理上的方法调用委托给被代理的对象。它充当间接级别,这样方法不会在对象本身上调用,而是在其代理上调用。只有InvocationHandler一个需要实现的方法:

public Object invoke(Object proxy, Method method, Object[] args)

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

与接口相比,动态代理类并不那么简单。虽然 JavaProxy只是一个接口或一组接口的运行时实现,但对象不必实现接口。因此,代理类需要生成字节码,这就是 cglib 等库发挥作用的地方。cglib 提供对代理类的支持,因为它可以动态生成字节码(即类文件),这意味着它可以在运行时以 JavaProxy可以在运行时实现接口的方式扩展类。

代理有很多用途。一种这样的用途是延迟加载。延迟加载允许仅在需要时加载对象图中的对象。我们可以在需要访问它们时即时加载它们,而不是立即将它们全部加载到内存中,这可能是昂贵且资源密集的,例如迭代对象集合。我们不是加载整个集合,而是一次加载一个小集合。这可以通过代理来实现。代理代表延迟加载的对象。对象本身(可能是从数据库加载的)在其代理上调用方法之前不会加载。代理拦截方法调用,然后将对象加载到内存中并将方法调用委托给它。

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

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 中就是这种情况。

于 2012-04-20T03:06:44.300 回答
2

Java 动态代理是 Java 语言的一个反射元素,它允许用户在运行时创建接口的代理。作为反射包的一部分,它是 Java 的一部分,并且随 JRE/JDK 一起提供。

CGLIB是一个代码生成库,它能够在运行时扩展 Java 类。因此,Spring 利用此功能为其 AOP 库代理非接口。

于 2012-04-20T03:03:08.550 回答