4.4多线程--代理模式

代理模式

image.png
  1. 用户只关心接口功能,而不在乎谁提供了功能。上图中接口是 Subject。
  2. 接口真正实现者是上图的 RealSubject,但是它不与用户直接接触,而是通过代理。
  3. 代理就是上图中的 Proxy,由于它实现了 Subject 接口,所以它能够直接与用户接触。
  4. 用户调用 Proxy 的时候,Proxy 内部调用了 RealSubject。所以,Proxy 是中介者,它可以增强 RealSubject 操作。

静态代理

接口实现方式

image.png

继承方式
image.png

/*
    静态代理DEMO
 */
public class StaticProxyDemo {
    public static void main(String[] args) {
        new WeddingCompany(new Person()).wedding();
    }
}

//1. 一个接口
interface Memarry {
    void wedding();
}

//2. 人,真正的结婚类
class Person implements Memarry{
    @Override
    public void wedding() {
        System.out.println("这个屌丝正在结婚办婚礼……");
    }
}

//3. 婚庆公司,结婚代理类
class WeddingCompany implements Memarry{
    private Person target;

    public WeddingCompany(Person target) {
        this.target = target;
    }

    @Override
    public void wedding() {
        System.out.println("婚庆公司提前布置会场");
        this.target.wedding();
        System.out.println("婚庆公司收尾款");
    }
}

动态代理

动态代理技术,不需要人工编写代理类 java 文件,而是在运行过程中,在 JVM 内存中创建出来的代理对象共我们使用。有两种实现技术:

基于 JDK(接口)的动态代理

JDK 自带的动态代理技术,要求目标类要实现一个接口;需要使用 Proxy 类的静态方法 newProxyInstance 在程序运行阶段在内存中生成一个代理对象,生成的代理对象与目标类实现同一个接口,是兄弟关系,不能互相转换,包容性差;(spring 框架中,如果配置 JDK 的动态代理,一定要用接口类型接收代理对象)

Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
loader: 固定写法,指定目标类对象的类加载器。用于加在目标类及其接口的字节码文件。通常使用目标类的字节码对象调用 getClassLoader() 方法。
interfaces:固定写法,指定目标类实现的所有接口的字节码对象的数组。通常调用 getInterfaces() 方法。
h: 

public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
proxy : 代理类对象的一个引用,即 Proxy.newProxyInstance() 方法返回的值,几乎用不到。
method : 触发 invoke 方法执行的方法的反射对象(Method 对象)。
args : 代理对象调用方法时,传递的实际参数。
/**
 * 基于 JDK (接口)的动态代理
 */
public class DynamicProxyDemo2 {
    public static void main(String[] args) {
        //1、创建目标类对象
        Person2 person = new Person2();
        //2、使用 JDK 的 API 动态生成一个代理类对象
        Memarry2 weddingCompany = (Memarry2)Proxy.newProxyInstance(person.getClass().getClassLoader(),
                person.getClass().getInterfaces(),
                (proxy, method, args1)->{
                    System.out.println("+++++++++++++++++++++++++++++");
                    if(method.getName().equals("wedding")){
                        System.out.println("婚庆公司正在筹办宴会厅");
                        String result = (String)method.invoke(person,args);
                        System.out.println("婚庆公司收尾款");
                        return result;
                    } else {
                        return method.invoke(person,args);
                    }

                });
        String result = weddingCompany.wedding();
        System.out.println(">>>>>result:"+result);
        // 自己模拟实现 JVM 运行中生成的代理类
//        InvocationHandler handler = (proxy, method, args1)->{
//                    System.out.println("+++++++++++++++++++++++++++++");
//                    if(method.getName().equals("wedding")){
//                        System.out.println("婚庆公司正在筹办宴会厅");
//                        String result = (String)method.invoke(person,args);
//                        System.out.println("婚庆公司收尾款");
//                        return result;
//                    } else {
//                        return method.invoke(person,args);
//                    }
//
//                };
//        SelfProxy selfProxy = new SelfProxy(handler);
//        System.out.println(">>>>>result:"+selfProxy.wedding());
    }
}

//1. 一个接口
interface Memarry2 {
    String wedding();

    void test1();
    void test2();
}
//2. 人,真正的结婚类
class Person2 implements Memarry2{
    @Override
    public String wedding() {
        System.out.println("这个屌丝正在结婚办婚礼……");
        return "恭喜恭喜";
    }

    @Override
    public void test1() {
        System.out.println("这是test1方法");
    }
    @Override
    public void test2() {
        System.out.println("这是test2方法");
    }
}
/**
 * 模拟 Proxy.newProxyInstance() 方法 是如何实现的
 */
public class SelfProxy implements Memarry2 {

    // 接收外部传递过来的 InvocationHandler 对象
    private final InvocationHandler handler;

    public SelfProxy(InvocationHandler handler){
        this.handler = handler;
    }
    
    @Override
    public String wedding() {
        try {
            // 调用的是 wedding 方法,则反射获取 wedding 对应的 method 对象,传入 invoke 中
            Method method = Memarry2.class.getMethod("wedding");
            // 调用 InvocationHandler 中的 invoke 方法
            String result = (String)handler.invoke(this,method,null);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return null;
    }

    @Override
    public void test1() {
        try {
            Method method = Memarry2.class.getMethod("test1");
            String result = (String)handler.invoke(this,method,null);
        } catch (Exception e) {
            e.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    @Override
    public void test2() {
        try {
            Method method = Memarry2.class.getMethod("test2");
            String result = (String)handler.invoke(this,method,null);
        } catch (Exception e) {
            e.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}

基于 CGLIB(父类)的动态代理

CGLIB 也是使用一个静态方法生成代理类对象;他要求目标类不能是最终类,也就是不能被 final 修饰,可以被继承;生成的代理类对象是目标类的子类。可以用父类接收代理对象。

Enhancer.create(Class type,Callback callback)
type: 指定目标类的字节码对象,即目标类的类型。
callback: 回调方法。Callback 是一个接口,只起到名称定义的作用,并不包含方法的声明。所以通常使用它的一个子接口 MethodInterceptor (方法拦截器),它内部只有一个方法 intercept。
Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)
        throws Throwable;
proxy : 代理类对象的一个引用,即 Enhancer.create() 方法返回的值,几乎用不到。
method : 触发 intercept 方法执行的方法的反射对象(Method 对象)。
args : 代理对象调用方法时,传递的实际参数。
methodProxy : 方法的代理对象,一般也不做处理。
/**
 * 基于 CGLIB 的动态代理
 */
public class DynamicProxyDemo {
    public static void main(String[] args) {
        //1、创建目标类对象
        Person person = new Person();
        //2、使用 CGLIB 的静态方法动态生成一个代理类对象,是父子关系
        Person personProxy = (Person)Enhancer.create(person.getClass(), new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("+++++++++++++++++++++++++++++");
                if(method.getName().equals("wedding")){
                    System.out.println("婚庆公司正在筹办宴会厅");
                    String result = (String)method.invoke(person,args);
                    System.out.println("婚庆公司收尾款");
                    return result;
                } else {
                    return method.invoke(person,args);
                }
            }
        });
        System.out.println(">>>>>result:"+personProxy.wedding());
    }
}

class Person {
    public String wedding() {
        System.out.println("这个屌丝正在结婚办婚礼……");
        return "恭喜恭喜";
    }

    public void test1() {
        System.out.println("这是test1方法");
    }
    public void test2() {
        System.out.println("这是test2方法");
    }
}
/**
* 模拟 Enhancer.create() 方法
*/
public class SelfProxy extends Person {

    private final MethodInterceptor methodInterceptor;
    public SelfProxy(MethodInterceptor methodInterceptor){
        this.methodInterceptor = methodInterceptor;
    }

    @Override
    public String wedding() {
        Method method = null;
        try {
            method = Person.class.getMethod("wedding");
            String result = (String)methodInterceptor.intercept(this,method,null,null);
            return result;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return super.wedding();
    }

    @Override
    public void test1() {
        Method method = null;
        try {
            method = Person.class.getMethod("test1");
            Object result = methodInterceptor.intercept(this,method,null,null);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    @Override
    public void test2() {
        Method method = null;
        try {
            method = Person.class.getMethod("test2");
            Object result = methodInterceptor.intercept(this,method,null,null);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

}

扩展

如果使用 dubbo + zookeeper,底层进行代理时,最好定死使用 CGLIB 的方式。因为 dubbo 会使用基于包名的扫描方式进行类的处理。JDK 生成的代理类的包名类似于 com.sun.proxy...的格式,而 CGLIB 生成的代理类的包名与目标类一致。

引文列表:
https://www.cnblogs.com/cC-Zhou/p/9525638.html
https://www.bilibili.com/video/BV1M54y1X78p?from=search&seid=12941460499174324218&spm_id_from=333.337.0.0

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容