美文网首页小卜java
JAVA基础之静态代理与动态代理

JAVA基础之静态代理与动态代理

作者: 汤太咸啊 | 来源:发表于2021-11-15 17:46 被阅读0次
    这个是新鲜的热乎的,针对某个面试题写了的内容,如果有问题欢迎来喷。

    来看看他们的区别

    静态/动态 区别
    静态 由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.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", "张三");
        }
    }
    

    相关文章

      网友评论

        本文标题:JAVA基础之静态代理与动态代理

        本文链接:https://www.haomeiwen.com/subject/wimqtrtx.html