静态/动态代理模式

静态/动态代理模式

一、代理模式

AOP的底层机制就是动态代理!

代理模式:代理模式就是给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来说代理模式就是生活中常见的中介。

如下图所示:

  1. 用户只需要关心接口的功能,而不需要关心是谁提供了这个功能。

  2. 正在实现这个接口功能的是RealSubject,但是在开发过程中用户不直接与其接触而是通过代理来实现。

  3. 代理就是图中的Proxy,他也实现了接口功能并与客户直接接触

  4. 用户在调用Proxy时,Proxy内部调用了RealSubject。所以Proxy相当于中介,而且可以增强RealSubject的功能。

  • 静态代理

  • 动态代理

静态代理

静态代理角色分析:

  • 抽象角色:一般使用接口或者抽象类来实现

  • 真实角色:被代理的角色

  • 代理角色:代理真实角色;代理真实角色后一般会做一些附属操作。

  • 客户:使用代理角色来进行一些操作

代码实现

Rent.java 即抽象角色

    //抽象角色:租房
    public interface Rent {
        void rent();
    }

 

Host.java:真实角色

//真实角色:房东,房东要出租房子
public class Host implements Rent {
​
    @Override
    public void rent() {
        System.out.println("房屋出租!");
    }
}

 

RentProxy.java:代理角色

public class RentProxy implements Rent {
​
    private Host host;
​
    public RentProxy(final Host host){
        this.host = host;
    }
​
​
    @Override
    public void rent() {
        see();
        host.rent();
        fare();
​
    }
​
    public void see(){
        System.out.println("带客户看房!");
    }
​
    public void fare(){
        System.out.println("收中介费!");
    }
}

 

测试代码(客户)

public class MyTest {
​
    @Test
    public void test(){
        //房东要租房
        Host host = new Host();
        
        //中介去帮助房东
        RentProxy bhp = new RentProxy(host);
        
        //你去找中介
        bhp.rent();
    }
}

 

分析:在这个过程中,我们并没有直接接触到房东,而是去找中介帮我们租房子,这就是所谓的代理模式。

静态代理的好处:

  • 使我们真实地角色更加存粹,不需要关心无关的事情

  • 其他的事情可以由代理来完成,实现了业务的分工

  • 其他的事务发生扩展时容易

缺点:

  • 类多了,多了代理类,工作量变大,开发效率变低

动态代理

  • 动态代理的角色和静态代理的一样

  • 动态代理的代理类是动态生成的,静态代理的代理类是我们提前写好的

  • 动态代理分为两种:一类是基于接口动态代理,一类是基于类的动态代理

    • 基于接口的动态代理:JDK动态代理

    • 基于类的动态代理:cglib

    • 现在用的较多的是javasist来生成的动态代理

JDK的动态代理需要了解两个类

核心:

  • InvocationHandler:调用处理程序

    Object invoke(Object proxy, Method method, Object[]args);
        参数:
            proxy - 调用该方法的代理实例
            method - 代理实例的接口方法的实例
            args - 方法的参数(理解的是这个意思)

     

  • Proxy

     public static Object newProxyInstance(ClassLoader loader,
                                           Class<?>[] interfaces,
                                           InvocationHandler h)
      throws IllegalArgumentException
         参数:
            loader:用哪个类加载器去加载代理对象
            interfaces:动态代理需要实现的接口
            h:动态代理方法在执行时,会调用h里面的invoke方法去执行

     

    代码实现:

    Rent.java 抽象角色

    //抽象角色:租房
    public interface Rent {
        void rent();
    }

     

    Host.java 真实角色

    //真实角色:房东,房东要出租房子
    public class Host implements Rent {
    ​
        @Override
        public void rent() {
            System.out.println("房屋出租!");
        }
    }

     

    ProxyInvocationHandler.java 代理角色

    package com.aishimin.dao;
    ​
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    ​
    public class ProxyInvocationHandler implements InvocationHandler {
        private Rent rent;
    ​
        public void setRent(Rent rent){
            this.rent = rent;
        }
    ​
        //生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色
        public Object getProxy(){
            return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
        }
    ​
        //在程序执行getProxy方法时,程序会自动跳转到这个方法执行
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            seeHouse();
            //核心:本质上用反射来实现!
            Object result = method.invoke(rent,args);
            fare();
            return result;
        }
    ​
        public void seeHouse(){
            System.out.println("带房客看房!");
        }
        public void fare(){
            System.out.println("收中介费!");
        }
    }

     

    测试:

    @Test
    public void test2(){
        //真实角色
        Host host = new Host();
        
        //代理实例的调用处理程序
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        
        //将真实地角色放置进去
        pih.setRent(host);
        
        //动态生成对应的代理类
        Rent proxy = (Rent) pih.getProxy();
        proxy.rent();
    }

     

    深化理解:

    实现一个通用的实现动态代理的类!

    public class ProxyInvocationHandler implements InvocationHandler {
    ​
        private Object target;
    ​
        public void setRent(Object target){
            this.target = target;
        }
    ​
        public Object getProxy(){
            return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            log(method.getName());
            Object result = method.invoke(target,args);
            return result;
        }
    ​
        public void log(String methodName){
            System.out.println("执行了"+methodName+"方法");
        }
    }

     

动态代理的好处:

静态代理有的优点动态代理都有:

  • 一个动态代理,一般代理的是某一类业务

  • 一个动态代理可以代理多个类,代理的是接口!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2021-02-27 19:35  aishimin  阅读(54)  评论(0)    收藏  举报