代理模式

代理模式是SpringAOP的底层!

分类:

  • 静态代理
  • 动态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
  • 客户:访问代理对象的人
    在这里插入图片描述

代码步骤:

  1. 接口
  2. 真实角色
  3. 代理角色
  4. 客户端访问代理

一、静态代理

// 接口:租房业务
public interface Rent {
    public void rent();
}

// 真实角色-房东:具有租房功能
class Host implements Rent{
    @Override
    public void rent() {
        System.out.println("房东要出租房子🏠");
    }
}

// 代理角色:代理房东出租房子,同样具有出租房子的功能。代理的附加功能可以看作对房东租房子功能的增强。
class Proxy implements Rent{
    private Host host;

    public Proxy() {}

    public Proxy(Host host) {
        this.host = host;
    }

    @Override
    public void rent() {
        seeHouse();
        host.rent();
        fare();
    }
    
    //代理的附加功能1
    public void seeHouse(){
        System.out.println("代理帮助房东介绍房子给用户👦");
    }
    //代理的附加功能2
    public void fare(){
        System.out.println("代理向房东收取代理费用💵");
    }
}
// 客户:访问代理,解决需求
public class Client {
    public static void main(String[] args) {
        //房东亲自出租房子
        Host host = new Host();
        host.rent();
        System.out.println("====================");

        //代理帮助房东出租房子
        Proxy proxy = new Proxy(host);
        proxy.rent();
    }
}

输出:
在这里插入图片描述
好处:

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务!
  • 公共业务交给代理角色,实现了业务的分工!
  • 公共业务发生扩展的时候,方便集中管理!

缺点:

  • 一个真实对象就会产生一个代理对象,代码量会翻倍~开发效率变低~

加深理解(AOP):
在这里插入图片描述

二、动态代理

动态代理的代理类是动态生成的,不是直接写好的!

动态代理分为两大类:基于接口的动态代理、基于类的动态代理

  • 基于接口:JDK动态代理
  • 基于类:cjlib动态代理
  • java字节码实现:javasist
1. JDK动态代理

两个关键类:Proxy:代理、InvocationHandler:调用处理程序

// 租房业务
interface RentBusiness {
    public void rent();
}

//房东:具有租房功能
class Host implements RentBusiness{
    @Override
    public void rent() {
        System.out.println("房东要出租房子🏠");
    }
}

//程序处理角色
class ProxyInvocationHandler implements InvocationHandler {
    //被代理的角色
    private Object represented;
    public void setRepresented(Object represented){
        this.represented = represented;
    }

    //生成得到代理类
    public Object getProxy(){
        //三个参数:classloader、interface、invocationHandler
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), represented.getClass().getInterfaces(),this);
    }

    //处理代理实例,并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //前置增强
        seeHouse();
        //动态代理的本质,就是使用反射机制实现
        Object result = method.invoke(represented,args);
        //后置增强
        fare();
        return result;
    }

    public void seeHouse(){
        System.out.println("代理帮助房东介绍房子给用户👦");
    }

    public void fare(){
        System.out.println("代理向房东收取代理费用💵");
    }
}
public class Client {
    public static void main(String[] args) {
        //代理角色现在没有
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        //设置被代理角色
        pih.setRepresented(new Host());
        //动态生成代理角色
        RentBusiness Proxy  = (RentBusiness)pih.getProxy();
        //代理角色调用相关接口的方法时,会自动调用invoke方法,在接口方法执行前后做增强
        Proxy.rent();
    }
}

输出:
在这里插入图片描述
关键:
被代理的角色时object类型,所以该程序处理角色,可以对任意类型的被代理角色进行代理,实现被代理角色任意方法的增强。

总结:

  • Proxy 通过 Proxy.newProxyInstance 动态生成代理对象,可代理任意类型的对象,且拥有一个相关联的调用处理程序。
  • InvocationHandler 是由代理实例调用的处理程序实现的接口
    每个代理实例都有一个关联的调用处理程序,当代理实例调用方法时,会触法自动执行调用处理程序实现的 invoke 方法。
2. cglib动态代理

CGLIB(Code Generator Library)是一个强大的、高性能的代码生成库。其被广泛应用于AOP框架(Spring、
dynaop)中,用以提供方法拦截操作。

CGLIB相比于JDK动态代理更加强大,JDK动态代理虽然简单易用,但是其有一个致命缺陷是,只能对接口进行代理。如果要代理的类为一个普通类、没有接口,那么Java动态代理就没法使用了。

CGLIB底层使用了ASM(一个短小精悍的字节码操作框架)来操作字节码生成新的类。除了CGLIB库外,脚本语言(如Groovy何BeanShell)也使用ASM生成字节码。ASM使用类似SAX的解析器来实现高性能。我们不鼓励直接使用ASM,因为它需要对Java字节码的格式足够的了解。

//房东:具有租房功能
public class Host {
    public void rent() {
        System.out.println("房东要出租房子🏠");
    }
}
public class Client {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Host.class);
        enhancer.setCallback(new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                System.out.println("代理帮助房东介绍房子给用户👦");
                Object invoke = method.invoke(new Host(), objects);
                System.out.println("代理向房东收取代理费用💵");
                return invoke;
            }
        });
        // 代理角色
        Host agent = (Host) enhancer.create();
        agent.rent();
    }
}

输出:
在这里插入图片描述
需要引入如下两个jar包
在这里插入图片描述
Enhancer可能是CGLIB中最常用的一个类,和Java1.3动态代理中引入的Proxy类差不多。和Proxy不同的是,Enhancer既能够代理普通的class,也能够代理接口。Enhancer创建一个被代理对象的子类并且拦截所有的方法调用(包括从Object中继承的toString和hashCode方法)。Enhancer不能够拦截final方法,例如Object.getClass()方法,这是由于Java final方法语义决定的。基于同样的道理,Enhancer也不能对fianl类进行代理操作。这也是Hibernate为什么不能持久化final class的原因。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值