一、代理模式定义

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.增加了系统复杂度