JDK的动态代理和Cglib的动态代理比较

1、讲动态代理之前,我们先了解下什么叫代理,从字面意思我们也能看出来意思就是代替某人做事情,看下面的例子:

package eureka.server.proxy;

public interface UserService {
    void printName();
}

这是一个UserService接口类;

package eureka.server.proxy;

public class UserServiceImpl implements UserService {
    @Override
    public void printName() {
        System.out.println("I am zhangsan");
    }
}

这是一个UserService接口实现类UserServiceImpl,加入说我们想要在doString方法前面加上打印日志的功能怎么做呢?看下面的代码实现:

package eureka.server.proxy;

public class UserServiceProxy {

    private UserService userService;

    public UserServiceProxy(UserService userService){
        this.userService = userService;
    }
    //代理类的方法
    public void proxyMethod() {
        before();
        userService.doString();
        after();
    }

    private void before(){
        System.out.println("method exe before");
    }

    private void after(){
        System.out.println("method exe after");
    }

    public static void main(String[] args) {
        UserServiceProxy userServiceProxy = new UserServiceProxy(new UserServiceImpl());
        userServiceProxy.proxyMethod();
    }
}

上面的代码运用的就是设计模式中的代理模式,不过运用的是静态代理模式,可能有的读者会问了,假如UserService接口新增了一个方法也需要打印日志,按照现在的方式只能在UserServiceProxy 类中新增一个proxyMethod1然后加上打印日志的代码,这种方式虽然可以实现,但是可拓展性不是很好,因为每新增一个方法就需要修改代理类的代码,而且还要在多个方法中调用打印日志的代码,那么有没有什么好办法解决这个问题呢,当然是有的,看下面的代码:

package eureka.server.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * jdk的动态代理
 */
public class JdkUserServiceProxy implements InvocationHandler{

    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
        beforeLog();
        Object obj = method.invoke(this.target, params);
        afterLog();
        return obj;
    }


    private void beforeLog(){
        System.out.println("method exe before");
    }

    private void afterLog(){
        System.out.println("method exe after");
    }

    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        JdkUserServiceProxy jdkProxy = new JdkUserServiceProxy(userService);
        //第一个参数是代理类的类加载器,第二个参数是被代理类实现的接口,第三个是实现InvocationHandler接口的代理类
        UserService userProxy =(UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), jdkProxy);
        userProxy.printName();
    }
}

这个就是JDK的动态代理技术,可以在运行时动态的代理的被代理的类,完美的解决了上面的硬编码和可拓展行问题,但是还是有个缺陷,就是被代理的类都必须实现一个接口,如果不实现接口,就不能用JDK的动态代理技术,那是不是不实现接口就不能使用动态代理技术了呢,当然不是,我们还有Cglib动态代理技术,代码如下:

package eureka.server.proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * Cglib动态代理
 */
public class CglibUserServiceProxy implements MethodInterceptor{


    /**
     * 参数:Object为由CGLib动态生成的代理类实例,Method为上文中实体类所调用的被代理的方法引用,Object[]为参数值列表,
     * MethodProxy为生成的代理类对方法的代理引用。返回:从代理实例的方法调用返回的值。
     * 其中,proxy.invokeSuper(obj,arg):
     * 调用代理类实例上的proxy方法的父类方法(即实体类ConcreteClassNoInterface中对应的方法)
     * @param proxy
     * @param method
     * @param params
     * @param methodProxy
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
        beforeLog();
        Object obj = methodProxy.invokeSuper(proxy, params);
        afterLog();
        return obj;
    }

    public  Object newProxy(){
        Enhancer enhancer = new Enhancer();
        //设置代理类class为父类
        enhancer.setSuperclass(UserServiceImpl.class);
        //设置拦截器
        enhancer.setCallback(this);
        return enhancer.create();
    }

    private void beforeLog(){
        System.out.println("method exe before");
    }

    private void afterLog(){
        System.out.println("method exe after");
    }

    public static void main(String[] args) {
        CglibUserServiceProxy cglibProcy = new CglibUserServiceProxy();
        UserService userProxy =(UserService)cglibProcy.newProxy();
        userProxy.printName();
    }
}

那么Cglib是不是就没有缺陷呢?当然不是,由于Cglib原理是生成目标类的一个子类并且覆盖目标类的方法,所以目标类和目标类的方法都不能修饰成final的,这点要注意,但是Cglib的效率比JDK的动态代理高;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值