首先静态代理写法和装饰器模式非常像,只是概念分的很细,本质是没有区别,都是用“真正干活”的类去实现方法,代理只是套了一层壳。
第一步抽象接口
public interface Movable {
void move();
}
第二步实现抽象接口(真正干活的类)
public class Subject implements Movable{
@Override
public void move() {
System.err.println("实现移动的具体实例Subject");
}
}
第三步,新建一个类,携带具体干活的Subject类,(用别人的手去抓蛇)
public class AProxySubject {
private Subject subject;
public AProxySubject(Subject subject) {
this.subject = subject;
}
@Override
public void move() {
System.err.println("proxy log before AAA");
subject.move();
System.err.println("proxy log before AAA");
}
}
第四步,写一个场景类测试
public class Client {
public static void main(String[] args) {
aProxySubject= new AProxySubject(
new Subject()
);
aProxySubject.move();
}
}
新增需求:现在想在旧的基础上再套一层代理,或者套N层代理即场景类如下:
public class Client {
public static void main(String[] args) {
BProxySubject bProxySubject =
new BProxySubject(
new AProxySubject(
new Subject()
)
);
bProxySubject.move();
}
}
这时候代理类可以把旧的Subject 换成Subject 的父类 Movable,这时候变为:
public class AProxySubject {
private Movable subject;
public AProxySubject(Movable subject) {
this.subject = subject;
}
@Override
public void move() {
System.err.println("proxy log before AAA");
subject.move();
System.err.println("proxy log before AAA");
}
}
看构造器知道,也就是构建代理类,需要准备Movable subject 这个材料,那么我自己也是可以变成这块的材料啊,所以在改下(自己也实现Movable)
public class AProxySubject implements Movable{
private Movable subject;
public AProxySubject(Movable subject) {
this.subject = subject;
}
@Override
public void move() {
System.err.println("proxy log before AAA");
subject.move();
System.err.println("proxy log before AAA");
}
}
然后同样造出B代理类
public class BProxySubject implements Movable {
private Movable subject;
public BProxySubject(Movable subject) {
this.subject = subject;
}
@Override
public void move() {
System.err.println("proxy log before BBB");
subject.move();
System.err.println("proxy log before BBB");
}
}
最后验证Client:
public class Client {
public static void main(String[] args) {
BProxySubject bProxySubject =
new BProxySubject(
new AProxySubject(
new Subject()
)
);
bProxySubject.move();
}
}
新增需求:现在把上面实现的静态代理,换另一种比较灵活写法,用Proxy来写
第一步,照常提供接口,和具体干活类
public interface Movable {
void move();
}
public class Tank implements Movable{
@Override
public void move() {
System.err.println("我是具体实例TAnk");
}
}
第二步,提供场景测试类
public class Client {
public static void main(String[] args) {
//首先开启proxy类生成,动态代理通过ASM会生成一个类,一般来讲,我们写 JAVA,写完编译后就是一个class类,动态代理是电脑帮我们写了一个类
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
}
(上面代码完整后,会出现如下图目录和文件)
![](https://img.haomeiwen.com/i15527691/60a45d2da3339314.png)
![](https://img.haomeiwen.com/i15527691/a553f56ebf66f54c.png)
接着继续完善上面代码
public class Client {
public static void main(String[] args) {
//首先开启proxy类生成,动态代理通过ASM会生成一个类,一般来讲,我们写 JAVA,写完编译后就是一个class类,动态代理是电脑帮我们写了一个类
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
Movable m = (Movable)Proxy.newProxyInstance(Tank.class.getClassLoader(), new Class[]{Movable.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//第一个参数是生成的代理对象,也就是m,基本没用上
System.err.println("代理前");
//持有具体类
//具体类返回什么类型就返回什么类型
Object o = method.invoke(new Tank(), args);
System.err.println("代理后");
return o;
}
});
//准备完成后测试move
m.move();
}
这里重点讲Proxy.newProxyInstance 这个方法它有三个参数:
第一个参数是类加载器,他是把生成的$proxy0.class 加载到内存,不然你怎么使用呢,一般选择和被代理类相同的加载器就可以了。
第二个参数指定生成的proxy0.class 需要实现的接口
第三指定proxy0.class 内部使用的InvocationHandler的具体实现方法,因为他以后要使用这个方法。
这里重点讲InvocationHandler,它重写了一个方法:
public Object invoke(Object proxy, Method method, Object[] args),
第一个参数他是生成代理对象,也就是$proxy0.class,基本没什么用
第二个参数Method method,也就是接口方法,他是没有实现的,代理才不会自己干活,看上面程序可以知道最后还是要放一个真正干活的类进去,这个方法会返回一个对象Object o, 这个是和真正干活对象返回类型一致,是什么他就是什么类型,这里是Void
第三个参数是方法参数,具体干活的类是什么他就是什么
Proxy.newProxyInstance 前面有个强转Movable,因为你看上面的$proxy0,他本身就实现了Movable这个接口,当然可以强转了
![](https://img.haomeiwen.com/i15527691/01e18268db171138.png)
上面的h.invoke(),就是我们在场景类Client匿名函数实现的invoke
新增需求:假设我没有接口我该怎么实现,我就只有一个普通类这时候就用CGLIB
非常普通的一个类(不能在普通了)
public class Tank {
public void move(){
System.err.println("mov mov mov");
}
}
新增场景类(我把导入的包也贴出来)
package cn.xqrcloud.mypattern.代理模式.动态代理.v2;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 🐌🐌🐌🐌🐌🐌🐌🐌🐌🐌🐌🐌道阻且长,行则将至🐌🐌🐌🐌🐌🐌🐌🐌🐌🐌🐌🐌
* 🍁 Program: mypattern
* 🍁 Description
* 🍁 Author: Stephen
* 🍁 Create: 2020-07-29 00:31
* 🐌🐌🐌🐌🐌🐌🐌🐌🐌🐌🐌🐌行而不辍,未来可期🐌🐌🐌🐌🐌🐌🐌🐌🐌🐌🐌🐌
**/
public class Client {
public static void main(String[] args) {
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(Tank.class);//设置父类
//enhancer.setCallback(new MyInvocationHandler());//相当于InvocationHandler
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//第一个参数继承Tank的类
System.err.println("开始之前");
Object result = method.invoke(new Tank(), objects);
// Object result = methodProxy.invokeSuper(o, objects);
System.err.println("开始之后");
return result;
}
});
Tank tankimpl = ((Tank) enhancer.create());
tankimpl.move();
}
}
第一步新增一个Enhancer 增强类,接着我把Tank 当接口或者父类(接口启示相当于父类了),接着实例一个以tank为接口的代理类tankimpl ,执行move方法,
而且move方法里面要用到类似InvocationHandler的东西,这里叫MethodInterceptor
所以在创建具体的tankimpl 之前,要把这个材料准备好,执行 enhancer.setCallback(...)
网友评论