一、什么是代理?
代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
二、静态代理
- 使用组合方式实现静态代理;
interface Movie {
void play();
}
public class RealMovie implements Movie {
@Override
public void play() {
System.out.println("看电影。。。。。");
}
}
public class MovieProxy implements Movie {
private Movie movie;
public MovieProxy(Movie movie) {
this.movie = movie;
}
@Override
public void play() {
System.out.println("看电影前先买票。。。。");
movie.play();
}
}
public class MovieTest {
public static void main(String[] args) {
Movie proxy = new MovieProxy(new RealMovie());
proxy.play();
/**
* 看电影前先买票。。。。
* 看电影。。。。。
*/
}
}
三、动态代理使用案例(jdk方式)
public interface WorkInterface {
void toWork();
void toWork2();
}
public class Engineer implements WorkInterface{
@Override
public void toWork() {
System.out.println("工程师开始工作了。。。。。。。。。");
}
@Override
public void toWork2() {
System.out.println("工程师开始工作了2222。。。。。。。。。");
}
}
public class WorkInvocationHandle implements InvocationHandler {
private Object obj;
public WorkInvocationHandle(Object obj) {
this.obj = obj;
}
/**
*
* proxy:代表动态代理对象
* method:代表正在执行的方法
* args:代表调用目标方法时传入的实参
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("进入代理,执行增强方法");
Object invoke = method.invoke(obj, args);//执行被代理的方法
return invoke; //返回结果
}
}
public class JkdProxy {
public static void main(String[] args) {
//开启动态代理的文件输出
// 代理class的生成路径是在idea的工作空间下的 com\sun\proxy 目录中
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
//创建代理类
WorkInterface proxy = (WorkInterface) Proxy.newProxyInstance(JkdProxy.class.getClassLoader(), Engineer.class.getInterfaces(), new WorkInvocationHandle(new Engineer()));
proxy.toWork();
proxy.toWork2();
/**
* 进入代理,执行增强方法
* 工程师开始工作了。。。。。。。。。
*/
}
}
Proxy.newProxyInstance
方法我们需要注意的参数:
第一个参数ClassLoader loader:类的加载器,传入我们自定义类的加载器
第二个参数Class<?>[] interfaces 注意很重要 这个参数是传入一个接口数组
第三个参数 h:类型是InvocationHandler,传入InvocationHandler接口的子类
在调用过程中特别注意:
Class<?> cl = getProxyClass0(loader, intfs);
调用了getProxyClass0方法, 该方法 需要传入两个参数 一个是类加载器,一个是接口数组
在方法getProxyClass0 中 会创建出一个类$Proxy0 ,并且创建出这个内部类的引用返回
我通过生出的内部类文件,反编译出源码可以看下:
package com.sun.proxy;
import com.ganyz.demo.jdkproxy.WorkInterface;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements WorkInterface {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void toWork2() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void toWork() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.ganyz.demo.jdkproxy.WorkInterface").getMethod("toWork2");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.ganyz.demo.jdkproxy.WorkInterface").getMethod("toWork");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
- 注意:我们可以发现这个生成的类继承了proxy 并且实现了我自己定义的那个接口,我们可以设置
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true")
在磁盘上写代理类;
四、代理源码解析
https://www.nhooo.com/note/qagnkd.html
https://my.oschina.net/u/4613350/blog/4810435