前言
其实之前写过类似一篇了,重新具体的总结一下
代理模式
为什么要学习代理模式?因为这就是SpringAOP的底层!【SpringAOP 和 SpringMVC】面试必定
代理模式的分欸:
- 静态代理
- 动态代理
代理的原型:
静态代理
角色分析:
- 抽象角色:一般会用接口或者抽象类来解决(这里指的是外卖平台和餐厅的共同目标”赚钱“)
- 真实角色:被代理的角色(厨师、餐厅)
- 代理角色:代理真实角色,代理真实角色后,通常会进行一些附属操作…(外卖平台)
- 客户:访问代理对象的人!(这里指的是要吃饭的人)
代理模式的好处:
- 可以使真实角色的操作更加纯粹!,不用去关注一些公共的业务
- 公共业务就交给了代理角色!实现了业务的分工!
- 公共业务发生扩展的时候,方便集中管理!
缺点:
- 一个真实角色就会产生一个代理角色,代码量翻倍~开发效率会变低
- 缺点解决的办法就是动态代理
代码步骤
- 接口
// 卖吃的(赚钱)publicinterfaceSell{publicvoidsell();}- 真实角色
// 厨师:真实角色publicclassChefimplementsSell{@Overridepublicvoidsell(){System.out.println("cike_y真实厨师:快来我这里点吃的吧");}}- 代理角色
// 少用继承(局限性很大)、多用组合的方式publicclassproxyimplementsSell{@Overridepublicvoidsell(){System.out.println("外卖平台开始代理厨师的话:");chef.sell();//帮真实角色(厨师)代理他说的话// 下面是外卖平台(中介代理)的附属操作System.out.println("外卖平台(中介代理)开始附属以下操作了:\n");SeeRider();SendOrder();GiveMoney();TakeCommission();TakeRiderFee();}// 组合privateChefchef;publicproxy(){}publicproxy(Chefchef){this.chef=chef;}// setProxy(){..} 没必要set注入// 代理可以做一些附属的事情publicvoidSeeRider(){// 找骑手System.out.println("帮你寻找骑手中……");}// 收取佣金publicvoidTakeCommission(){System.out.println("外卖平台收取佣金");}// 骑手费用publicvoidTakeRiderFee(){System.out.println("给骑手小费");}// 发送客户订单publicvoidSendOrder(){System.out.println("发送客户订单");}// 给餐厅钱publicvoidGiveMoney(){System.out.println("给餐厅钱");}}- 客户端访问代理角色
publicclassClient{publicstaticvoidmain(String[]args){// 想点这家餐厅做的菜Chefchef=newChef();// 外卖平台,帮你通知厨师做菜,但是外卖平台(代理)会做一些附属操作proxy proxy=newproxy(chef);// 你不用面对厨师、直接找外卖平台即可!proxy.sell();}}加深理解
在一个增删改查的业务
- 接口类(公共调用的方法)
publicinterfaceUserService{publicvoidadd();publicvoiddelete();publicvoidupdate();publicvoidquery();}- 真实角色(业务实现类)
publicclassUserServiceImpl{publicvoidadd(){System.out.println("添加用户");}publicvoiddelete(){System.out.println("删除用户");}publicvoidupdate(){System.out.println("修改用户");}publicvoidquery(){System.out.println("查询用户");}}- 代理角色(代理真实角色的类&横向扩展附属操作)
publicclassUserServiceProxyimplementsUserService{publicUserServiceProxy(UserServiceImpluserServiceImpl){this.userServiceImpl=userServiceImpl;}publicvoidsetUserServiceImpl(UserServiceImpluserServiceImpl){this.userServiceImpl=userServiceImpl;}privateUserServiceImpluserServiceImpl;@Overridepublicvoidadd(){debug("add");userServiceImpl.add();}@Overridepublicvoiddelete(){debug("delete");userServiceImpl.delete();}@Overridepublicvoidupdate(){debug("update");userServiceImpl.update();}@Overridepublicvoidquery(){debug("query");userServiceImpl.query();}// 日志方法:横向扩展增增删改查业务publicvoiddebug(Stringmsg){System.out.println("debug:"+msg+"方法执行了");}}- 客户端访问代理角色(客户端想实现真实角色的类,只能通过访问代理角色)
publicclassClient{publicstaticvoidmain(String[]args){UserServiceImpluserServiceImpl=newUserServiceImpl();UserServiceProxyuserServiceProxy=newUserServiceProxy(userServiceImpl);userServiceProxy.add();userServiceProxy.delete();userServiceProxy.update();userServiceProxy.query();}}聊聊AOP:
动态代理
动态代理的底层都是反射
- 动态代理和静态代理角色一样
- 动态代理的代理类是动态生成的,不是我们直接写好的
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口的—JDK的动态代理【我们在这里使用】
- 基于类:cglib
- java字节码实现:javasist
需要了解的两个类:Proxy:代理,InvocationHandler:调用处理程序
Proxy
Proxy提供了创建动态代理类和实例的静态方法。
InvocationHandler
- 代理实例的_调用处理程序_实现的_接口_
代理类写法
- 继承InvocationHandler接口
publicclassProxyInvocationHandlerimplementsInvocationHandler- 引用真实角色的接口
privateSellsell;- 获取真实角色的共同继承的接口
publicObjectgetProxy(){// 获取被代理接口的所有方法returnProxy.newProxyInstance(this.getClass().getClassLoader(),sell.getClass().getInterfaces(),this);}- 处理代理实例,并且执行方法返回结果
// 处理代理实例,并返回结果publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{Objectresult=method.invoke(sell,args);// 执行一个方法,执行完毕之后会获取一个结果returnresult;}代码步骤
真实角色(厨师)
// 厨师:真实角色publicclassChefimplementsSell{@Overridepublicvoidsell(){System.out.println("cike_y真实厨师:这里是Demo04案例,快来我这里点吃的吧");}}外卖平台和厨师都要赚钱(共同接口)
publicinterfaceSell{publicvoidsell();}外卖平台(动态代理类)
//等我们会用这个类自动生成代理类!publicclassProxyInvocationHandlerimplementsInvocationHandler{// 被代理的接口,解耦性强privateSellsell;publicvoidsetSell(Sellsell){this.sell=sell;}// Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),// new Class<?>[] { Foo.class },// handler);// 获取真实角色和代理角色公共的接口publicObjectgetProxy(){// 获取被代理接口的所有方法returnProxy.newProxyInstance(this.getClass().getClassLoader(),sell.getClass().getInterfaces(),this);}// 处理代理实例,并返回结果publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{// 在执行目标对象的方法之前,可以进行一些自定义操作Start();Objectresult=method.invoke(sell,args);// 执行一个方法,执行完毕之后会获取一个结果// 在执行目标对象的方法之后,可以进行一些自定义操作SeeRider();SendOrder();GiveMoney();TakeCommission();TakeRiderFee();returnresult;}// 代理的附属操作publicvoidStart(){System.out.println("这里是外卖平台,开始代理:");}// 代理可以做一些附属的事情publicvoidSeeRider(){// 找骑手System.out.println("帮你寻找骑手中……");}// 收取佣金publicvoidTakeCommission(){System.out.println("外卖平台收取佣金");}// 骑手费用publicvoidTakeRiderFee(){System.out.println("给骑手小费");}// 发送客户订单publicvoidSendOrder(){System.out.println("发送客户订单");}// 给餐厅钱publicvoidGiveMoney(){System.out.println("给餐厅钱");}}用户(要吃饭的人:面对外卖平台)
publicclassClient{publicstaticvoidmain(String[]args){// 真实角色Chefchef=newChef();// 代理角色ProxyInvocationHandlerproxyInvocationHandler=newProxyInvocationHandler();// 要代理的对象:指的是真实角色,设置代理的真实角色对象proxyInvocationHandler.setTarget(chef);// 代理角色(已经代理了真实角色了)获取接口Sellproxy=(Sell)proxyInvocationHandler.getProxy();// 直接面对外卖平台,不用找厨师proxy.sell();}万能的写法
只需要改变动态代理的对象为Object对象就可以了,因为Java 中Object 类是所有类的父类,也就是说Java 的所有类都继承了Object,子类可以使用Object 的所有方法。
publicclassProxyInvocationHandlerimplementsInvocationHandler{// 要代理的接口privateObjecttarget;publicvoidsetTarget(Objecttarget){this.target=target;}// 官方写法:// Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),// new Class<?>[] { Foo.class },// handler);// 获取真实角色的公共接口publicObjectgetProxy(){returnProxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);}// 处理代理实例,并返回结果publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{Objectresult=method.invoke(target,args);// 执行方法,返回结果returnresult;}}其余的:真实角色(厨师)、接口(外卖平台和厨师的共同目标)、用户(吃饭的人)写法都不需要变。
动态代理的好处:
- 可以使真实角色的操作更加纯粹!,不用去关注一些公共的业务
- 公共业务就交给了代理角色!实现了业务的分工!
- 公共业务发生扩展的时候,方便集中管理!
- 一个动态代理类代理的是一个接口,一般就是对应的一类业务
- 一个动态代理类可以代理多个类,只要是实现了同一个接口即可
参考文档:
JDK-api-1.8_google