1.代理模式是什么:

代理模式是Java常见的设计模式之一。所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接地调用实际的对象。

2.为什么要使用代理模式:

一般是因为客户端不想直接访问实际的对象,或者访问实际的对象存在困难,因此通过一个代理对象来完成间接的访问。

3.代理模式种类:

代理模式主要分为两类,静态代理和动态代理。静态代理比较简单,是由程序员编写的代理类,并在程序运行前就编译好的,而不是由程序动态产生代理类,这就是所谓的静态。


一、静态代理又分为聚合式静态代理和继承式静态代理

举个管理员网站记录操作日志的例子:

1.1、聚合式静态代理:

1.1.1、创建一个管理员接口

/** * 场景:管理员网站记录操作日志 * 方式一:聚合式静态代理 * 创建一个管理员接口 */ public interface Manager { void recordLog(); }

1.1.2、创建一个管理员类实现管理员接口

/** * 真实管理员类 */ public class Admin implements Manager { @Override public void recordLog() { System.out.println("处理记录日志开始结束之间的业务逻辑。。。"); } }

1.1.3、创建一个聚合方式的代理类

/** * 以聚合方式实现的静态代理 */ public class PolyAdmin implements Manager { private Admin admin; public PolyAdmin(Admin admin) { this.admin = admin; } @Override public void recordLog() { System.out.println("Admin 聚合式记录日志开始。。"); admin.recordLog(); System.out.println("Admin 聚合式记录日志结束。。"); } }

1.1.4、测试代码:

/** * 测试聚合式静态代理 */ public class TestPolyAdmin { public static void main(String[] args) { Manager proxyManager = new PolyAdmin(new Admin()); proxyManager.recordLog(); } } 输出结果: Admin 聚合式记录日志开始。。 处理记录日志开始结束之间的业务逻辑。。。 Admin 聚合式记录日志结束。。


1.2、继承式静态代理

1.2.1、创建一个继承式静态代理类:

/** * 继承式静态代理 */ public class ProxyAdmin extends Admin{ @Override public void recordLog() { System.out.println("Admin 继承式记录日志开始。。"); super.recordLog(); System.out.println("Admin 继承式记录日志开始。。"); } }

1.2.2、测试代码:

/** * 测试继承式静态代理 */ public class TestProxyAdmin { public static void main(String[] args) { ProxyAdmin proxyAdmin = new ProxyAdmin(); proxyAdmin.recordLog(); } }


静态代理模式总结:

优缺点:通过上面的代理代码,我们可以看出代理模式的特点,代理类接受一个Manager接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。但是也有缺点,每一个代理类都必须实现一遍委托类(也就是Admin)的接口,如果接口增加方法,则代理类也必须跟着修改。其次,代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。


二、动态代理:动态代理又分为jdk动态代理和cglib动态代理

2.1、jdk动态代理步骤:

  1. 创建一个实现InvocationHandler接口的类,它必须实现invoke()方法
  2. 创建被代理的类及接口
  3. 调用Proxy的静态方法,创建一个代理类
  4. 通过代理调用方法

import com.test.Manager; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DynamicProxy implements InvocationHandler { private Object target; public DynamicProxy(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Admin 动态代理打印日志开始。。。"); method.invoke(target,args); System.out.println("Admin 动态代理打印日志结束。。。"); return null; } }

2.1.1、测试代码:

import com.test.Admin; import com.test.Manager; import java.lang.reflect.Proxy; public class TestDynamicProxy { public static void main(String[] args) { //需要代理的真实对象 Manager manager = new Admin(); //创建中介类 DynamicProxy dynamicProxy = new DynamicProxy(manager); //获取类加载器 Class clazz=manager.getClass(); /** *loader 类加载器 *interfaces 实现接口 *h InvocationHandler */ Manager proxy = (Manager) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),dynamicProxy); proxy.recordLog(); } }

2.1.2、jdk动态代理总结:

JDK动态代理有一个强制性要求,就是被代理的类必须实现了某一个接口,或者本身就是接口。

在测试代码中,Proxy.newProxyInstance()方法需要3个参数:类加载器(要进行代理的类)、被代理类实现的接口,事务处理器。所以先实例化Admin,实例化InvocationHandler的子类DynamicProxy,将各参数传入Proxy的静态方法newProxyInstance()即可获得manager的代理类,前面的静态代理,代理类是我们编写好的,而动态代理则不需要我们去编写代理类,是在程序中动态生成的。


2.2、cglib动态代理

举个例子:

2.2.1、创建一个老师即将要来了的类:

public class Teacher { public void move() { System.out.println("Teacher is coming 。。。。。"); } }

2.2.2、创建cglib代理的实现类:

import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * 基于spring的cglib的继承式 动态代理, */ public class CglibDynamicProxy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); public Object getProxy(Class<?> clazz) { enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } /** * 拦截所有目标类方法的调用 * 参数: * obj目标实例对象 * method 目标方法的反射对象 * args方法的参数 * proxy代理类的实例 */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("cglib 动态代理之老师还没来。。。。"); methodProxy.invokeSuper(o,objects); System.out.println("cglib 动态代理之老师已经来了。。。。"); return null; } }

2.2.3、创建测试类:

public class TestCglibDynamicProxy { public static void main(String[] args) { CglibDynamicProxy cglibDynamicProxy = new CglibDynamicProxy(); Teacher train = (Teacher) cglibDynamicProxy.getProxy(Teacher.class); train.move(); } }


总结:

代理模式最佳方案(代理模式有哪些)(1)

三种代理方式对比

,