Java 动态代理笔记

本随笔为 《十分钟了解java动态代理》 笔记

代理模式

三要素:

  1. 接口:接口定义了服务要提供什么样的能力
  2. 提供服务的真实对象:一定要继承接口,来提供服务。别人不能直接访问这个对象,一定要通过代理去访问
  3. 代理对象:包含真实对象,从而操作真实主体对象,相当于访问者与真实对象的中介

两动作:

  1. 公共接口:真实对象和代理对象都必须同时继承同一个接口
  2. 代理对象必须包含真实的对象

动态代理

动态代理

例子:

约妹子王美丽。由于我是一个正经人,因此不能直接去约她。要通过她的家人,征得同意后授权之下才能去联系王美丽。王美丽的家人就是王美丽的代理。

注意点:

  1. 客户端不能直接访问对象,一定要通过代理对象访问
  2. 动态:王美丽的家人有很多,谁有用找谁。

Java的动态代理

Proxy和InvocationHandler对象就组成了动态代理:

  1. Proxy
    • 一个调度器:约王美丽的时候,联系她的家人,每个人不一定有时间,这个调度器总会找一个人来为你服务。
  2. InvocationHandler
    • 是一个增强器:约王美丽,王美丽只看中颜值,只要小伙子颜值够了就跟他约会。但是王美丽的家人要对王美丽负责,所以小伙子约王美丽的时候,家人要做“增强”——事前调研一下小伙子有没有钱、房子、车,有没有离过婚;事后增强——约会干了些啥,问王美丽小伙子怎么样。

代码

三大要素之一:Girl 接口

public interface Girl {
    
    void date();
    
    void watchMovie();
    
}

实现类:WangMeiLi

public class WangMeiLi implements Girl {
    
    @Override
    public void date() {
        System.out.println("王美丽说:跟你约会很开心!");
    }
    
    @Override
    public void watchMovie() {
        System.out.println("王美丽说:这个电影我不喜欢看。");
    }
    
}

三大要素之一:动态代理对象 InvocationHandler

/**
 * 增强器,只需要实现一个方法invoke(),业务就增强了
*/
public class WangMeiLiProxy implements InvocationHandler {
    
    // 代理对象必须把真实提供服务对象RealSubject包含进来
    // 代理是不能提供服务的,真正提供服务的是RealSubject
    private Gril girl;
    
    public WangMeiLiProxy(Girl girl) {
        super();
        this.girl = girl;
	}
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        doSomethingBefore();	// 前置增强
        Object ret = method.invoke(girl, args);	// Java 反射:调用 某个对象的方法,同时传递一些参数
        doSomethingEnd();		// 后置增强
        
        return ret;
    }
    
    public void doSomethingBefore() {
        System.out.println("王美丽的父母说:我得先调查下这个男孩子的背景!");
    }
    
    public void doSomethingEnd() {
        System.out.println("王美丽的父母说:他有没有对你动手动脚啊?");
    }
    
    // Proxy就是调度者
    public Object getProxyInstance() {
        // Proxy的核心静态方法newProxyInstance
        // this -> InvocationHandler
        return Proxy.newProxyInstance(girl.getClass().getClassLoader(), girl.getClass().getClassLoader().getInterfaces(), this);
    }
    
}

调用者:Lison

public class Lison {
	public static void main(String[] args) {
        // 隔壁有个女孩,叫王美丽
        Girl girl = new WangMeiLi();
        // 她有一个庞大的家庭,想要跟她约会必须征得她家里人的同意
        WangMeiLiProxy family = new WangMeiLiProxy(girl);
        // 有一次我去约王美丽,碰到了她的妈妈,我征得了她妈妈的同意
        // 即通过Proxy.newProxyInstance方法找出来一个人
        Girl mother = (Girl) family.getProxyInstance();
        // 通过她妈妈这个代理才能与王美丽约会
        mother.date();
        System.out.println("--------------------------------");
        // 通过她的妈妈这个代理才能与王美丽看电影
        mother.watchMovie();
    }
}

执行结果:

王美丽的父母说:我得先调查下这个男孩子的背景!
王美丽说:跟你约会很开心!
王美丽的父母说:他有没有对你动手动脚啊?
--------------------------------
王美丽的父母说:我得先调查下这个男孩子的背景!
王美丽说:这个电影我不喜欢看。
王美丽的父母说:他有没有对你动手动脚啊?

对于王美丽来讲,她只关心Lison的颜值。但是对于她的父母(前、后置增强),要关心这个男孩子的所有情况。

上述结果类似于事务:开启事务—执行业务代码—提交事务。体现了动态代理是所有AOP类注解的本质!

posted @ 2021-07-14 12:29  0202zc  阅读(78)  评论(0编辑  收藏  举报