代理模式
作用:
- AOP 实现
- 拦截器
- 中介
- 黄牛
- 媒婆
- 解耦
- 专人做专事
- 自己不想做,又不得不做的事
- 增强
代理:
-
静态代理
-
动态代理
角色
- 代理角色
- 被代理的角色(目标对象)
由被代理的角色来做最终的决定
代理角色通常来说会持有被代理角色对象引用(以便于代理角色完成工作之前或者之后能够找到被代理的对象,能够通知被代理对象)
静态代理动态代理的区别:
静态代理:
在代理之前所有的东西都是已知的(人工)
动态代理:
在代理之前,所有的东西都是未知的(自动化,智能化)
总结:
静态代理:
没办法拓展
JKD动态代理的原理
- 拿到被代理的对象的引用,并且获取到它的所有接口,反射获取
- JDK Proxy 类重新生成一个新的类,同时新的类要实现被代理类的所有实现
- 动态的生成 Java 代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体现)
- 编译新生成的 Java 代码, .class
- 再重新加载到 JVM 中运行
以上这个过程就叫字节码重组, JDK 中有个规范,只要是 $
开头的一般都是自动生成的。通过反编译工具可以查看源代码。
手写动态代理的原理
- 动态生成源代码 .java 文件
- JAVA 文件输出到磁盘
- 把 .java 文件编译成 .class 文件
- 编译生成的 .class 文件加载到 JVM 中,
- 返回字节码重组以后的新的代理对象
代码:
静态代理:
Person.class
public interface Person {
void findLove();
void zuFangZi();
void buy();
void findJob();
}
Son.class
public class Son implements Person {
public void findLove() {
// 我没有时间
// 工作忙
System.out.println(">>>>>找对象:肤白,貌美,大长腿");
}
public void zuFangZi() {
}
public void buy() {
}
public void findJob() {
}
}
Father.class
public class Father {
private Person person;
// 没办法拓展
public Father(Person person) {
this.person = person;
}
// 目标对象的引用给拿到
public void findLove(){
System.out.println("根据你的要求物色");
this.person.findLove();
System.out.println("双方父母是不是同意");
}
}
StaticProxyTest.class
public class StaticProxyTest {
public static void main(String[] args) {
// 只能帮儿子找对象
// 不能帮表妹、陌生人
Father father = new Father(new Son());
father.findLove();
}
}
JDK:
XieMu.class
public class XieMu implements Person {
public void findLove(){
System.out.println(">>>>>高富帅");
System.out.println(">>>>>身高180");
System.out.println(">>>>>胸大,6块腹肌");
}
public void zuFangZi() {
System.out.println(">>>>>租房子");
}
public void buy() {
System.out.println(">>>>>买东西");
}
public void findJob() {
System.out.println(">>>>>月薪20K");
System.out.println(">>>>>找工作");
}
}
JDK58.class
public class JDK58 implements InvocationHandler {
// 被代理的对象,把引用给保存下来
public Person target;
public Object getInstence(Person target) throws Exception {
this.target = target;
Class<? extends Person> clazz = target.getClass();
// 下半节,深入底层讲字节码是如何重组的。
// 用来生成一个新的对象(字节码重组来实现)
// public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是58,我要给你找工作,现在已经拿到你的简历");
System.out.println("开始投递");
method.invoke(this.target,args);
System.out.println("安排面试");
return null;
}
}
JDKMeiPo.class
public class JDKMeiPo implements InvocationHandler {
// 被代理的对象,把引用给保存下来
public Person target;
public Object getInstence(Person target) throws Exception {
this.target = target;
Class<? extends Person> clazz = target.getClass();
// 下半节,深入底层讲字节码是如何重组的。
// 用来生成一个新的对象(字节码重组来实现)
// public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是媒婆,我要给你找对象,现在已经拿到你的需求");
System.out.println("开始物色");
method.invoke(this.target,args);
System.out.println("如果合适的话,就准备办事!");
return null;
}
}
JDKProxyTest.class
public class JDKProxyTest {
public static void main(String[] args) throws Exception {
// Person person = (Person)new JDKMeiPo().getInstence(new XieMu());
// person.findLove();
Person person = (Person)new JDK58().getInstence(new XieMu());
System.out.println(person.getClass());
person.findJob();
// 原理:
// 1. 拿到被代理的对象的引用,并且获取到它的所有接口,反射获取
// 2. JDK Proxy 类重新生成一个新的类,同时新的类要实现被代理类的所有实现
// 3. 动态地生成 Java 代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体现)
// 4. 编译新生成的 Java 代码, .class
// 5. 再重新加载到 JVM 中运行
// 以上这个过程就叫字节码重组
// JDK 中有个规范,只要是 $ 开头的一般都是自动生成的。
// 通过反编译工具可以查看源代码。
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
FileOutputStream fileOutputStream = new FileOutputStream("$Proxy0.class");
fileOutputStream.write(bytes);
fileOutputStream.close();
}
}
$Proxy0.class
—JKD反射生成的源码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import com.darian.pattern.staticed.Person;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements Person {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m5;
private static Method m0;
private static Method m6;
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 void findLove() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
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 buy() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void findJob() throws {
try {
super.h.invoke(this, m5, (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);
}
}
public final void zuFangZi() throws {
try {
super.h.invoke(this, m6, (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"));
m4 = Class.forName("com.darian.pattern.staticed.Person").getMethod("findLove");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.darian.pattern.staticed.Person").getMethod("buy");
m5 = Class.forName("com.darian.pattern.staticed.Person").getMethod("findJob");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m6 = Class.forName("com.darian.pattern.staticed.Person").getMethod("zuFangZi");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
CGLIB
ZhangSan.class
public class ZhangSan {
public void findLove(){
System.out.println(">>>>>肤白,貌美,大象腿");
System.out.println(">>>>>");
}
}
CGLIBMeiPo.class
public class CGLIBMeiPo implements MethodInterceptor {
public Object getInstence(Class<?> clazz) throws Exception {
Enhancer enhancer = new Enhancer();
// 要把哪个设置为即将生成的新类的父类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
// 业务的增强
System.out.println("我是媒婆,我要给你找对象,现在已经拿到你的需求");
System.out.println("开始物色");
methodProxy.invokeSuper(o, objects);
System.out.println("如果合适的话,就办事!");
return null;
}
}
CglibTest.class
public class CglibTest {
public static void main(String[] args) throws Exception {
ZhangSan zhangSan = (ZhangSan)new CGLIBMeiPo().getInstence(ZhangSan.class);
zhangSan.findLove();
System.out.println("----------------------------");
System.out.println(zhangSan.getClass());
}
}
Custom:
DarianProxy.class
public class DarianProxy {
public static String ln = "\r\n";
public static Object newProxyInstance(DarianClassLoader classLoader, Class<?>[] interfaces, DarianInvocationHandler h) {
try {
// 1. 动态生成源代码 .java 文件
String src = generaterSrc(interfaces);
// 2. JAVA 文件输出到磁盘
// String filePath = DarianProxy.class.getResource("").getPath();
// System.out.println(filePath);
// File f = new File( "/$Proxy00.java");
// FileWriter fw = new FileWriter(f);
// fw.write(src);
// fw.flush();
// fw.close();
FileOutputStream fileOutputStream = new FileOutputStream("src\\main\\java\\com\\darian\\pattern\\proxy\\custom\\$Proxy0.java");
fileOutputStream.write(src.getBytes());
fileOutputStream.close();
File file = new File("src\\main\\java\\com\\darian\\pattern\\proxy\\custom\\$Proxy0.java");
// 3. 把 .java 文件编译成 .class 文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> iterable = manager.getJavaFileObjects(file);
JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable);
task.call();
manager.close();
// 4. 编译生成的 .class 文件加载到 JVM 中,
Class<?> proxyClass = classLoader.findClass("$Proxy0");
Constructor<?> constructor = proxyClass.getConstructor(DarianInvocationHandler.class);
// 5. 返回字节码重组以后的新的代理对象
constructor.newInstance(h);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static String generaterSrc(Class<?>[] interfaces) {
StringBuffer sb = new StringBuffer();
sb.append("package com.darian.pattern.proxy.custom;" + ln);
sb.append("import com.darian.pattern.staticed.Person;" + ln);
sb.append("import java.lang.reflect.Method;" + ln);
sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
sb.append("DarianInvocationHandler h;" + ln);
sb.append("public $Proxy0(DarianInvocationHandler h){" + ln);
sb.append("this.h = h;");
sb.append("}" + ln);
for (Method m : interfaces[0].getMethods()) {
sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "(){" + ln);
sb.append("try{" + ln);
sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{});" + ln);
sb.append("this.h.invoke(this, m, null);" + ln);
sb.append("}catch(Throwable e){" + ln);
sb.append("e.printStackTrace();" + ln);
sb.append("}" + ln);
sb.append("}");
}
sb.append("}" + ln);
return sb.toString();
}
}
DarianInvocationHandler.class
public interface DarianInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}
DarianClassLoader.class
public class DarianClassLoader extends ClassLoader {
private File classPathFile;
public DarianClassLoader() {
// String filePath = DarianClassLoader.class.getResource("").getPath();
// System.out.println(filePath);
// File f = new File( "/$Proxy00.java");
this.classPathFile = new File("src\\main\\java\\com\\darian\\pattern\\proxy\\custom\\$Proxy0.java");
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = DarianClassLoader.class.getPackage().getName() + "." + name;
if (classPathFile != null) {
File classFile = new File(classPathFile, name.replaceAll("\\.", "/") + ".class");
if (classFile.exists()) {
FileInputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(classFile);
out = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int len;
while ((len = in.read(buff)) != -1) {
out.write(buff, 0, len);
}
return defineClass(className, out.toByteArray(), 0, out.size());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != in) {
in.close();
}
if (null != out) {
out.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return null;
}
}
CustomMeipo.class
public class CustomMeipo implements DarianInvocationHandler {
// 被代理的对象,把引用给保存下来
public Person target;
public Object getInstence(Person target) throws Exception {
this.target = target;
Class<? extends Person> clazz = target.getClass();
// 下半节,深入底层将界字节码是如何重组的。
// 用来生成一个新的对象(字节码重组来实现)
// public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
return DarianProxy.newProxyInstance(new DarianClassLoader(), clazz.getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是媒婆,我要给你找对象,现在已经拿到你的需求");
System.out.println("开始物色");
System.out.println();
method.invoke(this.target,args);
System.out.println();
System.out.println("如果合适的话,就准备办事!");
return null;
}
}
CustomProxyTest.class
public class CustomProxyTest {
public static void main(String[] args) throws Exception {
// Person person = (Person)new JDKMeiPo().getInstence(new XieMu());
// person.findLove();
Person person = (Person)new CustomMeipo().getInstence(new XieMu());
System.out.println(person.getClass());
person.findJob();
}
}
$Proxy0.class
- 编译生成的代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.darian.pattern.proxy.custom;
import com.darian.pattern.staticed.Person;
import java.lang.reflect.Method;
public class $Proxy0 implements Person {
DarianInvocationHandler h;
public $Proxy0(DarianInvocationHandler var1) {
this.h = var1;
}
public void findLove() {
try {
Method var1 = Person.class.getMethod("findLove");
this.h.invoke(this, var1, (Object[])null);
} catch (Throwable var2) {
var2.printStackTrace();
}
}
public void buy() {
try {
Method var1 = Person.class.getMethod("buy");
this.h.invoke(this, var1, (Object[])null);
} catch (Throwable var2) {
var2.printStackTrace();
}
}
public void zuFangZi() {
try {
Method var1 = Person.class.getMethod("zuFangZi");
this.h.invoke(this, var1, (Object[])null);
} catch (Throwable var2) {
var2.printStackTrace();
}
}
public void findJob() {
try {
Method var1 = Person.class.getMethod("findJob");
this.h.invoke(this, var1, (Object[])null);
} catch (Throwable var2) {
var2.printStackTrace();
}
}
}
微信公众号:不止极客
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦