分类

静态代理:一个代理只帮同一种人代理
动态代理:一个代理可以帮不同的人代理

静态代理

我画了一个草图,方便大家理解
典型的例子,房东要租房,找到了中介,叫中介帮忙租出去,客户租房直接去找中介,中介来操作租房的具体事宜。
通俗易懂的代理模式_proxy

//抽象角色
public interface Rent {
    public void rent();
}
//房东
public class Host implements Rent {
    @Override
    public void rent(){
        System.out.println("房东房屋出租。。。");
    }
}
//中介
public class Proxy implements Rent{

    private Host host;//房东
    public Proxy() { }
    public Proxy(Host host) {
        this.host = host;
    }
    //租房
    @Override
    public void rent(){
        seeHouse();
        talk();
        host.rent();   
    }
    //看房
    public void seeHouse(){
        System.out.println("带顾客看房");
    }
    //陪顾客聊天
    public void talk(){
        System.out.println("陪顾客聊天");
    }
}
//客户
public class Client {
    public static void main(String[] args) {
        //房东要租房
        Host host = new Host();
        //中介帮助房东租房
        Proxy proxy = new Proxy(host);
        //中介来完成租房的各种细节!
        proxy.rent();
    }
}

带顾客看房
陪顾客聊天
房东房屋出租。。。

动态代理

分类:
基于接口的动态代理—JDK动态代理
基于类的动态代理 — cglib 代理
现在用的较多的是javassist动态代理

下面是基于JDK动态代理实现的

//抽象角色
public interface Rent {
    public void rent();
}
//房东
public class Host implements Rent {
    @Override
    public void rent(){
        System.out.println("房东房屋出租。。。");
    }
}
//中介
public class ProxyInvocationHandler implements InvocationHandler {

    private Rent rent;

    public void setRent(Rent rent) {
        this.rent = rent;
    }

    //生成代理类,每个代理实例都有一个关联的调用处理程序对象,它实现了接口InvocationHandler 。
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                rent.getClass().getInterfaces(),this);
    }

    // 处理代理实例上的方法调用并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        seeHouse();
        //核心:本质利用反射实现!
        Object result = method.invoke(rent, args);
        talk();
        return result;
    }

    //看房
    public void seeHouse(){
        System.out.println("带顾客看房");
    }
    //聊天
    public void talk(){
        System.out.println("陪顾客聊天");
    }

}

//客户
public class Client {
    public static void main(String[] args) {
        //房东要租房
        Host host = new Host();
        //代理实例的调用处理程序
      	ProxyInvocationHandler pih = new ProxyInvocationHandler();
        pih.setRent(host); 
        Rent proxy = (Rent)pih.getProxy(); //动态生成对应的代理类!
        proxy.rent();
    }
}
带顾客看房
陪顾客聊天
房东房屋出租。。。

如果还没有看懂,不急,看看下面的,这是封装好了的,可以直接使用


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @Auther: 罗罗
 */
public class ObjectProxy {
    public static<T> T getProxy(final T t){
        //=第一个参数,被代理类的类加载器
        //第二个参数:被代理类实现的接口
        //第三个参数:方法执行器
        Object o = Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
           //第一个参数:JDK的代理对象,别动
            //第二个参数:执行的方法
            //第三个参数:方法的参数
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object result = null;
                try {
                    //方法执行前
                  	LogUtils.log(method,args);
                    //返回值是方法的返回值
                    result = method.invoke(t, args);
                    //方法执行后
					LogUtils.log(method,args);
                }catch (Exception e){
                    System.out.println(method.getName()+"方法出现异常:"+e.getCause()+"--->方法参数:"+ Arrays.asList(args));
                }finally {
                    LogUtils.log(method,args);
                }
                return result;
            }
        });
        return (T)o;
    }
}
public static void main(String[] args) {
		//注意,这里的proxy 必须是接口,不是接口就会报错
        EatRiceImpl proxy = ObjectProxy.getProxy(new EatRice());
        proxy.eatFruit();
    }

报错如下

"C:\Program Files\Java\jdk1.8.0_144\bin\java.exe" "-javaagent:D:\IntelliJ IDEA\IntelliJ IDEA 2018.2.4\lib\idea_rt.jar=64270:D:\IntelliJ IDEA\IntelliJ IDEA 2018.2.4\bin" -bin\rep\com\fasterxml\jackson\core\jackson-annotations\2.10.0\jackson-annotations-2.10.0.jar" 
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to com.luo.log.EatRice
	at com.luo.test.LogTest.main(LogTest.java:14)

Process finished with exit code 1

原因是jdk动态代理生成的代理类,和接口的实现类是同一级的,无法转换。
看看为什么这么说,哈哈

public class EatRice implements EatRiceImpl{
    @Override
    public void eatFruit(int i,int b){
        int c =i/b;
        System.out.println("吃水果");
    }
}
public class LogTest {
    public static void main(String[] args) {
        EatRiceImpl proxy = ObjectProxy.getProxy(new EatRice());
          proxy.eatFruit(2,1);
        Class<?>[] interfaces = proxy.getClass().getInterfaces();
        System.out.println(Arrays.asList(interfaces));
    }
}
"C:\Program Files\Java\jdk1.8.0_144\bin\java.exe" "-javaagent:D:\IntelliJ IDEA\IntelliJ IDEA 2018.2.4\lib\idea_rt.jar=50133:D:\IntelliJ IDEA\IntelliJ IDEA 2018.2.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_144\jre\lib\charsets.jar;C:\Program bin\rep\com\fasterxml\jackson\core\jackson-annotations\2.10.0\jackson-annotations-2.10.0.jar" 
[interface com.luo.spring.log.EatRiceImpl]
吃水果

Process finished with exit code 0

是不是实现了同一个接口,所以是同一级的吧