昨天面试碰到了面试官问spring的时候,问完ioc,然后下个问题我以为是aop,后来才听清是动态代理,感觉回答的不是太好,也是好久不接触
1.静态代理
代理模式也就委托模式。
三个角色:
- Subject抽象主题角色:接口
- RealSubject具体主题角色:接口的实现类,业务逻辑的具体执行者
- Proxy代理主题角色:也叫做委托类,代理类。它负责对真实角色的应用,负责真实角色前后前后做预处理和善后处理。
在这里面Subject是一个借口,里面有一个Request()方法,RealSubject类实现了Subject这个接口,并且实现了request()方法,而在Proxy也实现了Subject接口,proxy里面还有一个变量Subject,可以通过构造函数将RealSubject注入,在实现request方法时,其实是调用的是Realsubject里面的request方法,在调用request()方法前后可以调用一些其他的方法。
下面是具体的代码
Subject.java
public interface Subject {
//定义一个方法
public void request();
}
RealSubject.java
public class RealSubject implements Subject {
@Override
public void request() {
//业务逻辑处理
}
}
Proxy.java
public class Proxy implements Subject {
private Subject subject = null;
public Proxy(Subject subject){
this.subject = subject;
}
@Override
public void request() {
before();
subject.request();
after();
}
public void before(){
//do something
}
public void after(){
//do something
}
}
代理模式的使用场景
为什么要使用代理呢?想想现实世界吧,打官司为什么要找个律师?因为你不想参与中间过程的是是非非,只要完成自己的答辩就行了,其他的比如事前调查、事后调查都由律师搞定,这就是为了减轻你的负担。代理模式的使用场景非常多,可以看见Spring aop,这是非常典型的动态代理
二:动态代理
动态代理是在实现阶段不用关心代理谁,而在运行阶段才指定代理哪一个对象。相对来说,自己写代理类的方式就叫静态代理
划重点,在运行阶段指定哪一个对象
具体代码,逻辑待会再说
抽象主题
public interface Subject {
/**
* //业务操作
* @param str
*/
void doSomething(String str);
/**
* 吃
* */
void eat(String str);
}
真实主题
public class RealSubject implements Subject {
@Override
public void doSomething(String str) {
System.out.println("do something!---->" + str);
}
@Override
public void eat(String str) {
System.out.println("今天晚上吃"+str);
}
}
动态代理的handler类
public class MyInvocationHandler implements InvocationHandler {
/**
* 被代理的对象
*/
private Object target;
public MyInvocationHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//log Before
System.out.println("log before:"+"method: "+method.getName()+ "return :"+method.getReturnType().getSimpleName());
Object result = method.invoke(target,args);
System.out.println("log after: "+new Date(System.currentTimeMillis()));
return result;
}
}
动态代理类
public class DynamicProxy<T> {
public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler){
//返回目标,并返回结果
return (T) Proxy.newProxyInstance(loader,interfaces,handler);
}
}
动态代理的场景类
public class Client {
public static void main(String[] args) throws IOException {
//定义一个代理类
Subject subject = new RealSubject();
//定义一个Handler
InvocationHandler handler = new MyInvocationHandler(subject);
//定义主题的代理
Subject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(),handler);
//代理的行为
System.out.println(proxy.getClass().getCanonicalName());
proxy.doSomething("finish");
proxy.eat("香锅里辣家的麻辣香锅");
//此处可以将
byte[] proxyClass = ProxyGenerator.generateProxyClass(proxy.getClass()
.getSimpleName(), proxy.getClass().getInterfaces());
//将字节码文件保存到D盘,文件名为$Proxy0.class
FileOutputStream outputStream = new FileOutputStream(new File(
"d:\\$Proxy0.class"));
outputStream.write(proxyClass);
outputStream.flush();
outputStream.close();
}
}
分析过程:
Subject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(),handler);
在我们使用proxy.doSomthing(args);
proxy.eat(args);
我们可以想象出,DynamicProxy.newProxyInstance(args)这个方法返回了一个proxy对象
我们可以看到是调用了这个方法
newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
// 此处就讲class生成好了
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
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);
}
}
最后这个方法会在运行中生成一个
类,名字叫:com.sun.proxy.$Proxy0
而我们并没有找到这个类,可以通过我们上面的Client里面的将这个运行中生成的类打印出来,我们来看看,这个类是什么样子的
$Proxy0.class,反编译
public final class $Proxy0 extends Proxy implements Subject {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
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 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 doSomething(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 void eat(String var1) throws {
try {
super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
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"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.husky.dynamicproxy.Subject").getMethod("doSomething", Class.forName("java.lang.String"));
m4 = Class.forName("com.husky.dynamicproxy.Subject").getMethod("eat", Class.forName("java.lang.String"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
首先$Proxy0这个类extends Proxy implements Subject
有一个静态代码块,会反射生成Method类,也就是给 $Proxy这个类的变量赋值
举例我在调用proxy.doSomething()这个方法时
我们其实是调用
public final void doSomething(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);
}
}
调用的是super.h.invoke(this, m3, new Object[]{var1});
这个h也就是实现InvocationHandler接口的MyInvocationHandler类。将这个$Proxy0,m3, new Object[]{var1}这些变量传过去
博客也会发布在博客园,博客园的博客都会是非常认真的,而不像csdn一样杂乱
具体代码:https://github.com/pompeii666/proxy
这篇博客耗时,一周,断断续续,白天工作回来,吃个饭,洗个澡,就想睡觉。