设计模式(3)--代理模式

本文详细介绍了代理模式的概念及其应用场景,对比了静态代理与动态代理的区别,并深入探讨了JDK动态代理和CGLIB动态代理的实现原理及代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代理模式在工作中用的比较多,常见的AOP使用的底层实现就是一种动态代理。
在面试中经常考察设计模式,一般都会问你工作中常用哪几种设计模式,当你说了几种设计模式的时候,一般就会问你什么时候回用到这种设计模式?这个很关键,这个是考察你在工作中是否真正的用到过这种设计模式的一种方式。

1,什么时候用代理模式?
代理模式,简言之,就是用一个代理类,代理当前类。 那为什么要这么做呢? 一般是因为一个类中的方法或者属性不想直接暴露给调用的第三方,也不想重新copy一份代码(修改麻烦,要改两份),所以,一般会用一个代理类,第三方调用的时候直接调用代理类就行了,而代理类中的方法实现还是用的是被代理类中的实现。

2,代理模式的分类
代理模式分为动态代理和静态代理两种,区别就是静态代理的代理关系是代码的编译期就确定的,动态代理是代码的运行期确定的(代码运行起来的时候,程序才知道你想代理哪个类【反射】)。
动态代理又分为cglib代理和jdk的代理,两者的区别是jdk代理只能代理接口,cglib代理既能代理接口又能代理实现类。

3,静态代理。

代理的类图:

这里写图片描述

subject是接口,proxy是代理类, RealSubject是真实的实现类, Client是调用方,为了说明代理模式的使用场景,我们看一下下面的代码:

interface Subject {
    void request();
}
class RealSubject implements Subject {
    public void request(){
        System.out.println("RealSubject");
    }
    public void response(){
       System.out.println("不想被调用方调用的方法");
    }
}
class Proxy implements Subject {
    private Subject subject;
    public Proxy(Subject subject){
        this.subject = subject;
    }
    public void request(){
        subject.request();
    }
}

在上面的一段代码中,面向Client,调用方可以调用request 但是不能调用到response。 这是代理模式最常见的使用场景。

2,jdk动态代理。

动态代理最被广泛的认知就是在spring 的 aop中使用了cglib实现的动态代理, 但是aop不仅仅可以用动态代理实现, aop也可以使用责任链模式实现, 所以读者要搞清楚这里的区别。

jdk代理又一定的局限性, 他要求被代理的类必须有一个接口,但是并不是所有的类都有接口。 下面代码是jdk代理的实现方式:

public interface Service {  
    //目标方法 
    public abstract void add();  
} 
public class UserServiceImpl implements Service {  
    public void add() {  
        System.out.println("This is add service");  
    }  
}

2、利用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口定义代理类的实现。

class MyInvocatioHandler implements InvocationHandler {
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("-----before-----");
        Object result = method.invoke(target, args);
        System.out.println("-----end-----");
        return result;
    }
    // 生成代理对象
    public Object getProxy() {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        return Proxy.newProxyInstance(loader, interfaces, this);
    }
}

jdk的动态代理模式写法有一些基本是固定的,必须要实现InvocationHandler接口,实现其中的invoke方法,这里可以看到在调用真实实现类实现方法的时候,前后可以做一些事情,这就是aop的实现,前后可以加日志、事物等等的一些处理。

cglib实现的动态代理:

cglib的动态代理相比jdk的动态代理要灵活很多,可以直接代理实现类。

public class SayHello {  
 public void say(){  
  System.out.println("hello everyone");  
 }  
} 
public class CglibProxy implements MethodInterceptor{  
 private Enhancer enhancer = new Enhancer();  
 public Object getProxy(Class clazz){  
  //设置需要创建子类的类  
  enhancer.setSuperclass(clazz);  
  enhancer.setCallback(this);  
  //通过字节码技术动态创建子类实例  
  return enhancer.create();  
 }  
 //实现MethodInterceptor接口方法  
 public Object intercept(Object obj, Method method, Object[] args,  
   MethodProxy proxy) throws Throwable {  
  System.out.println("前置代理");  
  //通过代理类调用父类中的方法  
  Object result = proxy.invokeSuper(obj, args);  
  System.out.println("后置代理");  
  return result;  
 }  
}  
public class DoCGLib {  
 public static void main(String[] args) {  
  CglibProxy proxy = new CglibProxy();  
  //通过生成子类的方式创建代理类  
  SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class);  
  proxyImp.say();  
 }  
}  

Cglib实现的关键是通过字节码技术动态创建子类实例。实现spring的MethodInterceptor是为了实现aop。 由于Cglib代理用了动态的创建子类,所以无法为final方法进行代理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

专注网赚的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值