设计模式之代理模式
代理模式是设计模式的一种,简单解释就是不直接访问目标对象,通过访问代理对象就可以实现对目标对象的访问。就像现在买火车票,不用直接去火车站买,可以直接去各个代售点或者APP上购买,这里的代售点或者APP就是火车站的代理,这样做的好处是,不用修改目标对象,可以在代理对象中增加额外的操作,达到扩展目标对象的目的
Java中主要有三种方式:静态代理,JDK动态代理,cglib代理。前两种代理方式都是通过接口代理,cglib可以实现代理类。
静态代理
静态代理中代理对象和被代理对象都需要实现同一个接口,才能达到代理的目的。
这样做就会存在不好的地方,当修改接口时,代理对象和被代理对象都需要修改,耦合性太大,不容易维护,同时可能会产生过多的代理类。
静态代理代码实现
定义一个接口:
1 | public interface IBaseDao { |
需要代理的目标类,需要实现IBaseDao接口:
1 | public class StaticProxyTarget implements IBaseDao { |
代理类,需要实现IBaseDao接口:
1 | public class StaticProxy implements IBaseDao { |
测试静态代理:
1 | public class ProxyTest { |
输出结果:
1 | start transaction |
JDK动态代理
JDK动态代理是利用Java API,动态的生成代理对象,达到代理目标对象的作用。
与静态代理不同的是,动态代理是在Java运行时动态生成字节码,并加载到jvm中运行,没有.class文件,静态代理编译后会产生.class文件。
定义一个接口:
1 | public interface IBaseDao { |
需要代理的目标类,需要实现IBaseDao接口:1
2
3
4
5
6
7public class DynamicProxyTarget implements IBaseDao{
public void save() {
System.out.println("save data");
}
}
动态代理类:
其中Proxy提供了用于创建动态代理对象的static方法。
主要用到了下面这个方法,可以直接创建一个动态代理对象,该代理对象的实现类实现了interfaces指定的系列接口,执行代理对象的每个方法时都会被替换成InvocationHandler的invoke方法。1
2
3static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
1 | public class DynamicProxy { |
测试JDK动态代理:
1 | public class ProxyTest { |
结果输出:
1 | start transaction |
cglib代理
cglib (Code Generation Library )是一个第三方代码生成类库,可以在运行时在内存中动态生成一个子类对象,从而实现对目标对象功能的扩展。Spring框架中的AOP就使用了cglib。
cglib和上面两种代理最大的不同就是,被代理类不需要实现接口,就可以实现对目标对象的代理,代码侵入性更小。
需要代理的目标类:
1 | public class CglibProxyTarget { |
cglib代理类,需要实现MethodInterceptor接口:
1 | public class CglibProxy implements MethodInterceptor { |
测试结果:
1 | public class ProxyTest { |
结果输出:
1 | start transaction |
总结
- 静态代理代理对象和被代理对象都需要实现同一个接口,实现简单,但是耦合性太大,不便于维护。
- JDK动态代理需要被代理对象实现业务接口,代理对象中实现InvocationHandler接口,通过Java反射生成代理,但是动态生成的代理更加灵活。
- 静态代理编译后产生.class文件,比JDK反射性能好,cglib是通过字节码生成代理,性能高于反射,但是cglib会生成子类继承被代理对象,所以被代理对象不能为final。
代码很简单,需要理解的是思想,代理模式运用广泛,很多框架中都使用了代理模式,只是设计更复杂,个人笔记,如有不对请指出。