这是我参与更文挑战的第6天,活动详情查看: 更文挑战
所谓动态代理,简单来说,其实就是在程序运行期间,动态地生成一个代理对象来实现对目标对象方法的增强。可以简单粗暴的理解为 代理对象 = 目标对象 + 增强代码
在讲动态代理之前,我们先来看下静态代理。
一、静态代理
我们举一个例子来说,假设每个单身的朋友都有谈恋爱求偶的技能,那么我们可以定义一个单身汉的接口,然后这个接口有一个求偶的方法如下:
public interface SingleDog {
String courtShip();//恋爱求偶结婚技能
}
然后我们的主角小王毕业五年,虽然至今单身,但是很幸运地也拥有了这项技能。
public class DogWang implements SingleDog {
@Override
public String courtShip() {
return "宝,我今天过马路了,过的什么路,爱你没有退路";
}
}
我们都知道小王有了谈恋爱的方法,但是平时作为一个社畜,上下班两点一线,一直苦于没有遇到一个合适的女孩子来施展自己的这项技能。同时这个年纪单身未婚,可把家里的王妈急坏了,赶紧介绍了朋友的女儿小宁给儿子认识。好了,这里的王妈就是我们的代理对象
public class WorryMom implements SingleDog {
private DogWang dogWang;
public WorryMom(DogWang dogWang) {
this.dogWang = dogWang;
}
@Override
public String courtShip() {
//介绍小宁给儿子认识
System.out.println("this is miss ning's wechat");
String honeyWord = dogWang.courtShip();
//耐心嘱咐儿子多联系
System.out.println("if you fail,get the fu** out of my home");
return honeyWord;
}
}
王妈作为代理对象,并不会实际去谈恋爱。而是通过构造方法传入小王,可以理解为带小王去见小宁。最终真正去谈恋爱的还是我们的主角小王。但是妈妈的嘱托一定程度上帮助小王更好地完成这项任务
静态代理的弊端
事实上王妈可能不止小王这一个儿子,那么她每新增一个儿子,都需要去增加硬编码,这之间有很强的耦合性,维护起来肯定是很麻烦的。
二、动态代理
相信通过上面的例子我们都能很清晰地理解静态代理,那么动态代理呢?
JDK提供了java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy类,这两个类来相互配合实现我们的动态代理。
Proxy中有个静态方法getProxyClass,用来获取接口的代理对象
public static void main(String[] args) throws Exception {
//获取接口的代理class对象 参数1是对应的类加载器,参数2是对应接口
Class<?> proxyClass = Proxy.getProxyClass(SingleDog.class.getClassLoader(), SingleDog.class);
//获取对应的有参构造器
Constructor<?> constructor =proxyClass.getConstructor(InvocationHandler.class);
SingleDog dogWang = (SingleDog) constructor.newInstance(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//invoke中没有目标对象,手动new一个
DogWang dogWang = new DogWang();
System.out.println("this is miss ning's wechat");
Object invoke = method.invoke(dogWang, args);
System.out.println("if you fail,get the fu** out of my home");
return invoke;
}
});
dogWang.courtShip();
}
上述代码的invoke方法中没有目标对象,只能手动new一个小王出来,这种硬编码的方式肯定不行。我们可以把目标对象作为参数,写一个方法专门用来获取代理class对象。如下:
public static Object getProxy(final Object target) throws Exception {
//获取接口的代理class对象
Class<?> proxyClass = Proxy.getProxyClass(target.getClass().getClassLoader(), target.getClass().getInterfaces());
//获取对应的有参构造器
Constructor<?> constructor = proxyClass.getConstructor(InvocationHandler.class);
Object proxy = constructor.newInstance(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("this is miss ning's wechat");
Object invoke = method.invoke(target, args);
System.out.println("if you fail,get the fu** out of my home");
return invoke;
}
});
return proxy;
}
调用时传入目标对象即可:
public static void main(String[] args) throws Exception {
SingleDog singleDog = (SingleDog) getProxy(new DogWang());
singleDog.courtShip();
}
这样其实就已经完美的实现了jdk的动态代理了,不过在日常使用中,一般是使用Proxy的另外一个方法来实现,Proxy#newProxyInstance。
这种方法更简洁地实现了动态代理。如下:
public static Object getProxy(final Object target) throws Exception {
Object instance = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("this is miss ning's wechat");
Object invoke = method.invoke(target, args);
System.out.println("if you fail,get the fu** out of my home");
return invoke;
}
});
return instance;
}
今天是和喜欢的人断联的整四个月,看不清将来的路,有时候会觉得很痛苦,害,还是要埋头往前走啊。
希望每个人都可以在冷铁卷刃之前,得以窥见天光吧。
以上,谢谢你看到这。