面试官问 Spring AOP 中两种代理模式的区别,我懵逼了( 二 )

4、客户端验证
public class Client {    public static void main(String[] args) {        Internet internet = new ProxyInternet(new RealInternet());        try {            internet.connectTo("so.com");            internet.connectTo("qq.com");        } catch (Exception e) {            System.out.println(e.getMessage());        }    }}5、输出
Connecting to so.comAccess Denied:qq.com

不能访问娱乐性网站 , 但是可以用 360 搜索 , SO 靠谱 , 哈哈
静态代理类优缺点优点:在不修改目标对象的前提下 , 可以通过代理对象对目标对象功能扩展
代理使客户端不需要知道实现类是什么 , 怎么做的 , 而客户端只需知道代理即可(解耦合) , 对于如上的客户端代码 , RealInterner() 可以应用工厂将它隐藏 。
缺点:
  1. 代理类和委托类实现了相同的接口 , 代理类通过委托类实现了相同的方法 。这样就出现了大量的代码重复 。如果接口增加一个方法 , 除了所有实现类需要实现这个方法外 , 所有代理类也需要实现此方法 。增加了代码维护的复杂度 。
  2. 代理对象只服务于一种类型的对象 , 如果要服务多类型的对象 。势必要为每一种对象都进行代理 , 静态代理在程序规模稍大时就无法胜任了 。
动态代理静态代理会产生很多静态类 , 所以我们要想办法可以通过一个代理类完成全部的代理功能 , 这就引出了动态代理 。
JDK原生动态代理
  • 代理对象 , 不需要实现接口 , 但是目标对象要实现接口 , 否则不能用动态代理
  • 代理对象的生成 , 是通过 JDK 的 API(反射机制) , 动态的在内存中构建代理对象
在 JAVA 中要想实现动态代理机制 , 需要
java.lang.reflect.InvocationHandler 接口和 java.lang.reflect.Proxy 类的支持
Coding1、网络接口不变
public interface Internet {    void connectTo(String serverHost) throws Exception;}2、真正的网络连接 , 也不会改变
public class RealInternet implements Internet{    @Override    public void connectTo(String serverHost) throws Exception {        System.out.println("Connecting to "+ serverHost);    }}3、动态代理 , 需要实现 InvocationHandler , 我们用 Lambda 表达式简化下
public class ProxyFactory {    /**     * 维护一个目标对象     **/    private Object target;    /**     * 构造器 , 初始化目标对象     **/    public ProxyFactory(Object target) {        this.target = target;    }    public Object getProxyInstance() {        /**         被代理对象target通过参数传递进来 ,          通过target.getClass().getClassLoader()获取ClassLoader对象 ,          然后通过target.getClass().getInterfaces()获取它实现的所有接口 ,          再将target包装到实现了InvocationHandler接口的对象中 。         通过newProxyInstance函数我们就获得了一个动态代理对象 。         */        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {            @Override            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                if(bannedSites.contains(args[0].toString().toLowerCase()))                {                    throw new Exception("Access Denied:"+args[0]);                }                //反射机制调用目标对象的方法                Object obj = method.invoke(target, args);                return obj;            }        });    }    private static List<String> bannedSites;    static    {        bannedSites = new ArrayList<String>();        bannedSites.add("bilibili.com");        bannedSites.add("youtube.com");        bannedSites.add("weibo.com");        bannedSites.add("qq.com");    }}


推荐阅读