代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
作用:
- 1.检测类中方法的执行
- 2.可以在类中所有的或者某一个方法执行的过程中 动态的植入代码进行运行
特点:
由被代理角色来做最终决定,代理角色通常来说会持有被代理角色对象的引用,以便于代理角色完成工作之前或者之后能够找到代理对象,能够通知被代理对象
分类: 静态代理,动态代理
一、代理
1. 静态代理
代理前所有的东西已知的(人工化)
静态代理类持有被代理类的引用,是具体的类;一般代理类实现和被代理相同的接口,如果被代理的接口修改,代理也会修改,复杂也麻烦。
2.动态代理
代理前所有的东西未知的((自动化的)
2.1 JDK代理
持有的代理引用可以不是具体的类,给一个接口就可以了;生成的代理类和被代理的类是同级的。
person接口:
package com.vison.proxy.jdkproxy;
public interface Person {
void findLove();
}
被代理类:
public class LiSi implements Person {
public void findLove() {
System.out.println("need find love");
}
}
代理类,实现InvocationHandler接口
package com.vison.proxy.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxy implements InvocationHandler {
private Person person;
public Object getInstance(Person person) {
this.person = person;
Class clazz = person.getClass();
return Proxy.newProxyInstance(person.getClass().getClassLoader(),clazz.getInterfaces(),this);
}
//代理,这里可以做相应的方法处理
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before to do method");
Object invoke = method.invoke(person, args);
System.out.println("after to do method");
return invoke; //这里是返回方法调用的结果
}
}
测试:
package com.vison.proxy.jdkproxy;
public class TestJdk {
public static void main(String[] args) {
Person person = (Person)new JdkProxy().getInstance(new LiSi());
person.findLove();
System.out.println("--------------"+person.getClass());
}
}
2.2 CGLIB代理
CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现.
被代理类:
package com.vison.proxy.cglib;
public class ZhouYu {
String findLove(){
System.out.println("easy to find love");
return "success";
}
}
代理类:
package com.vison.proxy.cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CgLibProxy implements MethodInterceptor {
public Object getInstance (Class<?> clazz){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//业务的增加
System.out.println("before to do method");
System.out.println("methodProxy--------"+methodProxy.getClass());
System.out.println("object---------"+proxy.getClass());
//这里调用invokeSuper方法
Object ans = methodProxy.invokeSuper(proxy, objects);
System.out.println("after to do method");
return ans;
}
}
测试:
package com.vison.proxy.cglib;
public class TestCglib {
public static void main(String[] args) {
CgLibProxy cgLibProxy = new CgLibProxy();
ZhouYu instance = (ZhouYu)cgLibProxy.getInstance(ZhouYu.class);
String love = instance.findLove();
System.out.println(love);
}
}
二、原理
1.JDK代理原理
测试中把内存中得代理class持久化,然后反编译来查看。
输出:
package com.vison.proxy.jdkproxy;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
public class TestJdk {
public static void main(String[] args) throws Exception {
Person person = (Person)new JdkProxy().getInstance(new LiSi());
person.findLove();
System.out.println(person.getClass()); //class com.sun.proxy.$Proxy0
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
FileOutputStream os = new FileOutputStream("E:\\temp\\&Proxy0.class");
os.write(bytes);
}
}
打开本地持久化的&Proxy0.class文件
import com.vison.proxy.jdkproxy.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 m3; //这个就是生成的方法findLove
private static Method m2;
private static Method m0;
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 {
//这里的h就是我们实现接口 InvocationHandler的类
super.h.invoke(this, m3, (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 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"));
m3 = Class.forName("com.vison.proxy.jdkproxy.Person").getMethod("findLove");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}