1,代理模式
2012年8月,在伦敦奥运会乒乓球男单决赛中,张继科以4-1战胜王皓夺得冠军;同时,他也实现了世锦赛、世界杯、奥运会三项冠军的大满贯,成为在中国男乒历史上继刘国梁和孔令辉之后的第三位大满贯选手。
作为一名职业运动员,毫无疑问 他的能力非常厉害 一直都是我的偶像
他的乒乓球技术非常高超,但是他因为要参加日常的训练,所以没有多余的时间来管理日常琐事。
所以张继科会找一个人来帮助他专门处理这一类事务,我们称呼这个人为-经纪人
1.1 静态代理
首先我们创建一个接口,定义张继科的一些能力
public interface Ability {
// 比赛
public abstract void game();
// 日常
public abstract void daily();
// 代言
public abstract void endorsement();
}
接下来创建我们的张继科
// 张继科
public class ZhangJike implements Ability{
@Override
public void game() {
System.out.println("张继科 参加一场奥林匹克运动会乒乓球总决赛 痛失亚军,含泪夺冠");
}
@Override
public void daily() {
System.out.println("张继科 与粉丝互动切磋,向福利院捐赠了乒乓运动器械,并和兴奋的小球迷爱心互动 进行高强度的训练");
}
@Override
public void endorsement() {
System.out.println("张继科 代言 华润怡宝矿泉水等品牌");
}
}
紧接着创建张继科的经纪人
// 经济人
public class ProxyPerson implements Ability{
ZhangJike zjk;
public ProxyPerson(ZhangJike zjk){
this.zjk = zjk;
}
@Override
public void game() {
System.out.println("安排往返机票,酒店住宿");
zjk.game();
}
@Override
public void daily() {
System.out.println("安排近期的事务");
zjk.daily();
}
@Override
public void endorsement() {
System.out.println("与一些企业签约代言");
zjk.endorsement();
}
}
最后我们创建一个环境类 测试一下静态代理
// 测试 静态代理
public class TestPro {
public static void main(String[] args) {
ZhangJike zhangJike = new ZhangJike();
ProxyPerson proxyPerson = new ProxyPerson(zhangJike);
proxyPerson.daily();
proxyPerson.endorsement();
proxyPerson.game();
}
}
打印结果如下:
1.2 动态代理
随着张继科的`经纪人`越来越厉害,找他当`经纪人`的运动员们越来越多,当然 我们的`男足`也来找他当`经纪人`。
这个`经纪人`非常厉害,不管你有什么能力都可以给你安排的妥妥当当
此时,我们创建这个`经纪人`就可以使用`反射`的方法就可以实现——反射
通过反射创建更厉害的经纪人
public class MyInvocationHandler implements InvocationHandler {
//这是动态代理的好处,被封装的对象是Object类型,接受任意类型的对象
private Object object;
/*
parameter: 实例化被代理的对象
return: 返回代理类对象
*/
public Object Binding(Object object){
this.object = object;
/**
* param1 -> loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
*
* param2 -> interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,
* 如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),
* 这样我就能调用这组接口中的方法了
* param3 -> h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
*/
return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是一个万能经纪人,什么都能给你安排得妥妥当当!");
// 这里的参数为什么为 this.object , 之后进行讲解
return method.invoke(this.object,args);
}
}
创建我们的男足
// 男足能力接口
public class MaleFoot implements Ability {
@Override
public void game() {
System.out.println("提前杀入本届亚洲杯");
}
@Override
public void daily() {
System.out.println("优秀射手-武磊");
}
@Override
public void endorsement() {
System.out.println("... nothing");
}
}
测试动态代理
// 测试
public class TestPro {
public static void main(String[] args) {
// 动态代理
MaleFoot maleFoot = new MaleFoot();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
Ability binding = (Ability) myInvocationHandler.Binding(maleFoot);
binding.daily();
binding.endorsement();
binding.game();
}
打印结果如下:
1.3 invoke
接下来讲解一下关于 InvocationHandler 的 invoke 方法
大家可能都有一个疑问
我们从始至终都没有调用过 invoke 方法,为什么它会被执行呢?
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是一个万能经纪人,什么都能给你安排得妥妥当当!");
return method.invoke(this.object,args);
}
这里我们从 newProxyInstance 的方法开始入手
return Proxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(),this);
首先 我们进入源码
/**
*loader -> 定义代理类 proxy class
*interfaces -> 代理类实现的接口列表
*h -> 调用方法调用的调用处理程序
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
// 判断 h 是否为null 如果为null 则抛出 NullPointerException();
Objects.requireNonNull(h);
// 克隆接口列表
final Class<?>[] intfs = interfaces.clone();
// 获取安全管理器
/**
*当运行未知的Java程序的时候,该程序可能有恶意代码(删除系统文件、重启系统等),为了防止运行恶意代码对系统产生影响,需要对运行的代码的权限进行控制,这时候就要启用Java安全管理器。
*/
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
查找或生成指定的代理类。
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
使用指定的调用处理程序调用其构造函数。
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
/**
cons即是形参为InvocationHandler类型的公共构造方法
private static final Class<?>[] constructorParams =
{ InvocationHandler.class };
*/
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;
}
});
}
// 获取cons的实例
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);
}
}
以下的部分内容参考了网络上的内容,在此对原作者表示感谢!
至此我们得知,newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) 这个方法做了一下两个操作:
1.根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)创建代理类$Proxy0.$Proxy0类 实现了interfaces的接口,并继承了Proxy类.
2.实例化$Proxy0并在构造方法中把DynamicSubject传过去,接着$Proxy0调用父类Proxy的构造器,为h赋值,
如下:
class Proxy{
InvocationHandler h=null;
protected Proxy(InvocationHandler h) {
this.h = h;
}
...
}
来看一下这个继承了Proxy的$Proxy0的源代码:
public final class $Proxy0 extends Proxy implements Subject {
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals",
new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode",
new Class[0]);
m3 = Class.forName("***.RealSubject").getMethod("request",
new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString",
new Class[0]);
} catch (NoSuchMethodException nosuchmethodexception) {
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
} catch (ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
} //static
public $Proxy0(InvocationHandler invocationhandler) {
super(invocationhandler);
}
@Override
public final boolean equals(Object obj) {
try {
return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final int hashCode() {
try {
return ((Integer) super.h.invoke(this, m0, null)).intValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void request() {
try {
super.h.invoke(this, m3, null);
return;
} catch (Error e) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final String toString() {
try {
return (String) super.h.invoke(this, m2, null);
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
}
接着把得到的$Proxy0实例强制转换成Subject,并将引用赋给subject。当执行subject.request()方法时,就调用了$Proxy0类中的request()方法,进而调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke()。
注: 在一位神秘大佬的帮助下,我们终于明白了proxy参数的作用了
在上图中,程序通过newProxyInstance方法将我们的binding类转换成了代理类 proxy。
具体操作如下:
接着把得到的$Proxy0实例强制转换成Subject,并将引用赋给subject。当执行subject.request()方法时,就调用了$Proxy0类中的request()方法,进而调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke()。
ps: 在此由衷感谢神秘大佬提供的帮助
2.4 AOP动态代理
定义接口
// 定义插入类的接口
public interface Insert {
public abstract void ist();
}
实现接口
public class InsertImpl implements Insert {
@Override
public void ist() {
System.out.println("我是被插入的代码片段!!!");
}
}
定义被插入类的方法
public class Code {
public void method1(){
System.out.println("============== 方法1 =============");
}
public void method2(){
System.out.println("============== 方法2 =============");
}
}
创建其子类
public class Section extends Code {
public void method1(){
System.out.println("子类 ============== 方法1 =============");
}
}
实现切面代理
public class MyInvocationHandlerAop implements InvocationHandler {
private Object object;
/*
parameter: 实例化被代理的对象
return: 返回代理类对象
*/
public Object Binding(Object object){
this.object = object;
/**
* param1 -> loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
*
* param2 -> interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,
* 如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),
* 这样我就能调用这组接口中的方法了
* param3 -> h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
*/
return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 多态
Code code = new Section();
code.method1();
Object invoke = method.invoke(this.object, args);
code.method2();
return invoke;
}
}
创建环境类
// 测试aop动态代理
public class TestProAop {
public static void main(String[] args) {
InsertImpl insert = new InsertImpl();
MyInvocationHandlerAop myInvocationHandlerAop = new MyInvocationHandlerAop();
Insert binding = (Insert) myInvocationHandlerAop.Binding(insert);
binding.ist();
}
}
打印结果如下:
同理,插入我们的其他类也可以
// 测试aop动态代理
public class TestProAop {
public static void main(String[] args) {
InsertImpl insert = new InsertImpl();
MyInvocationHandlerAop myInvocationHandlerAop = new MyInvocationHandlerAop();
Ability binding = (Ability) myInvocationHandlerAop.Binding(zhangJike);
binding.endorsement();
System.out.println();
binding.daily();
System.out.println();
binding.game();
}
}
打印结果如下:
通过以上的方法就能够动态切入我们所需添加的代码啦
{\__/} {\__/}
( ·-·) (·-· )
/ >------------------------------------------------< \
| ☆ |
| ☆ |
| ★ |
| ☆ |
| ☆ |
| |
-------------------------------------
如有兴趣可以关注我的公众号: