代理模式(Proxy)
代理模式就是为其他对象提供一种代理功能以控制对被代理对象的访问,其作用就是通过一个中间层达到间接访问目标对象的目的。
代理模式分为静态代理和动态代理
静态:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。
动态:在程序运行时运用反射机制动态创建而成。
2、动态代理
在上一节中的静态代理中,一个代理只能代理一种类型,而且是在编译器就已经确定被代理的对象。而动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象。动态代理有两种方式jdk动态代理和cglib动态代理。
2.1 jdk动态代理
使用jdk的代理机制必须要求被代理类实现一个具体接口,这样在生成的代理类才能知道重写哪些方法。jdk动态代理会生成一个被代理类所实现的接口的方法,如果没有实现任何接口,jdk代理机制则无法进行代理,解决办法就是使用cglib的代理机制进行代理。
java动态代理类主要位于Java.Long.reflect包下,一般主要涉及以下两个类:
- Proxy:提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
- InvocationHandler:是代理实例调用处理程序实现的借口,每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的invoke方法中。
具体代码
//坦克类实现一个Movable借口,并实现里面的move方法
public class Tank implements Movable {
@Override
public void move() {
System.out.println("Tank moving clsclacla...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Tank tank = new Tank();
//System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles","true");
//生成$Proxy0.class
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
/**
* 参数一:代理类的类加载器
* 参数二:被代理接口类数组
* 参数三:要实现的处理方法
*/
Movable m = (Movable) Proxy.newProxyInstance(Tank.class.getClassLoader(),
new Class[]{Movable.class},
new LogHandler(tank));
m.move();
}
}
public interface Movable {
void move();
}
//处理程序
public class LogHandler implements InvocationHandler {
Movable move;
public LogHandler(Movable m) {
this.move = m;
}
public void before(){
System.out.println("method start...");
}
public void after(){
System.out.println("method end...");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object obj = method.invoke(move, args);
after();
return obj;
}
}
根据下图的反编译文件$Proxy.class和相关源码可知代理对象m是如何调用LogHandler中的invoke方法的:
总结
优点:代理对象无需实现接口,免去了编写很多代理类的烦恼,同时接口增加方法也无需再维护目标对象和代理对象,只需在事件处理器中添加对方法的判断即可。
缺点:代理对象不需要实现接口,但是目标对象一定要实现接口,否则无法使用JDK动态代理。
2.2 cglib动态代理
具体代码
public class Tank{
public void move() {
System.out.println("Tank moving clsclacla...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Tank.class);
enhancer.setCallback(new TimeMethodInterceptor());
Tank tank = (Tank)enhancer.create();
tank.move();
}
}
/**
* 动态没生成代理对象
* 实现 MethodInterceptor方法代理接口,创建代理类
* 当访问代理中的方法时,委派给MethodInteceptor中的处理程序(intercept方法)进行出来,
* 在处理程序中添加了业务逻辑和回掉了被代理目标中的方法。
*/
public class TimeMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before");
Object res = null;
res = methodProxy.invokeSuper(o,objects);
System.out.println("after");
return res;
}
}
注意:使用cglib需要引入
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>