代理模式
静态代理:
静态得代理模式和装饰器模式十分相像,语法也是差不多,但是他们俩个逻辑思想上不太相同得,代理模式是代理对象来代理被代理对象并可以对代理对象进行一系列的增强(enhance)操作。装饰器模式的主要思想是,为一个主体类加上需要装饰的内容,而且装饰器中进行嵌套的时候传入的是java类。而代理模式传入的是接口。下面是基本的静态代理UML图

public class Tank implements Movable{
public static void main(String[] args){
TimeProxy tp = new TimeProxy(new Tank);
TankLogProxy tlp = new TankLogProxy(tp);
tp.move();
tlp.move();
}
/**
* 模拟坦克移动了一段儿时间
*/
@Override
public void move() {
System.out.println("Tank moving claclacla...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class TimeProxy implements Movable{
Movable m;
public TimeProxy( Movable m){
this.m = m;
}
public void move (){
System.out.println("start moving...");
m.move();
long end = System.currentTimeMillis();
System.out.println("stopped!");
}
}
class TankLogProxy implements Movable {
Movable m;
public TankLogProxy(Movable m) {
this.m = m;
}
@Override
public void move() {
System.out.println("start moving...");
m.move();
long end = System.currentTimeMillis();
System.out.println("stopped!");
}
}
interface Movable{
void move();
}
JDK动态代理
JDK动态代理是Jdk默认带的代理模式,因为静态代理模式的代码,他只能固定实现某一接口代理,或者是直接将代理对象设置为Object类型的对象,这样的话,在进行获取对象的时候需要进行类型的强制转换。十分不方便。为了解决这种问题,就产生了动态代理,JDK默认的动态代理必须要有接口,没有接口的话不能进行实现。
//Proxy对象中的 ProxyGenerator.generateProxyClass()方法是生成指定的代理类方法,他的底层是通过ASM来进行操作二进制码来生成代理对象的。生成的代理对象是看不见的。如果想要在自己的项目中看见代理对象的话。需要设置:ProxyGenerator中的saveGeneratedFiles属性值,该属性值为true的时候就会生成代理对象,生成的代理对象是class字节码文件,使用IDEA反编译之后我们可以看见里面有生成的代理方法,里面做了一些前置和后置的处理。并且还会增加toString() hashCode() 等方法。(生成的代理对象在最下方)
public class Tank implements Movable{
public static void main(String[] args){
Movable m = (Movable)Proxy.newProxyInstance(Tank.class.getClassLoader(), new Class[]{Movable.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method start..");
Object o = method.invoke(this,args)
System.out.println("method end..");
return o;
}
});
}
/**
* 模拟坦克移动了一段儿时间
*/
@Override
public void move() {
System.out.println("Tank moving claclacla...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
interface Movable{
void move();
}
CGlib动态代理
因为JDK默认的动态代理模式,必须要有接口才能够实现,加入没有接口的话就不能够实现了么,为了解决这个问题就有了CGlib动态代理。CGlib动态代理可以在没有接口的情况下就能生成代理对象。但是final不能进行代理。因为CGlib和JDK动态代理一样,也是实现了ASM,也是通过直接修改二进制文件来生成class文件。如果通过ASM修改final代理类,将final去掉的话也是可以进行代理的。Spring使用的动态代理就是CGlib。
具体代码如下:
public class Main{
public static void main(String[] args){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Tank.class);
//第一种形式
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println(o.getClass().getSuperclass().getName());
System.out.println("before");
Object result = null;
result = methodProxy.invokeSuper(o, objects);
System.out.println("after");
return result;
});
//第二种形式
enhancer.setCallback(new TimeMethodInterceptor());
Tank tank = (Tank)enhancer.create();
tank.move();
}
}
class TimeMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println(o.getClass().getSuperclass().getName());
System.out.println("before");
Object result = null;
result = methodProxy.invokeSuper(o, objects);
System.out.println("after");
return result;
}
}
class Tank {
public void move() {
System.out.println("Tank moving claclacla...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
生成的代理对象 Proxy0
package com.mashibing.dp.proxy.v10;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
final class $Proxy0 extends Proxy implements Movable {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void move() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.mashibing.dp.proxy.v10.Movable").getMethod("move");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
网友评论