代理
我们经常利用代理进行解耦以及控制对实际对象的访问等工作。例如,我们可以通过代理对方法的调用进行更精细的控制(例如加上日志、权限控制等),而无需修改实际对象的代码。代理的作用是无侵入式的给代码增加功能。有些事情是对象不想做或者不能做的,就可以通过代理来实现。
代理一般有三种模式:
- 静态代理
- 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;
}
@Override
public 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方法时,传递的实参
* */
@Override
public 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() {
@Override
public 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,因此会报错。
运行结果:
正确的修改: