代理模式(静态代理,JDK动态代理)

定义:使用一个代理将对象包装起来,然后用该代理对象取代原始对象;任何对原始对象的调用都要通过代理;代理对象决定是否以及何时将方法调用到原始对象上。

使用代理模式的目的

  1. 保护目标对象。
  2. 增强目标对象。before()、after()
  3. 降低了系统的耦合度。

弊端:降低了访问效率 。

可通过加缓存缓解上述弊端:缓存已处理过的业务,当来了一个新的业务访问时,先看缓存中有没有,没有再调用被代理类的方法。

静态代理

代理类和被代理类在编译器就被确定。

public class MyTest {
    public static void main(String[] args) {
        NikeClothFactory nikeClothFactory = new NikeClothFactory();
        MyProxy myProxy = new MyProxy(nikeClothFactory);
        myProxy.produceCloth();
        /**
         * 运行结果
         * 方法调用前
         * 我是被代理类
         * 方法调用后
         */
    }
}

//代理类
class MyProxy implements ClothFactory{
    private ClothFactory factory;

    public MyProxy(ClothFactory factory) {
        this.factory = factory;
    }

    @Override
    public void produceCloth() {
        before();
        factory.produceCloth();
        after();
    }

    public void before(){
        System.out.println("方法调用前");
    }

    public void after(){
        System.out.println("方法调用后");
    }
}

//被代理类
class NikeClothFactory implements ClothFactory{
    @Override
    public void produceCloth() {
        System.out.println("我是被代理类");
    }
}

interface ClothFactory{
    void produceCloth();
}

动态代理

  • 根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
  • 通过代理对象调用的方法,动态的去调用被代理类中的同名方法。

JDK动态代理

必须有接口。

实现步骤:

  1. 业务接口。
  2. 实现接口的被代理类。
  3. 实现InvocationHandler接口的代理类,重写invoke(...)方法。
  4. 通过Prox.newProxyInstance(...)获取代理类。

代码实现 :

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


public class a {
    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();
        MyProxy my = new MyProxy();
        my.bindObject(superMan);
        //Proxy.newProxyInstance    传入被代理类的类加载器、被代理类实现的接口、动态代理方法在执行时,会调用InvocationHandler里面的invoke方法去执行
        Object o = (HUman)Proxy.newProxyInstance(superMan.getClass().getClassLoader(), superMan.getClass().getInterfaces(), my);
        String out = ((HUman) o).Belief();
        System.out.println(out);
    }
}

class MyProxy implements InvocationHandler{
    private  Object obj;
    public void bindObject(Object obj){
        this.obj = obj;
    }
    @Override
    //invoke(Object proxy, Method method, Object[] args)    传入代理的对象、要调用的方法、以及传入方法的参数
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object returnValues = method.invoke(obj,args);
        return returnValues;
    }
}

//被代理类
class SuperMan implements HUman{
    @Override
    public String Belief() {
        return "fly";
    }
}

//接口
interface HUman{
    String Belief();
}

原理解析:

1.从Proxy.newProxyInstance(...)方法入手:

 2.getProxyClass0()方法

3.WeakCache中的get方法,也就是上面proxyClassCache.get()方法。

先说说这个里面的缓存结构。

map: 一级缓存;其中key存储的的由被代理类的类加载器决定的一个CacheKey对象,value存储的是二级缓存map对象(在源码中这个二级缓存对象的变量名叫做valueMap)。

subKeyFactory:二级缓存的key;存储被代理的类加载器和其实现接口的一个标识符。

valueFactory:二级缓存的value;存储对应的代理类工厂。

4.ProxyClassFactory创建代理类

流程梳理

首先从Proxy.newProxyInstance()方法开始;

       1. 在这个方法里面首先调用一个名为getProxyClass0()的静态方法,这个静态方法的作用就是查找或生成指定的代理类。若缓存中有所需的代理类,直接获取,没有则创建。

        具体怎么获取或者创建呢?

        getProxyClass0()的返回值是proxyClassCache.get()方法的返回值。

        proxyClassCache.get() 中有两个缓存,

        一级缓存;key存储的的由被代理类的类加载器决定的一个CacheKey对象;value存储的是二级缓存map对象。(用来区分classLoader)

       二级缓存:key存储被代理的类加载器和其实现接口的一个标识符;value存储对应的代理类工厂。(用来区分实现的接口)

        1.1在这个方法中首先根据代理类的类加载器获取一级缓存中的value对象(也就是二级缓存)。

                如果得到二级缓存为空,就创建一个二级缓存(此时它里面为空)存入到一级缓存中;

                若不为空直接获取。

        1.2根据被代理类实现的接口数组生成对应的二级缓存的key(key0,key1...) 。

        1.3根据这个key在二级缓存中获取对应代理类工厂。

                若这个代理类工厂存在,进行线程是否安全验证之后,直接返回缓存值。

                若这个代理类工厂不存在,先创建一个factory对象,此时里面还没有代理类。然后调用ProxyClassCache中apply方法。创建代理对象。

                ProxyClassCache创建代理类过程:

                a.判断被代理类是否实现接口。

                b.判断当前接口是否重复。

                c.定义生成代理类访问权限--public final。

                d.看接口的访问权限是否为public,如果是,生成的代理类和他放在同一个包下;如果不是放在com.sun.proxy包下。

                e.创建代理类名称。

                f.生成代理类字节码文件。(生成的代理类继承了Proxy,实现了传入的业务接口)

                g.加载字节码文件,生成指定代理类Class对象。

        获取到代理类class对象后,通过 有参构造,将实现了InvocationHandler接口的对象当作参数创建代理类对象。

        当我们通过代理类调用代理业务时,代理类会自动帮我们调用InvocationHandler中的invoke()方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值