前言
代理的概念在项目中广泛使用,如如雷贯耳的Retrofit就是(这个后续文章会进行讲解),这个知识面试也是必问的
代理的思想 (定义)
代理的思想:目的是通过引用代理对象的方式来间接访问目标对象,防止直接访问目标对象给系统带来的不必要复杂性。而对于动态代理而言 当需要对多个目标对象访问的时候,实现用同一个代理父类实现。
代理还可以调用实际对象的过程中 在前后提供服务
代理的分类
代理模式:分为静态代理跟动态代理。
模式组成
1.先说下静态代理
静态代理实例:
/**
* 公共接口 抽象主题类:是代理类跟被代理类共同的接口方法 (可以是抽象类,也可以是接口)
*/
public interface PublicInterface {
//第一家目标对象卖零食
void buyFood1();
void buyFood2();
//如果第二家目标对象卖水果
}
-------------------------------------
/**
* 代理:也就是使用者不直接对目标对象进行访问,通过第三方的形式去访问,防止直接访问目标对象给系统带来的不必要复杂性。
* 静态代理:违背了开闭原则,对修改关闭,对新增开放 导致扩展能力差 可维护差
* 静态代理类
*/
public class StaticProxyDemo implements PublicInterface{
//我要去买目标对象1中的辣条 需要有目标对象的引用
private Target1 target1;
public StaticProxyDemo(Target1 target1) {
this.target1 = target1;
}
//如果直接这样自己去命名方法名 会导致最后不知道这个真实对象(目标对象)的哪个方法
//所以该代理类跟真实对象需要使用一个公共接口
//public void buy() {
// if (target1 != null) {
// target1.buyFood();
// }
//}
@Override
public void buyFood1() {
if (target1 != null) {
target1.buyFood1();
}
}
@Override
public void buyFood2() {
if (target1 != null) {
target1.buyFood2();
}
}
}
------------------------------
/**
* 目标对象1 比如这个是一间产生零食的作坊
*/
public class Target1 implements PublicInterface {
//辣条
private String food1 = "辣条";
//糖果
private String food2 = "糖果";
//买50包辣条
@Override
public void buyFood1() {
System.out.println("买50包" + food1);
}
//买一箱糖果
@Override
public void buyFood2() {
System.out.println("买一箱果" + food2);
}
}
-------------------------
调用
//静态代理实例
PublicInterface target1 = new Target1();
StaticProxyDemo staticProxyDemo = new StaticProxyDemo(target1);
staticProxyDemo.buyFood1();
staticProxyDemo.buyFood2();
上面这个就是静态代理的实例,但是如果新来一个客户说我不想吃零食了 我想吃水果
/**
* 目标对象2:这是一家卖水果的店
*/
public class Target2{
//苹果
private String apple = "苹果";
//橘子
private String orange = "橘子";
//买50斤橘子 水果
public void buyFruit1() {
System.out.println("买50斤" + apple);
}
//买50斤橘子
public void buyFruit2() {
System.out.println("买50斤" + orange);
}
}
那我们是难道又写一个水果的静态代理类吗?或许在静态代理类里面新增水果的方法,但是这2个的对象不一样 我们是不是又要传入一个水果的实例进来,那么这个代理类是不是非常难以维护 而且不符合单一原则 ,如果还有其他用户又需要其他的东西呢? 对不对,也或者我们可以新增新的静态代理类 虽然保证了单一原则,但是这样我们的代码是不是越来越庞大呢?那有没有什么代理类能满足所有客户的需要呢?有的 那就是动态代理类
静态代理优点
- 1.代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可(解耦合)
- 2.业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。
静态代理缺点
- 1.代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
- 2.代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了 静态代理小结:如果都用同一个代理类去实现 那就导致每新增一个需求 代理类就需要更改(不符合开闭原则 对修改关闭,对新增开放 导致扩展能力差 可维护差)
2.动态代理
核心概念:动态代理类 代表的是所有的代理类 也就是减免了代码里存在多个代理类,但是其他代码是一点省不了的!!!! 比如目标对象上面的接口 多个目标对象 还是存在多个接口
定义
利用反射机制在运行时创建代理类. 接口、被代理类不能变,一定得保留接口存在。
模式组成
跟静态代理一致,只是代理类不再局限于只代理一个具体类接口。
动态代理底层实现
动态代理具体步骤:
1. 通过实现 InvocationHandler 接口创建自己的调用处理器;
2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
动态代理的实例
//核心类
/**
* 动态代理:目标就是保证只有一个代理类满足所有需求,当然也需要一个公共的接口 这个接口就是InvocationHandler
*/
public class DynamicProxyDemo {
//获取真实对象的代理类的实例 核心的核心方法!!!!!!
public Object getProxy(final Object object) {
return Proxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(),
new InvocationHandler() {
//切记proxy 是真实的代理类的实例 不是真实对象
//method 触发的方法
//args 方法中带的参数
//返回值是调用方法后 方法的返回值
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//可以自己添加一些前置逻辑
doSthBefore();
method.setAccessible(true);
//方法的返回值
Object result = method.invoke(object, args);
//可以自己添加一些后置逻辑
doSthAfter();
//所以不能返回代理类实例 而是应该是方法的返回值
//return proxy;
return result;
}
});
}
/*后置处理器*/
private void doSthAfter() {
System.out.println("精美包装,快递一条龙服务");
}
/*前置处理器*/
private void doSthBefore() {
System.out.println("根据需求,进行市场调研和产品分析");
}
}
---------------------------------------------
//目标对象1
/**
* 动态代理的时候 目标对象1 比如这个是一间产生零食的作坊
*/
public class DynamicTarget1 implements PublicInterface {
//辣条
private String food1 = "辣条";
//糖果
private String food2 = "糖果";
//买50包辣条
@Override
public String buyFood1() {
System.out.println("买50包" + food1);
return "买50包" + food1;
}
//买一箱糖果
@Override
public void buyFood2() {
System.out.println("买一箱果" + food2);
}
}
//目标1对象的对应接口
/**
* 公共接口 抽象主题类:是代理类跟被代理类共同的接口方法
*/
public interface PublicInterface {
//第一家目标对象卖零食
String buyFood1();
void buyFood2();
//如果第二家目标对象卖水果
}
---------------------------------------
//目标对象2
/**
* 目标对象2:这是一家卖水果的店
*/
public class DynamicTarget2 implements PublicInterface2{
//苹果
private String apple = "苹果";
//橘子
private String orange = "橘子";
//买50斤橘子 水果
@Override
public void buyFruit1() {
System.out.println("买50斤" + apple);
}
//买50斤橘子
@Override
public void buyFruit2() {
System.out.println("买50斤" + orange);
}
}
//目标对象2的接口
/**
* 公共接口 抽象主题类:是代理类跟被代理类共同的接口方法
*/
public interface PublicInterface2 {
//第二家目标对象卖水果
void buyFruit1();
void buyFruit2();
}
-------------------------------------------
//获取动态代理类的实例
PublicInterface proxy1 = (PublicInterface) dynamicProxyDemo.getProxy(new DynamicTarget1());
String food1 = proxy1.buyFood1();
PublicInterface2 proxy2 = (PublicInterface2) dynamicProxyDemo.getProxy(new DynamicTarget2());
proxy2.buyFruit1();
至此 静态代理类跟动态代理类的实例到此为止,我们正常使用的还是动态代理类居多,实例讲完了,那我们剩下的就是针对动态代理类源码分析
动态代理源码分析
1.通过proxy获取动态代理对象
从上面的实例我们就知道 通过Proxy.newProxyInstance(...)就获取到了代理对象,所以很显然点击newProxyInstance这个方法查看就好了
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
//校验调用处理程序不为空,也就是InvocationHandler不为空
Objects.requireNonNull(h);
//拷贝对象(浅拷贝/深拷贝https://www.jianshu.com/p/94dbef2de298)
//https://www.jianshu.com/p/7034e9a8c2df
final Class<?>[] intfs = interfaces.clone();
Class<?> cl = getProxyClass0(loader, intfs);
try {
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
cons.setAccessible(true);
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
这块源码入口内容不多 很直观, Class<?> cl = getProxyClass0(loader, intfs);就是这个代码,后续的是基于类通过反射获取对象就完事了。
1.分析Class<?> cl = getProxyClass0(loader, intfs);
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces); (1)
}
2.上面代码先是对接口数做了一个判断,随后通过缓存方式去获取被代理类的class对象,接下来对proxyClassCache.get(loader, interfaces);的分析,贴上源码
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讲解:https://blog.csdn.net/qq_38023748/article/details/89188337
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)); (2)
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(); (6)
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); (3)
}
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); (4)
}
}
}
}
第(2)、(3)、(4)处是核心代码,先分析第(2)处,subKeyFactory.apply(key, parameter),subKeyFactory的初始化是在proxy.newInstance(xxx)的时候赋值的,是proxy类中的静态成员变量。
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
-------------------------------------------------------------------------
private static final class KeyFactory
implements BiFunction<ClassLoader, Class<?>[], Object>
{
@Override
public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
switch (interfaces.length) {
case 1: return new Key1(interfaces[0]); // the most frequent
case 2: return new Key2(interfaces[0], interfaces[1]);
case 0: return key0;
default: return new KeyX(interfaces);
}
}
}
--------------------
private static final class KeyX {
private final int hash;
private final WeakReference<Class<?>>[] refs;
@SuppressWarnings("unchecked")
KeyX(Class<?>[] interfaces) {
hash = Arrays.hashCode(interfaces);
refs = (WeakReference<Class<?>>[])new WeakReference<?>[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
refs[i] = new WeakReference<>(interfaces[i]);
}
}
4.通过调用了KeyFactory类中的apply方法 返回带有被代理类实现了接口的集合的对象。我们再回到第(2)处,然后继续往后走,因为第一次进来基本上数据源都为空,所以走到第(3)处。
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
}
-------------------
Factory(K key, P parameter, Object subKey,
ConcurrentMap<Object, Supplier<V>> valuesMap) {
this.key = key;
this.parameter = parameter;
this.subKey = subKey;
this.valuesMap = valuesMap;
}
5.上面第一次就factory存起来了同时会走到第(4处)代码 ,这就相当于先 存后拿了,下次进来就会走到第(6)处代码调用存下来的factory的get()方法
V value = supplier.get(); (6)
------------------
还是这个工厂
Factory(K key, P parameter, Object subKey,
ConcurrentMap<Object, Supplier<V>> valuesMap) {
this.key = key;
this.parameter = parameter;
this.subKey = subKey;
this.valuesMap = valuesMap;
}
@Override
public synchronized V get() { // serialize access
// re-check
Supplier<V> supplier = valuesMap.get(subKey);
if (supplier != this) {
// something changed while we were waiting:
// might be that we were replaced by a CacheValue
// or were removed because of failure ->
// return null to signal WeakCache.get() to retry
// the loop
return null;
}
// else still us (supplier == this)
// create new value
V value = null;
try {
value = Objects.requireNonNull(valueFactory.apply(key, parameter)); (7)
} finally {
if (value == null) { // remove us on failure
valuesMap.remove(subKey, this);
}
}
// the only path to reach here is with non-null value
assert value != null;
// wrap value with CacheValue (WeakReference)
CacheValue<V> cacheValue = new CacheValue<>(value);
// try replacing us with CacheValue (this should always succeed)
if (valuesMap.replace(subKey, this, cacheValue)) {
// put also in reverseMap
reverseMap.put(cacheValue, Boolean.TRUE);
} else {
throw new AssertionError("Should not reach here");
}
// successfully replaced us with new CacheValue -> return the value
// wrapped by it
return value;
}
我们就会走到第(7)处代码 此时对象是成员变量的ProxyClassFactory工厂,进入这个工厂进去看看
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
-------------------------------------------------------------------------
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// prefix for all proxy class names
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*/
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
/*
* Verify that the Class object actually represents an
* interface.
*/
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
*/
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
*/
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// if no non-public proxy interfaces, use the default package.
proxyPkg = "";
}
{
// Android-changed: Generate the proxy directly instead of calling
// through to ProxyGenerator.
List<Method> methods = getMethods(interfaces);
Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
validateReturnTypes(methods);
List<Class<?>[]> exceptions = deduplicateAndGetExceptions(methods);
Method[] methodsArray = methods.toArray(new Method[methods.size()]);
Class<?>[][] exceptionsArray = exceptions.toArray(new Class<?>[exceptions.size()][]);
/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
return generateProxy(proxyName, interfaces, loader, methodsArray,
exceptionsArray); (8)
}
}
}