代理
我们经常利用代理进行解耦以及控制对实际对象的访问等工作。例如,我们可以通过代理对方法的调用进行更精细的控制(例如加上日志、权限控制等),而无需修改实际对象的代码。代理的作用是无侵入式的给代码增加功能。有些事情是对象不想做或者不能做的,就可以通过代理来实现。
代理一般有三种模式:
- 静态代理
- jdk动态代理
- cglib动态代理(这里不做过多赘述)
静态代理
静态代理很简单,我们通过代码来理解就很方便。
package TestProcxy;public class ProTest {public static void main(String[] args) {Father father = new Father();father.eat();}
}class Per{public void eat(){System.out.println("吃饭!!!");}
}class Father{Per per = new Per();public void eat(){System.out.println("拿筷子~~~~");per.eat();System.out.println("洗碗~~~~");}
}
运行结果:
jdk动态代理
代理里面就是对象要被代理的方法。java通过接口来保证代理的样子,即对象和代理要实现同一个接口中的方法就是被代理的所有方法。
代理可以增强或者拦截的方法都在接口中,接口需要写在newProxyInstance的第二个参数里。
package TestProxy;/*** 接口* 通过接口来进行代理*/
public interface Event {void eat(String something);
}package TestProxy;public class Per implements Event {String name;public Per(String name) {this.name = name;}@Overridepublic void eat(String something) {System.out.println(name + "吃" + something + "!!!");}
}package TestProxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class PerProxy {public static Event createProxy(){/*** java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:* public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)* 参数一:用于指定用哪个类加载器去加载生成的代理类* 参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法* 参数三:用来指定生成的代理对象要干什么事情*/Object o = Proxy.newProxyInstance(PerProxy.class.getClassLoader(),new Class[]{Event.class},new InvocationHandler() {/** 参数一:代理的对象* 参数二:要运行的方法 eat* 参数三:调用eat方法时,传递的实参* */@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("拿筷子~~~");method.invoke(new Per("张三"), args);System.out.println("洗碗~~~");return null;}});return (Event) o;}
}package TestProxy;public class ProTest {public static void main(String[] args) {PerProxy perProxy = new PerProxy();Event proxy = perProxy.createProxy();proxy.eat("刀削面");}
}
运行结果:
练习
对List的add方法进行增强,对remove方法进行拦截。
package TestProxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;public class EnhanceList {public static void main(String[] args) {List list = new ArrayList();Object o = Proxy.newProxyInstance(EnhanceList.class.getClassLoader(), new Class[]{List.class}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 对原List的add方法进行增强if (method.getName().equals("add")) {System.out.println("对list新增了" + args[0]);return method.invoke(list, args);} else if (method.getName().equals("remove")) {// 拦截根据索引删除的方法是正常的,如果拦截根据对象删除的方法就会报错,因为他们的返回值不一样System.out.println("拦截了remove方法");return null;} else {return method.invoke(list, args);}}});List proxyList = (List) o;proxyList.add("aaa");proxyList.add("bbb");proxyList.add("ccc");proxyList.add("ddd");proxyList.remove(0);proxyList.remove("aaa");System.out.println(list);}
}
这段代码是由问题的就是在拦截remove方法时的问题,因为remove重载了两种方法,返回值类型也不一样(一个是布尔类型,另一个是对象),而我们在拦截时只返回了null,因此会报错。
运行结果:
正确的修改: