为了将业务代码与扩展逻辑分离,有利于开发仅关注业务逻辑部分。另外,模块水平扩展更方便,添加业务实例后,只要更新代理就好了。
2.静态代理实现
略(由于静态代理可维护性差,而且硬编码冗余代码多,一般不采用)
静态代理需要创建代理类(实现业务接口)并实现业务接口所有方法,由代理类创建实例。通过调用代理类实例的方法去调用委托类实例的方法,但当扩展业务接口中的方法时,比如增加或减少业务接口中的方法,那么相应的,需要人工更改代理类中的方法实现。其次,代理类的方法实现中由于封装了对委托类实例方法的调用,所以可对非业务代码进行功能扩展,但当业务接口增加时,就需要将统一的扩展重复写入每个代理类方法的实现中,增加了代码冗余及复杂度。比如:业务接口只有支付的逻辑,但是需要代理类在实现接口方法中对业务逻辑做扩展,支付前、转账前、买理财前都要查余额,支付后、转账后、买理财后也要查余额,与支付pay()接口等无关的逻辑应该抽出来放在代理类的方法实现中去做,所以要求代理类的方法实现能够为接口中所有业务方法做统一的扩展,并且需要一个能够动态生成针对接口方法的代理类,而不是,每次接口有变化就要新建一个代理类。
总结:希望在业务代码前后统一做一些业务无关的扩展性功能,可以使用动态代理。
2.动态代理实现
public class DynamicProxyTest {
public static void main(String[] args){
IAnimal dog = new Dog();
InvocationHandler invocationHandler = new IAnimalProxy(dog);
IAnimal dogProxy = (IAnimal) Proxy.newProxyInstance(dog.getClass().getClassLoader(),dog.getClass().getInterfaces()
,invocationHandler);
dogProxy.run("haha");
dogProxy.skip("lala");
}
}
class IAnimalProxy implements InvocationHandler{
IAnimal animal;
public IAnimalProxy(IAnimal animal){
this.animal = animal;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before method invoked......");
Object obj = method.invoke(animal,args);
System.out.println("after method invoked......");
return obj;
}
}
class Dog implements IAnimal{
public void run(String name) {
System.out.println(name + " dog is running");
}
public void skip(String name) {
System.out.println(name + " dog is skipping");
}
}
interface IAnimal{
void run(String name);
void skip(String name);
}
3.动态代理原理
主要是通过Proxy类中的newProxyInstance方法创建代理类实例,查看jdk1.8源码分析代理类创建流程:
我们使用其中关键的步骤创建动态代理类,利用反编译工具javap(intellj可直接双击打开.class文件)打开,如下示例在main方法中生成动态代理类TestProxy.class
IAnimal dog = new Dog();
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
"TestProxy", dog.getClass().getInterfaces());
OutputStream ops = null;
try {
ops = new FileOutputStream(new File("TestProxy.class"));
ops.write(proxyClassFile);
ops.flush();
ops.close();
} catch (IOException e) {
e.printStackTrace();
}
打开TestProxy.class文件,如下: 主要在静态代码块运用反射机制动态生成接口方法,并为代理类实现接口所有方法。
public final class TestProxy extends Proxy implements IAnimal {
private static Method m1;
private static Method m2;
private static Method m4;
private static Method m3;
private static Method m0;
public TestProxy(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
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 skip(String var1) throws {
try {
super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void run(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final int hashCode() throws {
try {
return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m4 = Class.forName("proxy.IAnimal").getMethod("skip", new Class[]{Class.forName("java.lang.String")});
m3 = Class.forName("proxy.IAnimal").getMethod("run", new Class[]{Class.forName("java.lang.String")});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}