实现Java基于类的代理方式 - CGLIB动态代理(动态代理篇 三)

CGLIB(Code Generation Library)是一个基于类的动态代理库,它可以在运行时生成字节码来创建代理类。相比于JDK动态代理,CGLIB动态代理不需要接口,可以代理任意类。 CGLIB动态代理的实现原理是通过继承目标类来创建代理类,并重写目标类的方法。在代理类中,通过调用MethodInterceptor接口的方法来拦截目标方法的调用,并执行自定义的逻辑。

1. maven工程引入依赖(或者普通工程引入jar包)

        
            cglib
            cglib-nodep
            3.3.0
        

2. 设计目标类,实现功能

//接口
public interface UserService {
    void addUser(String name);
    void deleteUser(String name);
}
//目标类和方法
public class UserServiceImpl implements UserService {
    @Override
    public void addUser(String username) {
        System.out.println("添加的用户为: " + username);
    }

    @Override
    public void deleteUser(String username) {
        System.out.println("删除的用户为: " + username);
    }
}

3. 创建一个MethodInterceptor的实现类,用于拦截目标方法的调用并添加额外的逻辑。

//拦截目标方法的类(也就是拦截器)
public class LoggingInterceptor implements MethodInterceptor {
    /**
     * 重写intercept方法来拦截目标方法的调用,
     * 当调用被代理对象的方法时,intercept方法会被调用,并传入相应的参数.
     * 
     * @param obj  被代理的对象
     * @param method 目标方法的反射对象
     * @param args 目标方法的参数数组
     * @param proxy MethodProxy对象,用于调用父类的方法
     * @return 目标方法的执行结果
     * @throws Throwable 异常(有代理就有反射,有反射就会出现异常的情况)
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("-----前记录日志----");
        // 在执行目标方法之前记录日志
        System.out.println("准备执行的方法为: " + method.getName());

        // 调用代理对象的父类方法,即执行目标方法
        Object result = proxy.invokeSuper(obj, args);

        System.out.println("执行完成: " + method.getName());
        // 在执行目标方法之后记录日志
        System.out.println("-----后记录日志----");
        // 返回目标方法的执行结果
        return result;
    }
}

4. 使用CGLIB动态代理来创建代理对象并调用目标方法

public class Main {
    public static void main(String[] args) {
        // 创建Enhancer对象(用于创建代理对象)
        Enhancer enhancer = new Enhancer();
        
        // 设置被增强类(被代理的类)
        enhancer.setSuperclass(UserServiceImpl.class);
        // 设置回调对象(回调对象负责拦截目标方法的调用并执行自定义逻辑)
        enhancer.setCallback(new LoggingInterceptor());
        
        // 创建真实代理对象
        UserService proxy = (UserService) enhancer.create();
        // 代理对象调用方法(调用方法时,会执行拦截器(回调对象)中的方法)
        proxy.addUser("小明");
        proxy.deleteUser("小米");
    }
}

5. 执行结果(达到增强的效果)

实现Java基于类的代理方式 - CGLIB动态代理(动态代理篇 三)_第1张图片

GGLIB动态代理相对于JDK动态代理的优势

1. 无需接口:JDK动态代理要求目标类实现接口,而CGLIB动态代理可以代理任意类,包括没有实现接口的类。这使得CGLIB更加灵活,可以代理更多类型的目标对象。

2. 更高的性能:由于CGLIB是通过生成目标类的子类来实现代理,而JDK动态代理是通过实现目标类的接口来实现代理,所以CGLIB在性能方面通常比JDK动态代理更高效。CGLIB代理类的方法调用是通过方法继承实现的,而JDK动态代理需要通过反射调用目标方法,因此CGLIB的方法调用更快。

3. 更强的功能:CGLIB可以代理目标类的所有方法,包括final方法、私有方法和静态方法等。而JDK动态代理只能代理接口的方法。这使得CGLIB在某些场景下更有优势,例如对于第三方类库或无法修改源代码的类的代理。

4. 简单易用:相比于JDK动态代理,CGLIB的使用更加简单。在使用CGLIB时,我们只需要创建一个Enhancer对象,设置被代理类和回调对象,就可以创建代理对象。而JDK动态代理需要实现InvocationHandler接口,并通过Proxy类的静态方法创建代理对象

上一篇:JDK动态代理

你可能感兴趣的:(Java学习,java,开发语言)