01-设计模式:JDK动态代理
2021-01-06 本文已影响0人
XAbo
代理模式:在不改变原有类的前提下,对原有类进行业务增强。
动态与静态代理区别:动态代理的代理类是被用的时候在内存中创建。
jdk方式代理类:必须实现的有接口。
问题:如何给Manager方法add()执行前后增加额外的日志逻辑呢?
package realclass;
import interfaces.ControlDB;
import interfaces.ControlUI;
public class Manager implements ControlDB{
@Override
public void add() {
// TODO Auto-generated method stub
System.out.println("我是Manager,数据添加中……");
}
}
1、静态代理
package proxyclass;
import realclass.Manager;
import interfaces.ControlDB;
import interfaces.ControlUI;
public class ManagerLog_JT implements ControlDB {
private Manager manager ;
public ManagerLog_JT(){
manager=new Manager();
}
@Override
public void add() {
// TODO Auto-generated method stub
System.out.println("我是ManagerLog_JT,日志记录开始……");
manager.add();
System.out.println("我是ManagerLog_JT,日志记录结束……");
}
}
2、聚合方式
package proxyclass;
import interfaces.ControlDB;
public class ManagerLog_JH implements ControlDB {
ControlDB controlDB;
public ManagerLog_JH(ControlDB controlDB){
this.controlDB=controlDB;
}
@Override
public void add() {
// TODO Auto-generated method stub
System.out.println("我是ManagerLog_JH,日志记录开始……");
controlDB.add();
System.out.println("我是ManagerLog_JH,日志记录结束……");
}
}
3、测试类:
import interfaces.ControlDB;
import proxyclass.ManagerLog_JH;
import proxyclass.ManagerLog_JT;
import realclass.Manager;
public class ProxyTest {
public static void main(String[] args) {
// 正常调用Manager
Manager manager= new Manager();
manager.add();
System.out.println("==============================分割线============================");
System.out.println("为Mnager的add方法执行前后添加日志记录的操作,使用静态代理和聚合方式实现:");
System.out.println("————————————————————静态方式开始————————————————————");
ControlDB managerlog_jt=new ManagerLog_JT();
managerlog_jt.add();
System.out.println("————————————————————静态方式结束————————————————————");
System.out.println("————————————————————聚合方式开始————————————————————");
ControlDB managerlog_jh=new ManagerLog_JH(new Manager());
managerlog_jh.add();
System.out.println("————————————————————聚合方式结束————————————————————");
}
}
4、结果
我是Manager,数据添加中……
==============================分割线============================
为Mnager的add方法执行前后添加日志记录的操作,使用静态代理和聚合方式实现:
————————————————————静态方式开始————————————————————
我是ManagerLog_JT,日志记录开始……
我是Manager,数据添加中……
我是ManagerLog_JT,日志记录结束……
————————————————————静态方式结束————————————————————
————————————————————聚合方式开始————————————————————
我是ManagerLog_JH,日志记录开始……
我是Manager,数据添加中……
我是ManagerLog_JH,日志记录结束……
————————————————————聚合方式结束————————————————————
5、分析
不管哪种方式最终结果是代码的臃肿:
6、动态代理
原理:
1.在运行时根据反射生成一个被代理对象类似的“内存对象”。
2.“内存对象”可以执行原有对象的原生方法。
3.在执行原生方法前后可以增加业务逻辑。
4.增加的业务逻辑需用户自定义。
jdk实现的动态代理应用
package test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import proxyclass.ManagerLog_Proxy;
import realclass.Manager;
public class ManagerInvocationHandler implements InvocationHandler {
private Object obj;
public ManagerInvocationHandler(Object obj) {
this.obj = obj;
}
public static Object getProxyInstanceFactory(Object realObj){
Class<?> classType = realObj.getClass();
/* 参数1:被代理对象的类加载器,用来加载代理对象的字节码文件。
参数2:被代理对象实现的接口,用来是代理对象与被代理对象保持方法一致。
使用参数1、2保证了【原理1】
*/
return Proxy.newProxyInstance(classType.getClassLoader(),classType.getInterfaces(), new ManagerInvocationHandler(realObj));
}
@Override
//实现了【原理2 3 4】关键是该方法能被内存中的代理类调到
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("before========日志生成");
method.invoke(obj, args);
System.out.println("after=========日志结束");
return null;
}
}
动态代理的测试类:
package test;
import interfaces.ControlDB;
import interfaces.ControlUI;
import realclass.Manager;
import realclass.UserA;
public class ProxyTest {
public static void main(String[] args) {
System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
//返回内存中的代理类(无逻辑的方法体)
Manager manager= new Manager();
//拿到代理类,执行内存类中的方法
ControlUI managerui= (ControlUI) ManagerInvocationHandler.getProxyInstanceFactory(manager);
managerui.change();
}
}
内存中的类$Proxy0:如何生成看后续JAVA反射专题,会模拟jdk生成动态类。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sun.proxy;
import com.temp.ControlDB;
import com.temp.ControlUI;
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 ControlDB, ControlUI {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
//继承父类就是为了使用父类的中的属性InvocationHandler
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 change() throws {
try {
//回调invoke方法:super.h是因为父类才有InvocationHandler属性。
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 add() throws {
try {
super.h.invoke(this, m3, (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);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.temp.ControlUI").getMethod("change");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.temp.ControlDB").getMethod("add");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
代理类的父类:
public class Proxy implements Serializable {
private static final long serialVersionUID = -2222568056686623797L;
private static final Class<?>[] constructorParams = new Class[]{InvocationHandler.class};
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache(new Proxy.KeyFactory(), new Proxy.ProxyClassFactory());
//I am here
protected InvocationHandler h;
private static final Object key0 = new Object();
private Proxy() {
}
……
}
其他动态代理的实现技术:cglib,javassist,asm。