final类又没实现接口应该用哪一种代理, jdk动态代理还是cglib代理

Posted 洪宏鸿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了final类又没实现接口应该用哪一种代理, jdk动态代理还是cglib代理相关的知识,希望对你有一定的参考价值。

jdk动态代理还是cglib代理🧙

滚滚长江东逝水,浪花淘尽英雄。——唐代杨炯《临江仙》

jdk动态代理和cglib代理的示例

以下是一个使用JDK动态代理和CGLIB代理的示例。我们首先创建一个接口和实现类,然后分别使用JDK动态代理和CGLIB代理来创建代理对象。

  1. 接口:UserService.java
public interface UserService 
    void addUser(String name);


  1. 实现类:UserServiceImpl.java
public class UserServiceImpl implements UserService 
    @Override
    public void addUser(String name) 
        System.out.println("Adding user: " + name);
    


  1. JDK动态代理:JdkProxyHandler.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxyHandler implements InvocationHandler 
    private Object target;

    public JdkProxyHandler(Object target) 
        this.target = target;
    

    @SuppressWarnings("unchecked")
    public <T> T getProxyInstance() 
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this);
    

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
        System.out.println("JDK Proxy - Before method execution");
        Object result = method.invoke(target, args);
        System.out.println("JDK Proxy - After method execution");
        return result;
    


  1. CGLIB代理:CglibProxyHandler.java
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxyHandler implements MethodInterceptor 
    private Object target;

    public CglibProxyHandler(Object target) 
        this.target = target;
    

    @SuppressWarnings("unchecked")
    public <T> T getProxyInstance() 
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return (T) enhancer.create();
    

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable 
        System.out.println("CGLIB Proxy - Before method execution");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("CGLIB Proxy - After method execution");
        return result;
    


  1. 测试类:ProxyTest.java
public class ProxyTest 
    public static void main(String[] args) 
        UserService userService = new UserServiceImpl();

        // 使用JDK动态代理
        JdkProxyHandler jdkProxyHandler = new JdkProxyHandler(userService);
        UserService jdkProxy = jdkProxyHandler.getProxyInstance();
        jdkProxy.addUser("John");

        System.out.println("------------------------------------");

        // 使用CGLIB代理
        CglibProxyHandler cglibProxyHandler = new CglibProxyHandler(userService);
        UserService cglibProxy = cglibProxyHandler.getProxyInstance();
        cglibProxy.addUser("Jane");
    


运行 ProxyTest.java,你将看到以下输出:

JDK Proxy - Before method execution
Adding user: John
JDK Proxy - After method execution
------------------------------------
CGLIB Proxy - Before method execution
Adding user: Jane
CGLIB Proxy - After method execution

JDK动态代理和CGLIB代理都是AOP(面向切面编程)中的实现技术,它们可以在不修改目标类代码的情况下,为目标类添加一些额外的功能。

JDK动态代理原理

JDK动态代理是基于Java反射机制实现的。它主要使用了java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。

JDK动态代理的核心思想是:为目标类创建一个代理对象,这个代理对象实现了目标类的接口。当代理对象的方法被调用时,实际上是调用了InvocationHandlerinvoke方法。在invoke方法中,我们可以在调用目标类方法之前和之后执行一些自定义的逻辑。

要使用JDK动态代理,需要满足以下条件:

  • 目标类必须实现一个或多个接口。
  • 为目标类编写一个InvocationHandler实现类。

JDK动态代理的主要局限在于它只能代理实现了接口的类。如果一个类没有实现接口,就无法使用JDK动态代理。

CGLIB代理

CGLIB(Code Generation Library)是一个第三方代码生成库,它可以在运行时为目标类生成一个子类。CGLIB代理的核心思想是:为目标类创建一个子类,并覆盖目标类的方法。当代理类的方法被调用时,实际上是调用了MethodInterceptorintercept方法。在intercept方法中,我们可以在调用父类(即目标类)方法之前和之后执行一些自定义的逻辑。

要使用CGLIB代理,需要满足以下条件:

  • 目标类不能是final的,因为CGLIB需要生成目标类的子类。
  • 为目标类编写一个MethodInterceptor实现类。

CGLIB代理的优势在于它不要求目标类实现接口,但是由于它是通过创建子类来实现代理的,所以目标类不能是final的。

JDK动态代理基于Java反射机制,要求目标类实现接口。它创建的代理对象实现了目标类的接口,并通过InvocationHandler来实现方法拦截。


CGLIB代理基于代码生成技术,不要求目标类实现接口。它创建的代理对象是目标类的子类,并通过MethodInterceptor来实现方法拦截。

两者都可以实现在不修改目标类代码的情况下,为目标类添加额外功能。选择哪种代理方式取决于目标类是否实现了接口以及其他特殊需求。

final类又没实现接口应该用哪一种代理, jdk动态代理还是cglib代理

如果目标类是final类且没有实现接口,那么JDK动态代理和CGLIB代理都无法直接对其进行代理。JDK动态代理要求目标类实现一个或多个接口,而CGLIB代理需要生成目标类的子类,对于final类是无法创建子类的。

在这种情况下,你可以考虑以下解决方案:

  1. 修改目标类,去除final修饰符,或为其实现一个接口。然后,你可以选择使用JDK动态代理或CGLIB代理。

  2. 如果不能修改目标类,你可以尝试使用装饰器模式。创建一个新类,实现与目标类相同的接口(或扩展自目标类,如果目标类不是final的),并在新类中包装目标类。然后,在新类中实现代理逻辑。这种方式虽然不能直接代理目标类,但仍然可以在不修改目标类的情况下,为其添加额外的功能。

请注意,装饰器模式并非代理模式,但在某些情况下,它可以作为一种替代方案来实现类似的功能。

JDK动态代理与CGLIB动态代理

jdk动态代理的类必须是接口的实现类;1.8之后性能已超过cglib,按需选择jdk/cglib即可

cglib动态代理的类必须不被final关键字修饰;底层会继承要代理的类,覆盖方法来实现功能

springAOP默认使用jdk动态代理,若要被代理的类没有实现接口,则强制使用cglib

 

以上是关于final类又没实现接口应该用哪一种代理, jdk动态代理还是cglib代理的主要内容,如果未能解决你的问题,请参考以下文章

JDK动态代理与CGLIB动态代理

JDK动态代理与CGLIB动态代理

java动态代理(JDK和cglib)

jdk动态代理和cglib动态代理的区别

AOP的实现方式有哪几种?

AOP的实现方式有哪几种?