zoukankan      html  css  js  c++  java
  • java静态代理和动态代理

    
    

    代理的概念:代理类和委托类实现了相同的接口,在代理类的方法中调用委托类的方法。

    静态代理:指手动创建代理类。

    看一个静态代理的具体例子:

    Person接口:

    public interface Person {
        void giveMoney();
    }

    委托类Student,实现了Person接口。

    public class Student implements Person{
        private String name;
        public Student(String name){
            this.name=name;
        }
        @Override
        public void giveMoney() {
            System.out.println(name+"交学费");        
        }
    }

    代理类ProxyStudent,也实现了Person接口。

    /**
     * 学生代理类,和委托类一样实现了Person接口
     * @author xmanager
     *
     */
    public class StudentProxy implements Person{    
        //被代理的学生
        private Student s;
        
        public StudentProxy(Person p){
            //只代理学生对象
            if(p.getClass()==Student.class){
                s=(Student) p;
            }
        }
        
        @Override
        public void giveMoney() {
            //代理上交班费,调用被代理学生的上交班费行为
            s.giveMoney();
        }    
    }

    这样ProxyStudent就代理Student类上交了班费。

    做一个测试:

    public class AgentTest {
        public static void main(String[] args){
            Student s=new Student("张三");
            StudentProxy proxy=new StudentProxy(s);
            proxy.giveMoney();
        }
    }

    这样就用代理类代理了委托类,实现了交学费的功能。

    那么这样做的好处或者目的是什么呢?对StudentProxy 类稍作修改:

    /**
     * 学生代理类,和委托类一样实现了Person接口
     * @author xmanager
     *
     */
    public class StudentProxy implements Person{    
        //被代理的学生
        private Student s;
        
        public StudentProxy(Person p){
            //只代理学生对象
            if(p.getClass()==Student.class){
                s=(Student) p;
            }
        }
        
        @Override
        public void giveMoney() {
            System.out.println("做事情A");
            //代理上交班费,调用被代理学生的上交班费行为
            s.giveMoney();
            System.out.println("做事情B");
        }    
    }

    可以看到在调用giveMoney()方法前后,分别做了事情A和B。代理模式就是在代理引用实际对象时引入一定程度的间接性,因为这种间接性,可以附加很多用途。

    动态代理:代理类不是提前创建好的,而是在代码运行时生成的。

    通过java.lang.reflect下的Proxy类和InvocationHandler类,可以完成动态代理的自动生成。

    创建StuInvocationHandler类:

    public class StuInvocationHandler<T> implements InvocationHandler{
        //被代理的类
        T target;
        
        public StuInvocationHandler(T target){
            this.target=target;
        }
        /**
         * proxy:被代理对象
         * method:正在执行的方法
         * args:传入方法的参数
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            Object result=method.invoke(target, args);
            return result;
        }
    
    }

    创建代理对象并调用方法:

    public class ProxyTest {
        public static void main(String[] args) throws FileNotFoundException{
            //1、创建被代理对象
            Person zhangsan=new Student("zhangsan");
            //2、创建与被代理对象相关的InvocationHandler对象
            InvocationHandler stuHandler=new StuInvocationHandler<Person>(zhangsan);
            //3、创建与InvocationHandler相关的代理类
            /* newProxyInstance方法参数说明:
             * @param   loader the class loader to define the proxy class
             * @param   interfaces the list of interfaces for the proxy class
             *          to implement
             * @param   h the invocation handler to dispatch method invocations to
             * @return  a proxy instance with the specified invocation handler of a
             *          proxy class that is defined by the specified class loader
             *          and that implements the specified interfaces
             */          
            Person stuProxy=(Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);
            //4、代理执行方法
            stuProxy.giveMoney();//执行代理类的方法时,都会替换为去执行StuInvocationHandler类的invoke方法
            stuProxy.giveMoney2("123");
        
        }
    }

    当执行stuProxy.giveMoney();代码时,就会跳转到执行StuInvocationHandler类的invoke方法。

    另外可以不用Proxy.newProxyInstance方法,可以直接调用代理类的invoke方法。代码如下:

    public class Student{
        public void print() {
            System.out.println("student");
        }
    
        public void printname(String name) {
            System.out.println("mame is "+ name);
        }
    }
    
    public class ProxyTest {
        public static void main(String[] args)throws Exception,Throwable{
            Student s=new Student();
            StuInvocationHandler<Student> s1=new StuInvocationHandler<>();
            Method method=Student.class.getMethod("print",null);
            s1.invoke(s,method,null);
            Method method1=Student.class.getMethod("printname", String.class);
            s1.invoke(s,method1,new Object[]{"bonnie"});
        }
    }

    打印输出:

    before
    student
    after
    before
    mame is abc
    after

     

    动态代理的好处:可以统一管理动态代理所代理的方法。可以在invoke方法中修改代码,即修改了所有代理的方法,减少了代码量。

  • 相关阅读:
    golang 反射和利用反射取结构体值
    golang 实现Lru
    跨域
    JS原型链
    cookie 、sessionStorage与localStorage的区别
    计算真实div盒子的宽度和高度
    div水平垂直居中
    清除浮动的几种方法
    JS中for循环和定时器的小问题
    转换字符串和转换数字类型
  • 原文地址:https://www.cnblogs.com/BonnieWss/p/9504744.html
Copyright © 2011-2022 走看看