一、代理模式介绍
代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。
简言之,代理模式就是设置一个中间代理来控制访问原目标对象,以达到增强原对象的功能和简化访问方式。
一.静态代理
上图角色分析:
?抽象角色:一般会使用接口或者抽象类来解决
?真实角色:被代理的角色实现抽象方法
?代理角色:代理真实角色,代理真实角色,也实现抽象方法,一般会做一些附属操作。
代理模式的优点:
?可以使真实角色的操作更加纯粹!不用关注一些公共的业务。
?公共业务交给代理角色,实现了业务的分工
?公共业务扩展的时候,方便集中管理。
静态代理的缺点:
?一个真实角色就会产生一个代理角色,代码量翻倍,开发效率变低。
参考代码如下:
//1.抽象角色 public interface IRent { //租房接口的方法; public void rent(); } /*2.房东:中式英语;*/ public class HouseOwner implements IRent{ public void rent() { System.out.println("房东直租房屋,一室一厅一卫,一个月300$"); } } /*3.传说中中介,非链家莫属了*/ public class Proxy implements IRent{ //1.目标对象,代理房东的房子 HouseOwner target; //2.构造方法 public Proxy(HouseOwner target) { this.target = target; } //3.实现的代理方法 public void rent() { before(); target.rent(); after(); } //代理增强的附加功能; public void before(){ System.out.println("收取看房费100元"); } public void after(){ System.out.println("合适进行收费"); } } public class ClientTest { @Test public void test(){ //3.1房东直租 HouseOwner owner=new HouseOwner(); //3.2 中介代理对象的创建,来了 Proxy proxy=new Proxy(owner); //3.3 客户看房子; proxy.rent(); } }
效果:
作业扩充:
代理增加日志功能
1.?创建一个抽象接口,对用户业务进行抽象:实现一个日志输出功能,以记录业务代码的调用情况。
实现思路有两种,如下:
?思路1:在业务实现类每个方法中增加相应操作(该思路是传统方法,缺点很多)。
?思路2:使用代理,在不改变原有业务的情况下,实现此日志记录功能!
体现一个重要的思想:在不改变原有代码的情况下,实现对原有功能的增强。AOP的核心思想。
二.动态代理
动态代理和静态代理的角色是一样的,动态代理的代理类是动态生成的,不是像静态代理那样是直接写死的。动态代理可以分为两大类:一类是基于接口动态代理 , 一类是基于类的动态代理。
基于接口的动态代理,如JDK动态代理
基于类的动态代理,如cglib
JDK的动态代理需要了解两个类:
核心 : InvocationHandler (调用处理程序) 和 Proxy (代理)
//proxy - 调用该方法的代理实例 //method -所述方法对应于调用代理实例上的接口方法的实例。方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。 //args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。 Object invoke(Object proxy, 方法 method, Object[] args) . static Object newProxyInstance(ClassLoader loader, //指定当前目标对象使用类加载器 Class[] interfaces, //目标对象实现的接口的类型 InvocationHandler h //事件处理器 )
案例说明:
订单模块进行操作,增加日志功能。
JDK动态代理是代理工厂,不再需要实现多个接口了,注意这里面变化比较大。
package com.yh.jdk; //1.抽象接口 public interface OrderService { void addOrder(); void updateOrder(); void selectOders(); } package com.yh.jdk; /*2.目标对象*/ public class OrderDaoImpl implements OrderService{ public void addOrder() { System.out.println("增加订单业务"); } public void updateOrder() { System.out.println("更新订单业务"); } public void selectOders() { System.out.println("查询日志信息"); } } package com.yh.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /*3.定义一个动态代理的,工厂,又来了。呵呵,好处大大滴 * static Object newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h) 返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。 * loader - 类加载器来定义代理类 interfaces - 代理类实现的接口列表 InvocationHandler h - 调度方法调用的调用处理函数 * */ public class JDKProxyFactory { //3.1要代理的目标对象; Object target; //3.2构造方法; public JDKProxyFactory(Object target) { this.target = target; } //3.3 注意这里是重要的,合并实现的方法. public Object getInstance(){ return Proxy.newProxyInstance( target.getClass().getClassLoader(),//获取目标对象的类加载器; target.getClass().getInterfaces(),//获取目标对象的接口 new InvocationHandler() { //事件处理器,拦截方法,处理. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //注意看这里有个参数是method,还有印象吗? System.out.println("******开始记录日志 **********"); Object invoke = method.invoke(target, args); if(method.getName().equals("selectOders")) System.out.println("******结束记录日志 **********"); return invoke; } } ); } } ```package com.yh.jdk; import org.junit.Test; public class TestJdkClient { @Test public void test03(){ OrderService target=new OrderDaoImpl(); System.out.println(target.getClass()); //注意动态代理的灵活性;获取实例方法. OrderService jdkProxyFactory = (OrderService) new JDKProxyFactory(target).getInstance(); //代理类执行; jdkProxyFactory.addOrder(); } }