一、代理模式(Proxy Pattern)
代理模式也称为委托模式,是一种结构性设计模式。
在代理模式中,一个类代表另一个类的功能。我们创建具有现有对象的对象,以便向外界提供功能接口。
优点
可以隐藏委托类的实现;
可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理。
二、静态代理
静态代理设计模式
* 1、真实角色
* 2、代理角色: 要持有真实角色的引用
* 3、二者要实现相同的接口
装饰者模式就是静态代理的一种体现。
三、动态代理
字节码随用随创建,随用随加载。
动态代理常用的有两种方式
- 基于接口
提供者:JDK 官方的 Proxy 类。
要求:被代理类最少实现一个接口。
- 基于子类
提供者:第三方的 CGLib,如果报 asmxxxx 异常,需要导入 asm.jar。
要求:被代理类不能用 final 修饰的类(最终类)。
基于接口的动态代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package proxy.dynamic; /** * @author gavino * 模拟厂家,厂家直销 */ public class Manufacturers implements Market { @Override public void sal(Double price) { System.out.println("收款 "+price); } @Override public void afterSal() { System.out.println("免费售后2333"); } }
/** * @author gavino * 该接口提供销售规则 */ interface Market{ /** * 出售 */ public void sal(Double price); /** * 售后 */ public void afterSal(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| package proxy.dynamic;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;
/** * @author gavino * 模拟消费者 */ public class Customer { public static void main(String[] args) { //代理类中的真实对象(Manufacturers 制造商、厂商) final Manufacturers manufacturers = new Manufacturers(); Market agency = (Market) Proxy.newProxyInstance(manufacturers.getClass().getClassLoader(),manufacturers.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //获取当前方法方法 String name = method.getName(); //获取方法执行的参数 Double money = (Double) args[0]; Object realValue = null; if ("sal".equals(name)) { realValue = method.invoke(manufacturers, money*0.8); } return realValue; } }); manufacturers.sal(13300.0); agency.sal(13300.0); } }
=================================== 程序执行结果 =============================================== 收款 13300.0 收款 10640.0
|
相关方法和参数的详解
Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但是我们最常用的是newProxyInstance方法
Proxy.newProxyInstance(loader, interfaces, h);
这个方法的作用就是创建一个代理类对象,它接收三个参数:
1、loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载
2、interfaces:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,
如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。
3、h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用
- 通过Proxy类的newProxyInstance方法创建代理对象,我们来看下方法中的参数
- 第一个参数:manufacturers.getClass().getClassLoader(),使用handler对象的classloader对象来加载我们的代理对象
- 第二个参数:manufacturers.getClass().getInterfaces(),这里为代理类提供的接口是真实对象实现的接口,
这样代理对象就能像真实对象一样调用接口中的所有方法
- 第三个参数:h(匿名内部类),我们将代理对象关联到上面的InvocationHandler对象上
1 2 3 4 5 6 7 8 9
| /** * newProxyInstance方法的参数含义: * ClassLoader:和被代理对象使用相同的类加载器。 * 它是用于加载代理对象字节码的。 * Interfaces:Class[]:字节码数组,和被代理对象具有相同的行为。实现相同的接口。 * InvocationHandler:如何代理。用于提供增强的代码. * 常情况下都是匿名内部类,此接口的实现类都是谁用谁写. */ Proxy.newProxyInstance(loader, interfaces, h);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| new InvocationHandler() { /** * 执行被代理对象的任何方法,都会经过该方法。 * 此方法有拦截的功能。 * * 参数: * proxy:代理对象的引用。不一定每次都用得到 * method:当前执行的方法 * args:当前执行方法所需的参数 * 返回值: * 当前执行方法的返回值 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 方法增强 return null; } }
-----------------------------------------------------------------------------------------
method.invoke(obj, args);
|
基于接口的动态代理实现的总结
基于子类的动态代理
基于子类的动态代理
- 要求:
被代理对象不能是最终类
- 用到的类:
Enhancer
- 用到的方法:
create(Class, Callback)
- 方法的参数:
- Class:被代理对象的字节码
- Callback:如何代理
导入cglib的jar包和asm的jar包(maven 工程导入 cglib 依赖即可)
去掉接口实现
1 2 3 4 5 6 7 8 9 10 11 12 13
| package proxy.dynamic.cglib; /** * @author gavino * 模拟厂家,厂家直销 */ public class Manufacturers { public void sal(Double price) { System.out.println("收款 "+price); } public void afterSal() { System.out.println("免费售后2333"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| package proxy.dynamic.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;
/** * @author gavino * 模拟消费者 */ public class Customer { public static void main(String[] args) { final Manufacturers manufacturers = new Manufacturers(); Manufacturers cglibManufacturers = (Manufacturers)Enhancer.create(manufacturers.getClass(), new MethodInterceptor() { @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //提供增强的代码 Object realValue = null; //获取方法执行的参数 Double money = (Double)args[0]; if("sal".equals(method.getName())) { realValue = method.invoke(manufacturers, money*0.8); } return realValue; } }); manufacturers.sal(12000.0); cglibManufacturers.sal(12000.0); } } ======================================= 程序执行输出 ================================================ 收款 12000.0 收款 9600.0
|
相关方法和参数的详解
1 2
| Enhancer.create(type, callback);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Enhancer.create(type, new MethodInterceptor() { /** * 执行被代理对象的任何方法,都会经过该方法。在此方法内部就可以对被代理对象的任何方法进行增强。 * * 参数: * 前三个和基于接口的动态代理是一样的。 * MethodProxy:当前执行方法的代理对象。 * 返回值: * 当前执行方法的返回值 */ @Override public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { // 方法的增强 return null; } });
|