代理模式的本质:监控行为特征
JDK动态代理实现
1.接口角色:定义所有需要被监听行为
2.接口实现类:定义实现被监听对象
3.通知类:
1)对次要业务进行具体实现
2)通知JVM,当前被拦截的主要业务方法与次要业务方法应该如何绑定
4.监控对象(代理对象)
1)被监控实例对象
2)需要被监控的行为
3)具体通知类实例对象
代码实现
1.定义一个要监控的行为—>接口
public interface Eat {
/**
* 某种生物吃东西
* @param something
*/
void eat(String something);
}
2.定义实现接口的实例
public class Person implements Eat {
@Override
public void eat(String something) {
System.out.println("我吃" + something);
}
}
3.通知jvm需要拦截的方法—>实现InvocationHandler
public class Invocation implements InvocationHandler {
public Invocation(Object object) {
this.object = object;
}
private Object object;
/***
* 这个方法就是要告诉代理对象要处理的方法
*
* @param proxy 代理对象
* @param method 实例对象要调用的方法
* @param args 实例对象要调用的方法的参数
* @return Object
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (object instanceof Person){
wash();
}else if(object instanceof Dog){
sound();
}
return method.invoke(object, args);
}
private void wash(){
System.out.println("我是人,我要洗手");
}
private void sound(){
System.out.println("我是狗,汪汪汪");
}
}
4.创建代理对象
public static Object getInstance(Class clz) throws IllegalAccessException, InstantiationException {
/**
*
* ClassLoader loader, 被代理类的加载器
* Class<?>[] interfaces, 被代理类的所有接口
* InvocationHandler h 调用的处理器
*
* return 代理对象
*/
Object object = Proxy.newProxyInstance(clz.getClassLoader(), clz.getInterfaces(), new Invocation(clz.newInstance()));
return object;
}
Proxy.newProxyInstance方法解析
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException{
//判断InvocationHandler对象是否为空
Objects.requireNonNull(h);
//获取接口的克隆对象
final Class<?>[] intfs = interfaces.clone();
//获取安全管理对象,一般为空
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
//通过类加载器和接口去找或者生成接口对应的代理类
Class<?> cl = getProxyClass0(loader, intfs);
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
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);
}
}
//解析真正获取代理对象的方法
private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
//这里似乎是从缓存中拿到了数据,继续往下看
return proxyClassCache.get(loader, interfaces);
}
// 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<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;
}
}
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
supplier = factory;
}
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
JDK动态代理特点
1.实现InvocationHandlder接口
2.通过Proxy.newProxyInstance方法创建代理对象
3.被代理的对象必须实现接口