前言:静态代理和动态代理是一种编程风格、编程范式,也叫设计模式
- 静态代理
public class StaticProxy implements Service{
public static void main(String[] args) {
StaticProxy staticProxy=new StaticProxy(new DefaultService());
staticProxy.show();
}
private Service service;
public StaticProxy(Service service){
this.service=service;
}
@Override
public void show() {
System.out.println("Before");
service.show();
System.out.println("After");
}
}
interface Service{
void show();
}
class DefaultService implements Service{
@Override
public void show() {
System.out.println("here is default show");
}
}
2、 动态代理
public class JdkDynamicProxy {
public static void main(String[] args) {
byte[] bytes = ProxyGenerator.generateProxyClass("$ProxyDao", new Class[]{Dao.class});
try {
FileOutputStream out = new FileOutputStream("C:\\Users\\23317\\Desktop\\$ProxyDao.class");
out.write(bytes);
} catch (Exception ex) {
}
Object proxy = Proxy.newProxyInstance(JdkDynamicProxy.class.getClassLoader(),
new Class[]{Dao.class}, new DaoInvocationHandler());
Dao dao = (Dao) proxy;
dao.insert("qyd");
}
}
interface Dao {
void insert(String name);
}
class DaoImpl implements Dao {
@Override
public void insert(String name) {
System.out.println("insert->" + name);
}
}
class DaoInvocationHandler implements InvocationHandler {
private Dao dao = new DaoImpl();
/**
* @param proxy 生成的$ProxyDao类的对象
* @param method $ProxyDao类实现的接口的对应方法
* @param args $ProxyDao类实现的接口的对应参数,用户传进来的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before");
method.invoke(dao, args);
System.out.println("After");
return null;
}
}
public final class $ProxyDao extends Proxy implements Dao {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $ProxyDao(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 insert(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
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 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"));
m3 = Class.forName("club.qydqyj.aop.Dao").getMethod("insert", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
总结:
1、动态代理即jdk帮我们实现了类,按照静态原理代码编写范式,动态代理的类也实现了接口
2、动态代理的类继承了Jdk的Proxy类,这也是jdk动态代理是基于接口的原因,因为java是单继承原则
3、动态代理类不但实现了接口的所有方法,也重写了Object类的equals、hashcode、toString方法
4、按照静态代理的代码编写范式,还需要实现了接口的类作为动态代理类的成员属性,以此来调用真正实现接口的方法。首先需要知道要代理的类应该由用户定义的,如果java设计成动态代理类为需要传进去所有接口的实现类作为参数交给java生成动态代理类,这样虽然也可以,但是显然有点设计过度。所以java设计了InvocationHandler
类,java生成的动态代理类的所有重写方法都只调用InvocationHandler#invoke(Object proxy, Method method, Object[] args)
方法,把真正接口实现的代码编写交给用户实现,这样明显更合理。
5、InvocationHandler#invoke(Object proxy, Method method, Object[] args)方法参数列表:proxy是java生成的动态代理类;method是接口方法和equals、hashcode、toString方法,args是用户传进去某方法的参数。
上帝视觉:
//1
Object proxy = Proxy.newProxyInstance(JdkDynamicProxy.class.getClassLoader(),
new Class[]{Dao.class}, new DaoInvocationHandler());
//2
Dao dao = (Dao) proxy;
//3
dao.insert("qyd");
1中的proxy就是Java生成的动态代理类,其实就是上面的$ProxyDao类的对象,这个类实现了接口Dao,当调用insert方法的时候,会调用重写的InvocationHandler类的方法,在这个方法里面,我们可以通过method对象知道当前正在哪个方法上,然后就可以通过method#invoke(要代理的类,args)调用真正实现接口的方法。这里有一个疑惑?为什么InvocationHandler#invoke方法参数会有proxy对象,由上面可以知道这个对象是java生成的动态代理类的对象,想不到有什么场景可以用到它?