一、代理模式定义
1.代理模式是指为其他对象提供一种代理,以控制对这个对象的访问,属于结构型模式。
2.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
3.代理模式一般包含三种角色:
A.抽象主题角色(Subject):抽象主题类的主要职责是声明真是主题与代理的共同接口方法,该类可以是接口也可以是抽象类
B.真实主题角色(RealSubject):该类也被称为被代理类,该类定义了代理所表示的真实对象,是负责执行系统真正的业务逻辑对象
C.代理主题角色(Proxy):也被称为代理类,其内部持有RealSubject的引用,因此具备完全的对RealSubject的代理权。客户端调用代理对象的方法,同时也调用被代理对象的方法,但是会在代理对象前后增加 一些处理代码
4.在代码中,一般代理会被理解为代码增强,实际上就是在原代码逻辑前后增加一些代码逻辑,而使调用者无感知。代理模式属于结构型模式,分为静态代理和动态代理
5.代理模式的目的:一是保护目标对象,二是增强目标对象
二、代理模式的通用写法
1.代码示例:
1 /** 2 * 代理主题角色 3 */ 4 public interface ISubject { 5 void request(); 6 } 7 8 /** 9 * 真实主题角色 10 */ 11 public class RealSubject implements ISubject { 12 @Override 13 public void request() { 14 System.out.println("real service is called."); 15 } 16 } 17 18 /** 19 * 代理主题角色 20 */ 21 public class Proxy implements ISubject { 22 23 private ISubject subject; 24 25 public Proxy(ISubject subject){ 26 this.subject = subject; 27 } 28 29 @Override 30 public void request() { 31 before(); 32 subject.request(); 33 after(); 34 } 35 36 public void before(){ 37 System.out.println("called before request()."); 38 } 39 40 public void after(){ 41 System.out.println("called after request()."); 42 } 43 } 44 45 public class GeneralProxyTest { 46 public static void main(String[] args) { 47 Proxy proxy = new Proxy(new RealSubject()); 48 proxy.request(); 49 } 50 }
三、动态代理
1.上面通用写法实际上是一种静态代理,动态代理分为jdk动态代理和cglib动态代理
2.jdk动态代理示例
1 public interface IPerson { 2 void findLove(); 3 } 4 5 public class ZhangSan implements IPerson { 6 @Override 7 public void findLove() { 8 System.out.println("肤白貌美大长腿"); 9 } 10 } 11 12 public class JdkMeiPo implements InvocationHandler { 13 14 private IPerson target; 15 16 public IPerson getInstance(IPerson target){ 17 this.target = target; 18 Class<? extends IPerson> clazz = target.getClass(); 19 return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); 20 } 21 22 @Override 23 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 24 before(); 25 Object result = method.invoke(this.target, args); 26 after(); 27 return result; 28 } 29 30 private void before(){ 31 System.out.println("我是媒婆:已经收集到你的需求,开始物色"); 32 } 33 34 private void after(){ 35 System.out.println("双方同意,开始交往"); 36 } 37 } 38 39 public class JdkDynamicProxyTest { 40 public static void main(String[] args) { 41 JdkMeiPo jdkMeiPo = new JdkMeiPo(); 42 IPerson instance = jdkMeiPo.getInstance(new ZhangSan()); 43 instance.findLove(); 44 } 45 46 }
A.jdk动态代理采用字节码重组,重新生成对象来替代原始对象,以达到动态代理的目的。继承Proxy类并实现被代理类的所有接口,重写方法
B.jdk动态代理生成对象步骤:
a.获取被代理对象的引用,并获取它的所有接口,反射获取
b.jdk动态代理类重新生成一个新的类,同时新的类要实现被代理类实现的所有接口
c.动态生成java代码,新加的业务逻辑方法由一定的逻辑代码调用
d.编译新生成的java代码为.class文件
e.重新加载到jvm运行
3.cglib动态代码示例
1 public class Customer { 2 public void findLove(){ 3 System.out.println("有车有房有存款"); 4 } 5 } 6 7 public class CglibMeiPo implements MethodInterceptor { 8 9 public Object getInstance(Class<?> clazz) throws Exception{ 10 Enhancer enhancer = new Enhancer(); 11 enhancer.setSuperclass(clazz); 12 enhancer.setCallback(this); 13 return enhancer.create(); 14 } 15 16 @Override 17 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 18 before(); 19 Object obj = methodProxy.invokeSuper(o,objects); 20 after(); 21 return obj; 22 } 23 24 private void before(){ 25 System.out.println("我是媒婆:我要给你找对象,现在已经确认你的需求"); 26 System.out.println("开始物色"); 27 } 28 29 private void after(){ 30 System.out.println("如果合适的话,就准备办事"); 31 } 32 33 }
A.cglib代理的目标对象不需要实现接口,它是通过动态继承目标对象实现动态代理的
B.cglib会生成三个.class:继承目标类的,代理和被代理的FastClass
C.FastClass机制:为代理类和被代理类各生成一个类,这个类会为代理类或被代理类的方法分配一个index(int类型);这个index当作一个入参,FastClass就可以直接定位要调用的方法并直接进行调用,省去了反射调用,所以调用效率比JDK代理高
4.Cglib和Jdk动态代理对比
A.jdk动态代理实现了被代理对象的接口,cglib代理继承了被代理对象
B.jdk动态代理和cglib代理都在运行期生成字节码,jdk动态代理直接写Class字节码,cglib代理使用ASM框架写Class字节码,cglib代理实现更复杂,生成代理类效率比jdk动态代理低
C.jdk动态代理调用代理方法是通过反射机制调用的,cglib代理是通过FastClass机制直接调用方法的,cglib代理的执行效率更高
四、静态代理和动态代理的本质区别
1.静态代理只能通过手动完成代理操作,如果被代理类增加了新的方法,代理类需要同步增加,违反了开闭原则
2.动态代理采用在运行时生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则
3.若动态代理要对目标类的增强逻辑进行扩展,结合策略模式,只需要新增策略类即可,无须修改代理类的代码
五、代理模式的优缺点
1.优点:
A.代理模式能将代理对象与真实被调用目标对象分离
B.在一定程度上降低了系统的耦合性,扩展性好
C.可以起到保护目标对象的作用
D.可以增强目标对象的功能
2.缺点:
A.代理模式会造成系统设计中类的数量增加
B.在客户端和目标对象中增加一个代理对象,会导致请求处理速度变慢
C.增加了系统复杂度