什么是代理?
在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);
}
}
}
}