设计模式之代理模式

设计模式之代理模式,第1张

设计模式代理模式 1、代理模式定义

代理模式是在不修改源目标的前提下,额外扩展源目标的功能。

即通过访问源目标的代理类,再由代理类去访问源目标。这样一来,要扩展功能,就无需修改源目标的代码了。只需要在代理类上增加就可以了。

如上图所示:访问者通过上图 1 的方式,替换 2 的方式。保留源目标类方法不动的情况下,实现起拓展功能。

2、代理模式类别

下书代码实例,是我们创建的一个确定接口及对应的实现类,作为源目标类。

public interface Person {
    void wakeUp();
    void sleep();
}
public class Student implements Person {
    private String name;
    public Student() { }
    public Student(String name) {
        this.name = name;
    }
    public void wakeUp() {
        System.out.println( " Good morning " + name);
    }
    public void sleep() {
        System.out.println(" Good evening " + name);
    }
}
2.1、静态代理

静态代理即声明一个明确的代理类,来拓展源目标的方法。

public class StudentProxy implements Person {
 		private Person person;
		public StudentProxy(Person person) {
        this.person = person;
    } 
    public void wakeUp() {
        System.out.print(" 我是静态代理 wakeUp ");
        this.person.wakeUp();
    } 
    public void sleep() {
        System.out.print(" 我是静态代理 Sleep ");
        this.person.sleep();
    } 
    public static void main(String[] args) {
        Person student = new Student("王大拿");
        Person person = new StudentProxy(student);
        student.wakeUp();
        student.sleep();
        person.wakeUp();
        person.sleep();
    }

}

输出结果:

 Good morning 王大拿
 Good evening 王大拿
 我是静态代理 wakeUp  Good morning 王大拿
 我是静态代理 Sleep  Good evening 王大拿

静态代理缺点:

  • 会存在大量的冗余的代理类,这里演示了1个接口,如果有10个接口,就必须定义10个代理类。
  • 不易维护,一旦接口更改,代理类和目标类都需要更改。
2.2、动态代理

动态代理, 即无需声明式的创建java代理类,而是在运行过程中生成"虚拟"的代理类,被ClassLoader加载。

2.2.1、jdk动态代理 2.2.1.1、实现方式一 java.lang.reflect.InvocationHandler
public class JDKProxy  implements InvocationHandler { 
    private Object object ; 
    public JDKProxy(Object object) {
        this.object = object;
    } 
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        if(methodName.equals("wakeUp")){
            System.out.print(" 我是JDK动态代理 wakeUp ");
        }else if (methodName.equals("sleep")){
            System.out.print(" 我是JDK动态代理 sleep ");
        }
        return method.invoke(object , args);
    } 
    public static void main(String[] args) {
        JDKProxy proxy1 = new JDKProxy(new Student("刘星星"));
        Person person = (Person) Proxy.newProxyInstance(proxy1.getClass().getClassLoader(), new Class[]{Person.class}, proxy1);
        person.wakeUp();
        person.sleep();
    }
}

输出结果:

我是JDK动态代理 wakeUp  Good morning 刘星星
我是JDK动态代理 sleep  Good evening 刘星星

可以看到被代理后Person的Bean对应的是代理实体类为Proxy

2.2.2.1.2 实现方式二 java.lang.reflect.Proxy
public class JDKProxy2 { 
    private Object object; 
    public Object getProxy() {
        Object proxy = Proxy.newProxyInstance(object.getClass().getClassLoader(),
                object.getClass().getInterfaces(),
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        String methodName = method.getName();
                        if ("wakeUp".equals(methodName)) {
                            System.out.print("我是JDk动态代理2 wakeUp ");
                        } else if ("sleep".equals(methodName)) {
                            System.out.print("我是JDk动态代理2 sleep ");
                        }
                        return method.invoke(object, args);
                    }
                });
        return proxy;
    } 
    public JDKProxy2(Object object) {
        this.object = object;
    } 
    public static void main(String[] args) {
        Student student = new Student("大西瓜");
        JDKProxy2 proxy2 = new JDKProxy2(student);
        Person person = (Person) proxy2.getProxy();
        person.wakeUp();
        person.sleep();
    }
}

输出结果:

我是JDk动态代理2 wakeUp  Good morning 大西瓜
我是JDk动态代理2 sleep  Good evening 大西瓜
2.2.2、cglib动态代理

Spring在5.X之前默认的动态代理实现一直是jdk动态代理。但是从5.X开始,spring就开始默认使用Cglib来作为动态代理实现。并且springboot从2.X开始也转向了Cglib动态代理实现。

Cglib是一个开源项目,它的底层是字节码处理框架ASM,Cglib提供了比jdk更为强大的动态代理。主要相比jdk动态代理的优势有:
jdk动态代理只能基于接口,代理生成的对象只能赋值给接口变量,而Cglib就不存在这个问题,Cglib是通过生成子类来实现的,代理对象既可以赋值给实现类,又可以赋值给接口。
Cglib速度比jdk动态代理更快,性能更好

public class CGLibProxy implements MethodInterceptor { 
    private Enhancer enhancer = new Enhancer(); 
    private Object bean; 
    public CGLibProxy(Object bean) {
        this.bean = bean;
    } 
    public Object getProxy() {        //设置需要创建子类的类
        enhancer.setSuperclass(bean.getClass());
        enhancer.setCallback(this);
        //通过字节码技术动态创建子类实例
        return enhancer.create();
    } 
    //实现MethodInterceptor接口方法
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        String methodName = method.getName();
        if (methodName.equals("wakeUp")) {
            System.out.print("我是cglib动态代理 wakeUp ");
        } else if (methodName.equals("sleep")) {
            System.out.print("我是cglib动态代理 sleep ");
        }        //调用原bean的方法
        return method.invoke(bean, args);
    } 
    public static void main(String[] args) {
        CGLibProxy proxy = new CGLibProxy(new Student("陈鹏鹏"));
        Student student = (Student) proxy.getProxy();
        student.wakeUp();
        student.sleep();
    }
}

输出结果:

我是cglib动态代理 wakeUp  Good morning 陈鹏鹏
我是cglib动态代理 sleep  Good evening 陈鹏鹏

cglib包引入:

<dependency>
    <groupId>cglibgroupId>
    <artifactId>cglibartifactId>
    <version>3.3.0version>
dependency>

代理模式是技术迭代的核心,组件开发的重中之重

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/875870.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存