Java动态代理

为什么需要代理?
在不修改被代理类代码的条件下,可以对被代理类中的方法进行想要的处理,如添加日志,记录方法运行时间(testNG就有此功能,未修改我们的测试代码,却可以统计每个方法的运行时间)
 
从静态代理作为理解的入口:
何为静态代理?
可对应生活中的,hr统计测试岗位人员信息交给人事部主管。
  首先创建一个Person接口,约束个人信息统计的方法:
public interface Person {
    void giveMessage();
    void fun();
}

  创建员工类:

package day03;

public class Employee implements Person{
    String name;
    Employee(String name){
        this.name = name;
    }

    public void giveMessage(){
        System.out.println("give Message");
    }

    public void fun(){
        System.out.println("other fun");
    }
}

  创建员工代理类,相当于hr类:

public class EmployeePro implements Person{
    Employee employee;
    EmployeePro(Employee employee){
        this.employee = employee;
    }


    public void giveMessage(){
        System.out.println("add logs");
        System.out.println("give Message");

    }

    public void fun(){
        System.out.println("add logs");
        System.out.println("other fun");
    }

}
View Code

 测试下:

public class Test {
    public static void main(String[] args) {
        Employee employee = new Employee("Claire");//创建被代理人
        EmployeePro employeePro = new EmployeePro(employee);//创建代理人对象
        employeePro.giveMessage();//通过代理人来执行相应方法
    }
}
View Code

运行结果:

 

思考:
1.员工类中有2个方法,添加日志的代码就写了2遍,造成代码重复。
 
2.如果要统计开发岗位人员信息交给人事主管呢,又要怎么做?
需要再创建开发岗位的代理类,重写方法并添加日志。
以上缺点很明显:需要手动创建多个代理类,并且添加日志的功能重复N遍。
 
动态代理便很好的解决了该问题,下面是动态代理的实现方式:
 
创建一个类实现InvocationHandler:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

//该类使用泛型,可以支持作为任何类的InvocationHandler,如果不理解,可以直接写成非泛型
public class MyInvocationHandler<T> implements InvocationHandler {
    T target;//需要关联的被代理对象,这里将代理与被代理关联起来
    MyInvocationHandler(T target){
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("add log");//在方法执行之前添加日志
        Object result = method.invoke(target, args);//这里是通过反射调用target对象的method方法,参数是args
        return result;
    }
}
View Code

测试下:

import java.lang.reflect.Proxy;

public class ProxyTest {
    public static void main(String[] args) {
        //创建被代理人
        Person employee = new Employee("claire");
        //创建代理对象
        Person employeePro = (Person) Proxy.newProxyInstance(ProxyTest.class.getClassLoader(), new Class<?>[]{Person.class}, new MyInvocationHandler<Person>(employee));
        //代理对象执行相应方法
        employeePro.giveMessage();
        employeePro.fun();
    }
}
View Code

 

测试结果是:

 

我们还可以使用匿名类的方式来实现,代码就更简洁了,如下:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTestAnonymous {
    public static void main(String[] args) {
        Person employee = new Employee("claire");
        Person emplPro = (Person) Proxy.newProxyInstance(ProxyTestAnonymous.class.getClassLoader(), new Class<?>[]{Person.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("add logs");//方法调用前添加日志
                Object result = method.invoke(employee, args);
                return result;
            }
        });

        emplPro.fun();
        emplPro.giveMessage();
    }
}
View Code

 

 

以上我们就使用动态代理解决了上面提出的问题。

 

但是可以发现,Java自带动态代理,被代理类必须有对应的实现接口,这就比较受限了。

 

posted @ 2020-05-20 09:42  小屁妞  阅读(230)  评论(0编辑  收藏  举报