代理模式
代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问。
1.提高扩展性和复用性
2.保护目标对象
结构图:
Subject:RealSubject和Proxy的公共接口
RealSubject:Proxy代理的真实实体
Proxy:代理,与RealSubject实现同一接口,代理就可以代替真实实体。
Java中的代理技术:JDK、CGLIB、Javaassist、ASM
Spring中常用JDK、CGLIB
Mybatis中使用Javaassist
场景:假如软件的研发过程中,程序员不能直接与客户对接,必须由产品经理与客户进行对接,从而研发部门根据客户的需求进行相应研发工作。这里产品经理和程序员都是研发部门的员工,具有相同的职责(产品研发)。产品经理就代理了程序员的具体工作,可以采用代理模式。
例:
1. 静态代理方式:
public interface Staff { // Subject void createWebAPP(); // 开发Web应用 void createAndroidApp(); // 开发Android应用 }
public class Programmer implements Staff { // RealSubject @Override public void createWebAPP() { System.out.println("Web应用开发"); } @Override public void createAndroidApp() { System.out.println("Android应用开发"); } }
public class Manager implements Staff { // Proxy Programmer programmer; @Override public void createWebAPP() { if (programmer == null) { programmer = new Programmer(); }
} @Override public void createAndroidApp() { if (programmer == null) { programmer = new Programmer(); } } }
public class Test { public static void main(String[] args) { Manager manager = new Manager(); manager.createAndroidApp(); // 代理执行被代理的方法 manager.createWebAPP(); } }
输出:
Web应用开发
Android应用开发
2. 动态代理方式:
(1)JDK动态代理
底层使用反射,只能创建接口的代理。
public interface Staff { // Subject void createWebAPP(); // 开发Web应用 void createAndroidApp(); // 开发Android应用 }
public class Programmer implements Staff { // RealSubject @Override public void createWebAPP() { System.out.println("Web应用开发"); } @Override public void createAndroidApp() { System.out.println("Android应用开发"); } }
public class DynamicProxyHandler implements InvocationHandler { // Proxy,代理类必须实现InvocationHandler接口 Object target; // 被代理的对象,可以是任何对象(Object是任何类的父类) /** * 1. 建立代理对象与被代理对象之间的关系 * @param target 被代理对象 * @return 被代理对象 */ public Object bind(Object target) { this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); // 三个参数:target的类加载器;把生成的动态代理的对象挂在哪些接口下,这里是挂在target实现的接口下;实现方法逻辑的代理类 } /** * 2. 实现代理逻辑的方法,调用被代理对象的任何方法,此方法都会执行
* @param proxy 代理对象(bind方法生成的) * @param method 当前调度的方法 * @param args 当前方法参数 * @return 代理结果返回 * @throws Throwable 异常 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(target, args); return result; } }
public class Test { public static void main(String[] args) { DynamicProxyHandler proxyHandler = new DynamicProxyHandler(); // 绑定具体的代理对象,返回给其接口的引用 Staff proxy = (Staff) proxyHandler.bind(new Programmer()); proxy.createWebAPP(); // 代理执行被代理的方法
proxy.createAndroidApp();
}
}
输出:
Web应用开发
Android应用开发
(2)CGLIB动态代理
不需要提供接口,只要一个非抽象类(被代理对象)。底层提供使用字节码处理框架ASM,创建类和接口的代理。
依赖:
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
public class Programmer { // RealSubject public void createWebAPP() { System.out.println("Web应用开发"); } public void createAndroidApp() { System.out.println("Android应用开发");
} }
public class CglibProxy implements MethodInterceptor { // 必须实现MethodInterceptor /** * 生成CGLIB代理对象 * @param cls Class 类 * @return Class 类的CGLIB代理对象 */ public Object getProxy(Class cls) { // CGLIB 增强对象 Enhancer enhancer = new Enhancer(); // 设置增强类型 enhancer.setSuperclass(cls); // 定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor方法 enhancer.setCallback(this); // 生成并返回对象 return enhancer.create(); } /** * 代理逻辑方法 * @param o 代理对象 * @param method 方法 * @param objects 方法参数 * @param methodProxy 方法代理 * @return 代理逻辑返回 * @throws Throwable 异常 */ public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { // CGLIB 反射调用的真实对象方法 Object result = methodProxy.invokeSuper(o,objects); return result; } }
public class Test { public static void main(String[] args) { CglibProxy cp = new CglibProxy(); Programmer pg = (Programmer)cp.getProxy(Programmer.class); pg.createWebAPP(); pg.createAndroidApp(); }
}