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方法中修改代码,即修改了所有代理的方法,减少了代码量。

posted @ 2018-08-20 16:29  第二人生Bonnie  阅读(221)  评论(0编辑  收藏  举报