代理模式
一、概念
代理模式是指为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用,代理模式属于结构型设计模式。使用代理模式主要有两个目的:一保护目标对象,二增强目标对象。
二、JDK动态代理
代理的目标接口,相亲
public interface Person {
public void findLove();
}
代理目标实现,要相亲的人
public class JDKCustomer implements Person {
@Override
public void findLove() {
System.out.println("高富帅");
System.out.println("身高180cm");
System.out.println("胸大,6块腹肌");
}
}
代理类媒婆,帮客户找对象
public class JDKMeipo implements InvocationHandler {
private Object target;
public Object getInstance(Object target) throws Exception{
this.target=target;
Class<?> aClass = target.getClass();
return Proxy.newProxyInstance(aClass.getClassLoader(),aClass.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
method.invoke(this.target,args);
after();
return null;
}
public void before(){
System.out.println("before");
}
public void after(){
System.out.println("after");
}
}
test
public class JDKProxyTest {
public static void main(String[] args) {
try{
Person person = (Person) new JDKMeipo().getInstance(new JDKCustomer());
person.findLove();
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
FileOutputStream fos = new FileOutputStream("E://$Proxy0.class");
fos.write(bytes);
fos.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
特点
1.代理的目标必须实现接口,生成的代理类和目标实现同样的接口,有点装饰模式的意思
2.需要提供类加载器,代理目标类的类加载器
3.需要提供一个实现了InvocationHandler接口的类对象(重点是invoke方法)
4.调用目标方式时使用的是反射调用
5.JDK是直接写Class字节码,生成代理类,生成的代理类实现了代理目标的所有接口,并实现了其方法。
6.方法的方法default方法无法被代理,代理目标类的方法如果不是来自接口则无法被代理
7.需要提供代理目标类的实例(对象),内部类似装饰调用,最终执行方法的还是我们提供的对象来完成的。先生成对象,设置参数,再生成代理对象。
8.记住,是接口实现代理,只能代理接口抽象的方法
原理
/**
* <p>
* JDK代理,生成的代理类模拟
* </p>
*
* @author: longWarren
* @time: 2020/08/31
*/
public class JDKProxyClassSimulation {
/**
* <p>
* jdk代理特点
* 1.代理的目标必须实现接口
* 2.需要提供类加载器,代理目标类的类加载器
* 3.需要提供一个实现了InvocationHandler接口的类对象(重点是invoke方法)
* 4.调用目标方式时使用的是反射调用
* 5.JDK是直接写Class字节码,生成代理类,生成的代理类实现了代理目标的所有接口,并实现了其方法。
* </p>
*/
public static class JDKProxyClass extends Proxy implements Person {
/**
* 这就是实现代理的核心,proxy中有一个h对象,就是InvocationHandler的实现,真正的掉用就是其invoke方法
* @param h
*/
public JDKProxyClass(InvocationHandler h) {
super(h);
}
@Override
public void findLove() {
try
{
super.h.invoke(this, m3, null);
return;
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
private static Method m3;
private static Method m2;
private static Method m1;
private static Method m0;
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
m3 = Class.forName("com.dalong.learn.design.mode.proxy.Person").getMethod("findLove", new
Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
}
三,CGLIB动态代理
代理的目标接口,相亲
public interface Person {
public void findLove();
}
代理目标实现,要相亲的人
public class CglibCustomer implements Person {
@Override
public void findLove() {
System.out.println("高富帅");
System.out.println("身高180cm");
System.out.println("胸大,6块腹肌");
}
}
代理类媒婆,帮客户找对象
public class CglibMeipo implements MethodInterceptor {
public Object getInstance(Class<?> clazz) throws Exception{
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object o1 = methodProxy.invokeSuper(o, objects);
after();
return o1;
}
public void before(){
System.out.println("before");
}
public void after(){
System.out.println("after");
}
}
特点
1.代理的目标无需实现接口,生成的代理类会继承要代理的类,所以要代理的类不可以用final修饰
2.需要提供一个实现了MethodInterceptor接口的类对象(重点是intercept方法)
3.使用的是继承方式实现,不能代理final方法
4.调用目标方式时使用的直接调用(super.method()),使用FastClass实现(不太懂里面的细节)
5.无需提供代理目标类的实例(对象),先生成代理对象,再设置参数
6.CGLib 使用ASM框架写Class 字节码,Cglib 代理实现更复杂,生成代理类比JDK 效率低。
7.CGLib 是通过FastClass 机制直接调用方法,CGLib 执行效率更高。
原理
public class CglibProxyClassSimulation {
public static class CglibProxyClass extends CglibCustomer implements Factory {
private MethodInterceptor methodInterceptor;
//使用dialing类调用时,会调用这个方法,然后转入intercept方法
public final void findLove(){
//methodInterceptor.intercept();
return;
}
//intercept里面调用 methodProxy.invokeSuper(o, objects);就会调用这个方法
public void cgLibFindLove(){
super.findLove();
}
@Override
public Object newInstance(Callback callback) {
return null;
}
@Override
public Object newInstance(Callback[] callbacks) {
return null;
}
@Override
public Object newInstance(Class[] classes, Object[] objects, Callback[] callbacks) {
return null;
}
@Override
public Callback getCallback(int i) {
return null;
}
@Override
public void setCallback(int i, Callback callback) {
}
@Override
public void setCallbacks(Callback[] callbacks) {
}
@Override
public Callback[] getCallbacks() {
return new Callback[0];
}
}
}