【Java基础】代理

什么是代理?

在Java中主要分为静态代理和动态代理模式,动态代理是一种比较常用的代理模式,它让我们不需要手动去编写代理类,而只要去实现代理的扩展即可。

代理有什么作用?

代理是一种设计模式,代理模式主要有两个目的:一是保护目标对象,二是增强目标对象,

什么是静态代理?

被代理类RealSubject实现Subject接口,代理类ProxySubject也要实现相同的接口,并持有被代理类RealSubject的实例,在实现的接口方法中做相应的逻辑操作。这种方式就是静态代理。

在这里插入图片描述

public interface Subject {
    void doSomething();
}
public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("I'm eating food!");
    }
}
public class ProxySubject implements Subject {

    Subject subImp = new RealSubject();

    @Override
    public void doSomething() {
        subImp.doSomething();
        after();
    }
    public void after(){
        System.out.println("I do the dishes!");
    }
}

什么是动态代理?

静态代理中,需要编写实现类实现被代理类的接口,有没有可能不编写实现类,直接在运行期创建某个interface的实例呢?这是可能的,因为Java标准库提供了一种动态代理(Dynamic Proxy)的机制,可以在运行期动态创建某个interface的实例。先看下java创建对象的过程。

在这里插入图片描述
在这里插入图片描述

可以看出,要创建一个实例,最关键的就是得到对应的Class对象。只不过对于初学者来说,new这个关键字配合构造方法,实在太好用了,底层隐藏了太多细节,一句 Person p = new Person();直接把对象返回给你了。我自己刚开始学Java时,也没意识到Class对象的存在。
在这里插入图片描述

动态代理如何实现?

Class对象包含了一个类的所有信息,比如构造器、方法、字段等。如果我们不像静态代理一样写代理类,这些信息从哪获取呢?通过反射,代理类和目标类理应实现同一组接口。下面介绍一下JDK实现动态代理的方式:JDK动态代理;当然还有其他方式,比如 ASM(字节码操作框架)以及CGlib(基于ASM)动态代理(不是通过实现相同接口的方式,本文不讲)

JDK动态代理

JDK动态代理用法

在这里插入图片描述

Java如何实现动态代理?首先实现动态代理,代理类和目标类理应实现同一组接口。之所以实现相同接口,是为了尽可能保证代理对象的内部结构和目标对象一致,这样我们对代理对象的操作最终都可以转移到目标对象身上,代理对象只需专注于增强代码的编写。被代理类RealSubject及其实现的接口还是需要有的,而且和静态代理的一样。我们需要实现InvocationHandler接口,在InvocationHandler接口实现中持有被代理类的对象,也就是这里的target,在invoke方法中通过Method传入被代理类对象(target)及方法参数(args),实现调用被代理接口的方法,同时实现代理类需要实现的逻辑,比如这里打印了“I do the dishes!”。

public class Handler implements InvocationHandler {

    Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        method.invoke(target,args);
        System.out.println("I do the dishes!");
        return null;
    }
}
public class Main {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        Subject proxySubject = (Subject)Proxy.newProxyInstance(RealSubject.class.getClassLoader(),
                                                               new Class[] {Subject.class}, new          
                                                               Handler(realSubject));
        proxySubject.doSomething("eating food!");
    }
}
JDK动态代理的原理

从生成代理类的入口Proxy.newProxyInstance(删掉了部分关系不大的代码)看一下如何生成的代理类。

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
    Objects.requireNonNull(h);

    final Class<?>[] intfs = interfaces.clone();

    /*
     * 查找或者生成指定代理类的类对象(也就是class对象)
     */
    Class<?> cl = getProxyClass0(loader, intfs);

    try {
        /*
         * 通过代理类的类对象传入构造参数获取构造器
         */
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        /*
         * 判断类的修饰符,如果不是public,则设置可访问。
         * (类可以用修饰符public声明,在这种情况下,类对所有类都可见。如果一个类没有修饰符(默认,也称为package-
         *   private),它只在自己的包中可见)
         */
        if (!Modifier.isPublic(cl.getModifiers())) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
        }
        /*
         * 使用此Constructor对象表示的构造函数,使用指定的初始化参数创建和初始化构造函数声明类的新实例。 
         * 这里初始化参数是InvocationHandler,至于为什么要看getProxyClass0生成的class实例的内容(构造器的内容)
         * 猜测构造器肯定有InvocationHandler类型入参。
         */
        return cons.newInstance(new Object[]{h});
    } catch (IllegalAccessException|InstantiationException e) {
    } 
}
private static Class<?> getProxyClass0(ClassLoader loader,
                                       Class<?>... interfaces) {
    if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }
    /*
     * 通过缓存查找值, 如果给定的 (key, subKey) 对在缓存中没有条目或者条目已经被清除,否则通过ProxyClassFactory创建
     * 代理类的class对象。
     */
    return proxyClassCache.get(loader, interfaces);
}
/*
 * proxyClassCache其实是WeakCache,有个ProxyClassFactory入参
 */
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
    proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
public V get(K key, P parameter) {
    Objects.requireNonNull(parameter);

    expungeStaleEntries();

    Object cacheKey = CacheKey.valueOf(key, refQueue);

    // lazily install the 2nd level valuesMap for the particular cacheKey
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }

    // create subKey and retrieve the possible Supplier<V> stored by that
    // subKey from valuesMap
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;

    while (true) {
        if (supplier != null) {
            // supplier might be a Factory or a CacheValue<V> instance
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }
        // else no supplier in cache
        // or a supplier that returned null (could be a cleared CacheValue
        // or a Factory that wasn't successful in installing the CacheValue)

        // lazily construct a Factory
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }

        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                // successfully installed Factory
                supplier = factory;
            }
            // else retry with winning supplier
        } else {
            if (valuesMap.replace(subKey, supplier, factory)) {
                // successfully replaced
                // cleared CacheEntry / unsuccessful Factory
                // with our Factory
                supplier = factory;
            } else {
                // retry with current supplier
                supplier = valuesMap.get(subKey);
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值