Java 的代理模式的实现自我总结

静态代理

特点:被代理对象和代理对象必须实现同一个接口(比较好理解)–直接上代码示例如下:

//被代理类和代理类必须实现的接口
public interface BuyHouse {
    /**
     * 买房操作接口
     * @param name 买房者
     */
    void buyHouse(String name);
}

被代理类:

public class BuyHouseImpl implements BuyHouse {
    @Override
    public void buyHouse(String name) {
        System.out.println(name+"在 "+LocalDate.now().toString() +" 买房了");
    }
}

代理类:

public class StaticBuyHouseProxy implements BuyHouse {
    private BuyHouse buyHouse;

    public StaticBuyHouseProxy(final BuyHouse buyHouse) {
        this.buyHouse = buyHouse;
    }

    @Override
    public void buyHouse(String name) {
        System.out.println("买房前咨询中介看房~~~~");
        buyHouse.buyHouse(name);
        System.out.println("买房后咨询装修公司装修~~~~~");
    }
}

测试示例代码:

public static void main(String[] args) {
        BuyHouse buyHouse = new BuyHouseImpl();
        StaticBuyHouseProxy staticBuyHouseProxy = new StaticBuyHouseProxy(buyHouse);
        staticBuyHouseProxy.buyHouse("李四");
    }

总结:静态代理更类似于装饰者模式,利用被代理者对象的注入执行真正的业务操作,只是在执行业务前后进行一些其他业务处理

JDK动态代理

特点:被代理对象必须实现接口,但是不需要创建实现接口的代理类,由运行程序时动态生成代理对象
缺点:还是被接口限制,无法为普通的类进行代理
示例代码如下:
接口:

//被代理对象必须实现的接口
public interface BuyHouse {
    /**
     * 买房操作
     * @param name 买房者
     */
    void buyHouse(String name);
}

被代理类:

public class BuyHouseImpl implements BuyHouse {
    @Override
    public void buyHouse(String name) {
        System.out.println(name+"在 "+LocalDate.now().toString() +" 买房了");
    }
}

执行代理操作的handler处理器:

public class BuyHouseProxyHandler implements InvocationHandler {
    private Object object;

    public BuyHouseProxyHandler(final Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDK动态:"+args[0]+"代理买房前找中介咨询~~");
        Object invoke = method.invoke(object, args);
        System.out.println("JDK动态:"+args[0]+"代理买房后找装修公司咨询~~~");
        return invoke;
    }
}

测试代码:

public static void main(String[] args) {
        BuyHouse buyHouse = new BuyHouseImpl();
        //生成代理对象
        BuyHouse house =(BuyHouse) Proxy.newProxyInstance(BuyHouse.class.getClassLoader(), buyHouse.getClass().getInterfaces(), new BuyHouseProxyHandler(buyHouse));
        house.buyHouse("张三");
    }

Spring CGLIB 动态代理

特点:被代理对象不需要实现接口,脱离了接口限制,CGLIB 创建代理对象的时间比JDK代理创建对象时间长得多,但是代理对象的性能比JDK动态代理创建的代理对象要高的多

示例代码如下:
被代理类:

public class BuyCar {
    public void buyCar(String name){
        System.out.println(name+"买车了~~~");
    }
}

代理操作的方法拦截器:

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CGLIBProxyBuyCar implements MethodInterceptor {
    private Object target;

    public CGLIBProxyBuyCar(final Object target) {
        this.target = target;
    }
    //获取代理对象
    public Object getProxyInstance(){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    //执行被代理对象的方法时的拦截方法
    //Object 参数为代理对象,此处有坑
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println(args[0]+"买车前试驾~~~");
        //Object result = methodProxy.invoke(this.target, args);
         //Object result = methodProxy.invokeSuper(o, args);
        Object result = method.invoke(this.target, args);
        System.out.println(args[0]+"买车后买保险,装潢~~~");
        return result;
    }
}

测试代码:

public static void main(String[] args) {
        BuyCar buyCar = new BuyCar();
        CGLIBProxyBuyCar cg = new CGLIBProxyBuyCar(buyCar);
        BuyCar proxy =(BuyCar) cg.getProxyInstance();
        proxy.buyCar("王五");
    }

CGLIB 动态代理的坑:
MethodInterceptor的 拦截方法:

// @Param Object o 是代理对象 
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//操作前逻辑
//执行invoke时 传入的对象参数必须是被代理的对象
method.invoke(this.target,args);
//执行invokeSuper时,传入的对象参数必须是代理对象,即Object o
//methodProxy.invokeSuper(o,args);
//操作后逻辑
}

错误示范:

@Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println(args[0]+"买车前试驾~~~");
        //此处传入的对象参数为代理对象
        Object result = method.invoke(o, args);
        //Object result = methodProxy.invoke(o, args);
        //此处对象参数应该传入代理对象o,但是传入的却是被代理对象
        //Object result = methodProxy.invokeSuper(this.target, args);
        System.out.println(args[0]+"买车后买保险,装潢~~~");
        return result;
    }

执行测试代码后的结果如下(只截取部分):
出现死循环,导致栈溢出报错~~~~

Caused by: java.lang.StackOverflowError
	at java.nio.CharBuffer.<init>(CharBuffer.java:281)
	at java.nio.HeapCharBuffer.<init>(HeapCharBuffer.java:70)
	at java.nio.CharBuffer.wrap(CharBuffer.java:373)
	at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:265)
	at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
	at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
	at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
	at java.io.PrintStream.write(PrintStream.java:526)
	at java.io.PrintStream.print(PrintStream.java:669)
	at java.io.PrintStream.println(PrintStream.java:806)
	at com.example.awngfei.proxy.CGLIBProxy.CGLIBProxyBuyCar.intercept(CGLIBProxyBuyCar.java:27)
	at com.example.awngfei.proxy.CGLIBProxy.BuyCar$$EnhancerByCGLIB$$b0ba1bb4.buyCar(<generated>)
	at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at com.example.awngfei.proxy.CGLIBProxy.CGLIBProxyBuyCar.intercept(CGLIBProxyBuyCar.java:28)
	at com.example.awngfei.proxy.CGLIBProxy.BuyCar$$EnhancerByCGLIB$$b0ba1bb4.buyCar(<generated>)
	at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at com.example.awngfei.proxy.CGLIBProxy.CGLIBProxyBuyCar.intercept(CGLIBProxyBuyCar.java:28)
	at com.example.awngfei.proxy.CGLIBProxy.BuyCar$$EnhancerByCGLIB$$b0ba1bb4.buyCar(<generated>)
	at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at com.example.awngfei.proxy.CGLIBProxy.CGLIBProxyBuyCar.intercept(CGLIBProxyBuyCar.java:28)
	at com.example.awngfei.proxy.CGLIBProxy.BuyCar$$EnhancerByCGLIB$$b0ba1bb4.buyCar(<generated>)
	at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at com.example.awngfei.proxy.CGLIBProxy.CGLIBProxyBuyCar.intercept(CGLIBProxyBuyCar.java:28)
	at com.example.awngfei.proxy.CGLIBProxy.BuyCar$$EnhancerByCGLIB$$b0ba1bb4.buyCar(<generated>)
	at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)

你可能感兴趣的:(java代理模式)