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