代理模式中静态代理、jdk动态代理、cglib动态代理有什么不同?

1.静态代理

首先,写一个要实现的目标的接口:


/**
 * @author wayleung
 * @description
 * @date 2020-08-12 09:42:20
 */
public interface TargetInterface {
    String sayHello(String name);
}

然后再写一个目标实现类,也就是需要被代理(增强)的类:

/**
 * @author wayleung
 * @description
 * @date 2020-08-12 09:43:39
 */
public class Target implements TargetInterface {
    @Override
    public String sayHello(String name) {
        String result = "Hello," + name;
        System.out.println(result);
        return result;
    }
}

然后就是代理类的编写,此处的核心是把被代理类进行注入并调用

/**
 * @author wayleung
 * @description
 * @date 2020-08-12 09:44:47
 */
public class Proxy implements TargetInterface {

    private TargetInterface targetInterface;

    public Proxy(TargetInterface targetInterface) {
        this.targetInterface = targetInterface;
    }

    @Override
    public String sayHello(String name) {
        System.out.println("代理前做点东西");
        String result = targetInterface.sayHello(name);
        System.out.println("代理后做点东西");
        return result;
    }
}

最后就是使用了:

/**
 * @author wayleung
 * @description
 * @date 2020-08-12 09:41:39
 */
public class StaticProxyDemo {
    public static void main(String[] args) {
        TargetInterface target =  new Target();
        Proxy proxy = new Proxy(target);
        proxy.sayHello("way");
    }
}

 

静态代理容易实现,容易理解,但是缺点就是每需要增强一个类就需要一个代理类,修改增加方法,代理类也需要改变,耦合严重

 

2.Jdk动态代理

静态代理是编译时便进行了代理,而动态代理则是通过动态修改字节码,并载入JVM来实现

Proxy和Target、TargetInterface可以共用上面的代码,我就不重复了

Jdk动态代理主要就是用了Java 反射包下的Proxy.newInstance这个方法,而这个方法里的参数又需要一个InvocationHandler的实现类,所以首先实现InvocationHandler接口:

/**
 * @author wayleung
 * @description
 * @date 2020-08-12 10:10:27
 */
public class MyInvocationHandler implements InvocationHandler {

    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理前做点东西");
        Object result = method.invoke(target, args);
        System.out.println("代理后做点东西");
        return result;
    }
}

然后就是使用了:

/**
 * @author wayleung
 * @description
 * @date 2020-08-12 09:53:07
 */
public class DynamicProxyDemo {
    public static void main(String[] args) {
        TargetInterface target = new Target();
        MyInvocationHandler dynamicProxyInvocationHandler = new MyInvocationHandler(target);
        TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), dynamicProxyInvocationHandler);
        System.out.println(proxy.getClass().getName());
        proxy.sayHello("way");
    }
}

Jdk代理需要被代理类(也就是Target)实现接口(也就是TargetInterface),为什么呢?通过上面的输出可以看到 com.sun.proxy.$Proxy0 ,proxy是一个代理对象,通过反编译源码可以得知$Proxy0类继承了Proxy类,那么由于单继承的缘故,proxy要建立与代理类的关系的话那么只能通过接口了。而这也是Jdk动态代理的一个缺点,因为有时被代理类并非全都有实现接口。

 

3.Cglib动态代理

首先,引入相关依赖:

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

这次,为了对比,我们建一个没有实现接口的被代理类:

/**
 * @author wayleung
 * @description
 * @date 2020-08-12 09:43:39
 */
public class TargetNoInterface{
    public String sayHello(String name) {
        String result = "Hello," + name;
        System.out.println(result);
        return result;
    }
}

然后就是类似Jdk动态代理的实现相关api:


/**
 * @author wayleung
 * @description
 * @date 2020-08-12 10:38:32
 */
public class MyMethodInterceptor implements MethodInterceptor {


    @Override
    public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理前做点东西");
        Object result = methodProxy.invokeSuper(target, args);
        System.out.println("代理后做点东西");
        return result;
    }
}

最后就是去使用它:


/**
 * @author wayleung
 * @description
 * @date 2020-08-12 10:37:19
 */
public class CglibDynamicProxyDemo {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(TargetNoInterface.class.getClassLoader());
        enhancer.setSuperclass(TargetNoInterface.class);
        enhancer.setCallback(new MyMethodInterceptor());
        TargetNoInterface proxy = (TargetNoInterface) enhancer.create();
        System.out.println(proxy.getClass().getName());
        proxy.sayHello("way");
    }
}

通过这个可见,CGlib动态代理不需要被代理类实现接口,值得注意的是,CGlib 动态代理是通过生成一个被代理类的子类(继承)来拦截被代理类的方法调用,因此不能代理声明为 final 类型的类和方法,假如被代理类是final类,那么运行时报错:

假如被代理方法是final方法,那么能运行,但是方法没有被代理(没有被增强):

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值