关于java:JAVA基础之静态代理与动态代理

4次阅读

共计 4705 个字符,预计需要花费 12 分钟才能阅读完成。

这个是陈腐的热乎的,针对某个面试题写了的内容,如果有问题欢送来喷。

来看看他们的区别

动态 / 动静 区别
动态 由程序员创立代理类或特定工具主动生成源代码再对其编译。在程序运行前代理类的.class 文件就曾经存在了
动静 在程序运行时使用反射机制动态创建而成。

咱们先把动态代理和动静代理的代码放上来
看名字,这个是须要被代理的接口,无论是动态还是动静,都须要一个接口
ToBeProxyedInterface.java

public interface ToBeProxyedInterface {void addUser(String userId, String userName);
    void delUser(String userId);
    String findUser(String userId);
    void modifyUser(String userId, String userName);
}

上面是两个类,ToBeProxyedService1.java,ToBeProxyedService2.java,动态代理只须要一个就能够了,动静代理为了试验其动态性,所以来了两个具体的 Service,后边能够看 Client 的 main 办法实现,如何指定 1 还是 2 的 service 调用
ToBeProxyedService1.java

public class ToBeProxyedService1 implements ToBeProxyedInterface {
    @Override
    public void addUser(String userId, String userName) {System.out.println("ToBeProxyedService1.addUser");
    }
    @Override
    public void delUser(String userId) {System.out.println("ToBeProxyedService1.delUser");
    }
    @Override
    public String findUser(String userId) {System.out.println("ToBeProxyedService1.findUser");
        return "张三";
    }
    @Override
    public void modifyUser(String userId, String userName) {System.out.println("ToBeProxyedService1.modifyUser");
    }
}

ToBeProxyedService2.class

public class ToBeProxyedService2 implements ToBeProxyedInterface {
    @Override
    public void addUser(String userId, String userName) {System.out.println("ToBeProxyedService2.addUser");
    }
    @Override
    public void delUser(String userId) {System.out.println("ToBeProxyedService2.delUser");
    }
    @Override
    public String findUser(String userId) {System.out.println("ToBeProxyedService2.findUser");
        return "张三 2";
    }
    @Override
    public void modifyUser(String userId, String userName) {System.out.println("ToBeProxyedService2.modifyUser");
    }
}

重点来类,动态代理,通过构造方法传入了具体的须要代理的 Service,因而每一个 Handler 只能代理一个 Service,再减少一个 Service 时候,就须要在对应一个 Handler,扩大不太好
StaticProxyHandler.java

public class StaticProxyHandler implements ToBeProxyedInterface {
    // 指标对象
    private ToBeProxyedService1 toBeProxyedService1;
    // 通过构造方法传入指标对象
    public StaticProxyHandler(ToBeProxyedService1 toBeProxyedService1){this.toBeProxyedService1=toBeProxyedService1;}
    @Override
    public void addUser(String userId, String userName) {
        try{
            // 增加打印日志的性能
            // 开始增加用户
            System.out.println("start StaticProxyHandler-->addUser()");
            toBeProxyedService1.addUser(userId, userName);
            // 增加用户胜利
            System.out.println("success StaticProxyHandler-->addUser()");
        }catch(Exception e){
            // 增加用户失败
            System.out.println("error StaticProxyHandler-->addUser()");
        }
    }
    @Override
    public void delUser(String userId) {toBeProxyedService1.delUser(userId);
    }
    @Override
    public String findUser(String userId) {toBeProxyedService1.findUser(userId);
        return "张三";
    }
    @Override
    public void modifyUser(String userId, String userName) {toBeProxyedService1.modifyUser(userId,userName);
    }
}

最重点来了,动静代理,能够在外面看不到任何具体的 Service 是哪个,具体的指定哪个 Service 在后边的 Client 的 main 办法传入指定不同的 Service。实际上动静代理是通过实现了 InvocationHandler 实现的
具体看下,newProxyInstance 办法是通过入参传入指定的具体的哪个 Service 的动静绑定,而 Handler 中实现 InvocationHandler 中的 invoke 办法,才是真正调用的具体的办法的实现。
DynamicProxyHandler.java

public class DynamicProxyHandler implements InvocationHandler {
    // 指标对象
    private Object targetObject;
    // 绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些办法将被调用时,执行 invoke 办法。public Object newProxyInstance(Object targetObject){
        this.targetObject=targetObject;
        // 该办法用于为指定类装载器、一组接口及调用处理器生成动静代理类实例
        // 第一个参数指定产生代理对象的类加载器,须要将其指定为和指标对象同一个类加载器
        // 第二个参数要实现和指标对象一样的接口,所以只须要拿到指标对象的实现接口
        // 第三个参数表明这些被拦挡的办法在被拦挡时须要执行哪个 InvocationHandler 的 invoke 办法
        // 依据传入的指标返回一个代理对象
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                targetObject.getClass().getInterfaces(),this);
    }
    @Override
    // 关联的这个实现类的办法被调用时将被执行
    /*InvocationHandler 接口的办法,proxy 示意代理,method 示意原对象被调用的办法,args 示意办法的参数 */
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {System.out.println("start DynamicProxyHandler--invoke >>");
        for(int i=0;i<args.length;i++){System.out.println(args[i]);
        }
        Object ret=null;
        try{
            /* 原对象办法调用前解决日志信息 */
            System.out.println("satrt DynamicProxyHandler call method -->>");
            // 调用指标办法
            ret=method.invoke(targetObject, args);
            /* 原对象办法调用后处理日志信息 */
            System.out.println("success DynamicProxyHandler call method -->>");
        }catch(Exception e){e.printStackTrace();
            System.out.println("error DynamicProxyHandler call method -->>");
            throw e;
        }
        return ret;
    }
}

上面的 main 办法能够看到,动态代理传入的就是具体的 ToBeProxyedService1,无奈实现扩大
后边的动静代理我写了两遍,实际上每次传入的不同的 ToBeProxyedService1 和 ToBeProxyedService2,别离都能够执行,不便动静扩大,后边如果再有 ToBeProxyedService3,只有调用前批改就能够,不必批改具体的 Handler,不便扩大了。
Client.java

public class Client {public static void main(String[] args){
        // 动态代理,每一个固定写死了具体的须要代理的类
        StaticProxyHandler staticProxyHandler = new StaticProxyHandler(new ToBeProxyedService1());
        staticProxyHandler.addUser("1111", "张三");
        // 动静代理,须要执行 ToBeProxyedService1 就传入 ToBeProxyedService1,如果须要执行 ToBeProxyedService2 就传入 ToBeProxyedService2
        DynamicProxyHandler proxyHandler=new DynamicProxyHandler();
        ToBeProxyedInterface service = (ToBeProxyedInterface) proxyHandler.newProxyInstance(new ToBeProxyedService1());
        service.addUser("1111", "张三");
        service = (ToBeProxyedInterface) proxyHandler.newProxyInstance(new ToBeProxyedService2());
        service.addUser("1111", "张三");
    }
}
正文完
 0