zoukankan      html  css  js  c++  java
  • 代理模式(静态代理、动态代理)

    代理模式的由来:当调用某个对象时,不关心是否准确得到该对象,而是只要一个能提供对应功能的对象即可,这时我们可以为该对象提供一个代理对象,由代理对象控制对源对象的引用。

    第一.静态代理

    常见静态代理模式:一个接口,两个实现类,分别为被代理类和代理类,代理类中进行如下操作即可
    1.创建接口类型成员变量
    2.构造方法中创建被代理类对象()
    3.实现的接口方法中调用被代理类的实现的接口方法
    示例代码如下:

    // 被代理类
    class SubjectImpl implements Subject {
        @Override
        public void action() {
            System.out.println("执行action方法体");
        }
    }
    
    // 代理类
    class ProxyClass implements Subject {
        private Subject subject = new SubjectImpl();
    
        private void beforeHandle() {
            System.out.println("业务方法执行前执行前置增强处理");
        }
    
        private void afterHandle() {
            System.out.println("业务方法执行后执行后置增强处理");
        }
    
        @Override
        public void action() {
            this.beforeHandle();
            subject.action();
            this.afterHandle();
        }
    
    }
    
    public class ProxyTest {
        public static void main(String[] args) {
            ProxyClass obj = new ProxyClass();
            obj.action();
        }
    }

    要使用被代理类对象的方法时,只需简单的实例化代理类对象,调用此代理类对象的方法即可,其实是方法内部调用了被代理类的方法。

    第二.动态代理

    JDK动态代理主要用到了Proxy类和InvocationHandler接口,两者都在java.lang.reflect包下。

    首先介绍一下Proxy类,这个类是所有动态代理类的父类,主要用到这个类的newProxyInstance()静态方法:

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

    这个方法直接生成一个动态代理类对象,方法需要传三个参数,第一个参数是被代理类对应的类加载器对象,第二个参数是被代理类实现的一系列接口对应的Class对象组成的数组一个数组,第三个参数是一个InvocationHandler对象(一个InvocationHandler实现类对象)。

    InvocationHander接口就只有一个方法:

    public Object invoke(Object proxy, Method method, Object[] args)

    我们得自定义一个InvocationHander接口实现类,重写invoke()方法。

    JDK动态代理代码示例:

    //接口
    interface Subject {
        public void doSomething(String str);
    }
    
    // 接口实现类
    class RealSubject implements Subject {
        @Override
        public void doSomething(String str) {
            System.out.println("Subject接口实现类RealSubject实现doSomething方法()");
        }
    }
    
    // InvocationHandler接口实现类
    class MyIncovationHandler implements InvocationHandler {
        private Object proxied;
    
        // 构造器参数是被代理类对象
        public MyIncovationHandler(Object proxied) {
            this.proxied = proxied;
        }
    
        public MyIncovationHandler() {
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            before();
            method.invoke(proxied, args);
            after();
            return null;
        }
    
        // 增强处理方法,可以抽出到一个单独的工具类里面
        private void before() {
            System.out.println("Before处理");
        }
    
        private void after() {
            System.out.println("After处理");
        }
    }
    
    public class JdkDynamicProxyTest {
        public static void main(String args[]) {
            Subject s = new RealSubject();
            Object obj = Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(),
                    new MyIncovationHandler(s));
            Subject subject = (Subject) obj;
            subject.doSomething("kou");
        }
    }

         上例中,有一个RealSubject类,实现了接口Subject。InvocationHander接口的实现类MyInvocationHander,重写了invoke方法,在方法体中调用第二个参数method的invoke方法,method的invoke方法需要两个参数,第一个参数是被代理类的实例,第二个参数是参数列表,是invoke方法的第三个参数。这里被代理类的实例不建议直接new出来一个实例然后传进去,而是建议在创建InvocationHander实例时把被代理类实例传进来,这样比较解耦。

          编译上Proxy.newProxyInstance()的返回值类型是Object,但其实运行时类型是动态代理类的类型($Proxy开头的类),又因为实现了代理类所实现的全部接口,所以可以强转为任意一个所实现的接口类型。这个时候调用该接口的方法,底层就会执行接口实现类对应的实现。

          Proxy的newProxyInstance()方法的第二个参数是接口对应的Class对象组成的数组,而不是被代理类的Class对象。所以说,JDK动态代理建立在接口之上的。那么,如果被代理类没有实现任何接口,就不能用JDK动态代理了,需要用到cglib动态代理。cglib动态代理其实是对被代理类创建一个子类,让这个子类去代理父类,所以要求被代理类不能是final的。

  • 相关阅读:
    Extjs 集合了1713个icon图标的CSS文件
    Sencha Touch 2 DataView / List 分页
    Sencha Touch 笔记
    [奉献]通过命令快速启动应用程序的小软件(QuickLauncher V1.1)
    PTC FlexPLM rfa 接口自动创建产品规格
    Excel Vba 调用WebService的两种方式,解决MSSOAP30 64位不兼容问题
    Extjs4.1.x 框架搭建 采用Application动态按需加载MVC各模块
    C#获取远程图片,需要Form用户名和密码的Authorization认证
    [转]plsql不安装oracle客户端 进行远程连接
    WPF、Silverlight程序编码资料收集
  • 原文地址:https://www.cnblogs.com/koushr/p/5873447.html
Copyright © 2011-2022 走看看