设计模式(一)--代理模式
设计模式是java基础中很重要的一部分,设计模式说白了就是以前的人总结出的套路,就像小说中那些武功秘籍、内功心法一样
设计模式分为三大类:
1、创建型模式(5种):工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
2、结构型模式(7种):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
3、行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式
、中介者模式、解释器模式
设计模式不应该死记硬背、更应该去融会贯通,应用到项目中,可以通过查看框架或者一些优秀开源项目得到启发
本文讲的是代理模式,因为要写关于AOP的随笔了,代理是跳不过去的,所以还是单独写一下吧,方便自己理解、复习
代理模式
生活中有很多代理的例子,很多职业都会有代理(微商、保险等),又或者是一个明星,他的经纪人也是代理,虽然这个代理有时很坑爹。
。。又或者是Spring AOP,代理是一种思想,不只是存在Java
定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用
1、静态代理
SellCar.java为共同接口
public interface SellCar { void sellCar(); }
SellCarImpl.java目标对象
public class SellCarImpl implements SellCar{ @Override public void sellCar() { System.out.println("selll car"); } }
SellCarProxy.java代理类
public class SellCarProxy implements SellCar{ private SellCar sellCar; @Override public void sellCar() { System.out.println("sell car proxy start"); if (null == sellCar) { sellCar = new SellCarImpl(); } sellCar.sellCar(); System.out.println("sell car proxy end"); } }
SellCarTest.java测试类
public class SellCarTest { public static void main(String[] args) { SellCar sellCar = new SellCarProxy(); sellCar.sellCar(); } }
结果:
sell car proxy start
selll car
sell car proxy end
缺点:
目标对象要创建好,作为代理类的内部属性。一个target对应一个proxy,这样如果需要代理的对象很多,难道就要写很多proxy吗?接口内
方法修改了,target对象和proxy对象都要修改。如果我们提前不知道目标对象是什么,这个都是静态代理存在的问题
2、动态代理
动态代理不关心target对象,而是在运行期间生成proxy
2.1).jdk动态代理
jdk自带的,不需要第三方jar包,使用简单但相对功能较弱
SellCarProxy.java
@AllArgsConstructor //生成全参构造器 public class SellCarProxy implements InvocationHandler { private Object target; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("sell car proxy start"); Object o = method.invoke(target, args); System.out.println("sell car proxy end"); return o; } }
SellCarTest.java
public class SellCarTest { public static void main(String[] args) { SellCar sellCar = (SellCar) Proxy.newProxyInstance( SellCarImpl.class.getClassLoader(), SellCarImpl.class.getInterfaces(), new SellCarProxy(new SellCarImpl()) ); sellCar.sellCar(); } }
结果:
sell car proxy start
selll car
sell car proxy end
注意:
第一/二个参数,一定是target类,而不是通用接口类,否则会报错:com.sun.proxy.$Proxy0 cannot be cast to com.it.SellCar,因为你
能去获取接口的interface数组啊
三个参数分别为:加载target的类加载器,target类实现的接口,实现对象
缺点:
只能代理实现接口的类,如果没有接口,将无法使用
2.2).cglib动态代理
CGLib采用了非常底层的字节码技术,总体性能比JDK自带的动态代理好,且功能十分强大其原理是通过字节码技术为一个类创建子类,并在子
类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
首先需要引入jar包
<dependency> <groupId>cglib</groupId> <artifactId>cglib-nodep</artifactId> <version>3.1</version> </dependency>
SellCarProxy.java
public class SellCarProxy implements MethodInterceptor { private Object target; public Object getTarget(Object object) { this.target = object; Enhancer enhancer = new Enhancer(); //设置父类,被代理类(这里是Car.class) enhancer.setSuperclass(this.target.getClass()); enhancer.setCallback(this); // 回调方法 return enhancer.create(); // 创建代理对象 } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("sell car proxy start"); methodProxy.invokeSuper(o, objects); //代理类调用父类的方法 System.out.println("sell car proxy end"); return null; } }
SellCarTest.java
public class SellCarTest { public static void main(String[] args) { SellCarProxy proxy = new SellCarProxy(); SellCar sellCar = (SellCarImpl)proxy.getTarget(new SellCarImpl()); sellCar.sellCar(); } }
结果:
sell car proxy start
selll car
sell car proxy end
2.3).ASM:这个不太懂,实现动态代理效率很高
静态代理和动态代理的区别:
代理类的创建时间不同,静态代理通常只能代理一个类,而动态代理可以代理多个,运行的时候才知道代理的是什么
1、静态代理:是直接创建的代码,对其进行编译。代理类的class文件已经存在
2、动态代理:程序运行过程,由反射机制动态生成
文章参考:公众号-方志朋-一起学设计模式 - 代理模式