JDK动态代理和Cglib代理

JDK动态代理是通过Java反射机制来实现的,它要求目标对象必须实现一个接口,然后通过Proxy类的newProxyInstance()方法来创建代理对象。生成的代理对象也会实现这个接口,并且将所有方法的调用都转发给InvocationHandler处理器去处理。因为JDK动态代理是基于接口的,所以它只能代理实现了接口的类,无法代理没有实现接口的类。

Cglib代理则是通过继承目标对象来实现的,它不要求目标对象必须实现接口,而是在运行时动态生成一个目标对象的子类,然后通过子类来实现对目标对象的代理访问。生成的代理对象是目标对象的子类,并且重写了目标对象的所有方法,在重写的方法中加入了增强代码。因为Cglib代理是基于继承的,所以它可以代理没有实现接口的类。

JDK动态代理是Java提供的一种基于接口的代理方式,它的原理可以简单概括为以下几个步骤:

  1. 定义接口:首先定义一个接口,该接口中包含了目标对象的所有方法。

  2. 创建InvocationHandler对象:创建一个实现了InvocationHandler接口的代理处理器对象,该对象用于处理代理对象的方法调用。

  3. 创建代理对象:通过Proxy类的newProxyInstance()方法创建代理对象。该方法需要传入三个参数:ClassLoader对象、Class[]对象和InvocationHandler对象。其中,ClassLoader对象用于指定代理对象的类加载器,Class[]对象用于指定代理对象需要实现的接口,InvocationHandler对象用于指定代理对象的方法调用处理器。

  4. 调用代理对象方法:通过代理对象调用目标对象的方法时,代理对象会将方法调用转发给InvocationHandler对象处理。在InvocationHandler对象的invoke()方法中,可以对方法调用进行增强处理,然后再将处理后的方法调用结果返回给代理对象。

当我们通过JDK动态代理调用目标对象的方法时,代理对象会首先检查目标对象是否实现了至少一个接口。如果目标对象没有实现接口,那么JDK动态代理就无法生成代理对象。否则,JDK动态代理会使用Java反射机制在运行时动态生成一个代理类,该代理类实现了目标对象实现的所有接口,并继承了Proxy类。然后,JDK动态代理会创建一个InvocationHandler对象,并将其与代理类关联起来。当我们调用代理对象的任意方法时,代理对象会将方法调用转发给InvocationHandler对象处理。在InvocationHandler对象的invoke()方法中,可以对方法调用进行增强处理,例如记录日志、事务管理等。最后,InvocationHandler对象将处理后的方法调用结果返回给代理对象。

Cglib代理是通过继承目标对象来实现代理的,它的原理可以简单概括为以下几个步骤:

  1. 创建Enhancer对象:首先创建一个Enhancer对象,它是Cglib的核心类,用于生成代理对象。

  2. 设置父类和回调函数:通过 ​setSuperclass()​方法设置目标对象的父类,然后通过 ​setCallback()​方法设置回调函数,即MethodInterceptor对象。

  3. 创建代理对象:调用Enhancer对象的 ​create()​方法,生成代理对象。在生成代理对象的过程中,Cglib会动态创建目标对象的子类,并重写目标对象的所有非final方法,在重写的方法中加入了增强代码,以实现对目标对象的代理访问。

  4. 调用代理对象方法:通过代理对象来调用目标对象的方法时,Cglib会先判断是否是代理对象自己实现的方法,如果是,则直接调用代理对象自己的方法;如果不是,则调用父类(即目标对象)的方法。在调用父类方法之前和之后,Cglib会自动调用回调函数中的 ​intercept()​方法,以实现增强逻辑的执行。

 Cglib代理只能代理非final类的非final方法,因为final方法不能被重写。此外,Cglib代理相对于JDK动态代理而言,由于采用继承的方式实现代理,会生成目标对象的子类,因此在性能上相对较低。

假设我们有一个接口 ​UserService​,它有一个方法 ​getUserById(int id)​用来根据用户ID获取用户信息。现在我们想要对这个方法进行代理,记录每次调用的时间。可以通过如下代码实现:

public interface UserService {
    User getUserById(int id);
}

public class UserServiceImpl implements UserService {
    public User getUserById(int id) {
        // 根据id从数据库中获取用户信息
        return user;
    }
}

public class UserServiceProxy implements InvocationHandler {
    private Object target;

    public UserServiceProxy(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before method " + method.getName());
        long startTime = System.currentTimeMillis();
        Object result = method.invoke(target, args);
        long endTime = System.currentTimeMillis();
        System.out.println("after method " + method.getName() + ", elapsed time: " + (endTime - startTime) + "ms");
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        UserService proxy = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(),
                new Class[] { UserService.class }, new UserServiceProxy(userService));
        User user = proxy.getUserById(1);
    }
}

 在上面的代码中,我们创建了一个 ​UserServiceProxy​类,它实现了 ​InvocationHandler​接口,用来处理代理对象的方法调用。在 ​invoke()​方法中,我们先记录了方法调用前的时间,然后调用了目标对象的方法,最后记录了方法调用后的时间,并输出了方法调用的耗时。在 ​Main​类中,我们使用 ​Proxy.newProxyInstance()​方法来创建代理对象,然后通过代理对象来调用 ​getUserById()​方法。

假设我们有一个类 ​UserServiceImpl​,它有一个方法 ​getUserById(int id)​用来根据用户ID获取用户信息。现在我们想要对这个方法进行代理,记录每次调用的时间。可以通过如下代码实现:

public class UserServiceImpl {
    public User getUserById(int id) {
        // 根据id从数据库中获取用户信息
        return user;
    }
}

public class UserServiceInterceptor implements MethodInterceptor {
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("before method " + method.getName());
        long startTime = System.currentTimeMillis();
        Object result = proxy.invokeSuper(obj, args);
        long endTime = System.currentTimeMillis();
        System.out.println("after method " + method.getName() + ", elapsed time: " + (endTime - startTime) + "ms");
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserServiceImpl.class);
        enhancer.setCallback(new UserServiceInterceptor());
        UserServiceImpl userService = (UserServiceImpl) enhancer.create();
        User user = userService.getUserById(1);
    }
}

在上面的代码中,我们创建了一个 ​UserServiceInterceptor​类,它实现了 ​MethodInterceptor​接口,用来处理代理对象的方法调用。在 ​intercept()​方法中,我们先记录了方法调用前的时间,然后调用了目标对象的方法,最后记录了方法调用后的时间,并输出了方法调用的耗时。在 ​Main​类中,我们使用 ​Enhancer​类来创建代理对象,然后通过代理对象来调用 ​getUserById()​方法。需要注意的是,Cglib代理要求目标类不能是final类,否则会抛出异常。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值