什么是代理
就是某一个对象要执行某个任务,但是呢,这个任务又不是由它自己来完成的,而是由另外一个代理对象来代替它完成的,这就是代理模式的定义。
看图:
( https://www.jianshu.com/p/6e962d1e7ddd)
为什么要使用代理
这个问题非常重要,如果搞不清它的使用场景,就不要滥用设计模式。考虑这样一种场景,很多对象X1,X2....Xn的执行逻辑都要包含同一个任务,如果把这个任务提取出来单独作为一个任务,交给Y来执行,Y就是代理对象。其他对象在执行的时候,不是由他们本人来执行,而是由Y来分别调用X1,X2...Xn中的方法来执行,Y就可以在执行X中的方法之前,执行公共任务。这就是Spring AOP的动态代理实现机制。
静态代理
先上代码。有一个接口Person,抽象地表示人,它有一个动作吃饭
/* author:chxy data:2020/3/31 description: */ package proxy2; public interface Person { public void dinner(); }
有一个实现类Man,它具体地实现了吃饭这个动作
/* author:chxy data:2020/3/31 description: */ package proxy2; public class Man implements Person{ @Override public void dinner() { System.out.println("man is having dinner"); } }
Man的吃饭动作无法直接执行,而是由代理类来代替它执行,代理类加入了自己的执行逻辑
/* author:chxy data:2020/3/31 description: */ package proxy2; public class ManProxy implements Person{ private Person target; public ManProxy(Person p){ this.target = p; } @Override public void dinner() { //饭前洗手 System.out.println("washing hands"); target.dinner(); } }
在Demo中执行
/* author:chxy data:2020/3/31 description: */ package proxy2; public class Main { public static void main(String[] args) { Person p = new ManProxy(new Man()); //dinner是由代理类ManProxy来执行的 p.dinner(); } }
执行结果如下:
washing hands
man is having dinner
静态代理就是一个目标类要有一个代理类,如果增加一个类Women,也要有相应的代理类WomenProxy,如果目标类有N个,代理类也要有N个,会导致类的数目爆炸。因此出现了动态代理,目标是:N个目标类,1个代理类。看代码:
增加一个Person的实现类Women
/* author:chxy data:2020/3/31 description: */ package proxy2; public class Women implements Person{ @Override public void dinner() { System.out.println("women is having dinner"); } }
增加一个Handler继承InvocationHandler,实现其中的invoke方法,它是实现动态代理的核心,代理接口中定义的方法的每次调用,都会“经过“这个方法
/* author:chxy data:2020/3/31 description: */ package proxy2; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class PersonHandler implements InvocationHandler { //被代理对象 Person p; public PersonHandler(Person p) { this.p = p; } @Override //proxy:代理对象 //method:被代理的方法 //args:该方法的参数 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //如果吃饭这个动作被调用了, if(method.getName().equals("dinner")){ System.out.println("washing hands"); method.invoke(p); } return null; } }
在main方法,通过Proxy的newProxyInstance()方法得到代理对象,该代理对象实现了第二个参数中的多个接口。直接调用代理对象中的方法实现目标对象中的执行逻辑:
/* author:chxy data:2020/3/31 description: */ package proxy2; import java.lang.reflect.Proxy; public class Main { public static void main(String[] args) { PersonHandler handlerForMan = new PersonHandler(new Man()); final Person man = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),//代理的接口 new Class[]{Person.class},//代理类要实现的接口 handlerForMan);//处理器 man.dinner(); PersonHandler handlerForWomen = new PersonHandler(new Women()); final Person woman = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{Person.class}, handlerForWomen); woman.dinner(); } }
实现的效果是:只用一个代理类(并没有显示写出来)代理了Man类和Women类。