代理设计模式:
定义:对其他对象提供一种代理以控制对这个对象的访问。
特征:代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等
按照代理的创建时期,代理类可以分为两种:
1. 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
2. 动态代理:在程序运行时,运用反射机制动态创建而成。
其中动态代理也可分为两种:
1.jdk动态代理
2.cglib动态代理
先讲一下静态代理:
比如有一个接口Actor
public interface Actor {
//表演
void act();
//跳舞
void dance();
}
艺人王宝强实现了这个接口
public class WangBaoQiang implements Actor {
@Override
public void act() {
System.out.println("宝强表演");
}
@Override
public void dance() {
System.out.println("宝强跳舞");
}
}
创建一个静态代理对象负责照顾王宝强的行程安排staticProxy
public class StaticProxy implements Actor {
private Actor actor = new WangBaoQiang();
@Override
public void act() {
System.out.println("确认钱到位了,让宝强表演");
//调用原有功能的原有方法
actor.act();
}
@Override
public void dance() {
System.out.println("确认钱到位了,让宝强跳舞");
actor.dance();
}
public static void main(String[] args) {
StaticProxy staticProxy = new StaticProxy();
staticProxy.act();
staticProxy.dance();
}
}
以上就是静态代理,静态代理对象需要自己创建,
jdk动态代理
public class JdkProxy {
public static void main(String[] args) {
//1.创建被代理对象
Actor actor = new WangBaoQiang();
//2.创建王宝强的代理对象proxyActor--经纪人
/**
* loader – the class loader to define the proxy class 加载此对象(Actor.class)所表示的类或接口的类加载器。
* interfaces – the list of interfaces for the proxy class to implement 代理类实现的接口列表
* h – the invocation handler to dispatch method invocations to
*/
//定义代理类加载器
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
//getClass:返回此对象运行的类(.class),getInterfaces:返回此类实现的接口列表(.class)
Class<?>[] interfaces = actor.getClass().getInterfaces();
Actor proxyActor = (Actor) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
/**
* @param proxy 方法所调用的代理实例
* @param method 对应于在代理实例上调用的接口方法的方法实例。
* @args 一个对象数组,包含在代理实例的方法调用中传递的参数的值,如果接口方法不接受参数,则为null。原始类型的参数被包装在适当的原始包装类的实例中
* @return 方法执行的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("经纪人确认钱到位了");
//保证原有方法的功能,即调用原有对象的原有方法
Object obj = method.invoke(actor, args);
System.out.println("表演结束,经纪人帮助王宝强安排住宿");
return obj;
}
});
//3.调用代理对象执行方法(保证具体的业务功能由被代理对象自己完成,而事务功能由代理对象来完成.)
proxyActor.act();
System.out.println("=================");
proxyActor.dance();
}
}
debug执行结果:
Connected to the target VM, address: '127.0.0.1:14151', transport: 'socket'
经纪人确认钱到位了
宝强表演
表演结束,经纪人帮助王宝强安排住宿
=================
经纪人确认钱到位了
宝强跳舞
表演结束,经纪人帮助王宝强安排住宿
Disconnected from the target VM, address: '127.0.0.1:14151', transport: 'socket'
Process finished with exit code 0
查看jvm虚拟机生成的动态代理类源码:
在图片所指向的位置输入:-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true,运行代码即可生成代理类源码
代理类源码
public final class $Proxy0 extends Proxy implements Actor {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void dance() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void act() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.itheima.poxy.jdk.Actor").getMethod("dance");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.itheima.poxy.jdk.Actor").getMethod("act");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
由代码可知,该代理类继承了Proxy动态代理类并实现了Actor接口
Proxy类:
动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。 代理接口 是代理类实现的一个接口。 代理实例 是代理类的一个实例。
Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
可查看API中 java.lang.reflect.Proxy
第一步
静态代码块首先获取方法对象并赋值给私有静态成员变量.
第二步
通过InvocationHandler h调用invoke方法,并传递三个参数,代理对象,方法对象(m1,m4,m2…),方法参数.
protected InvocationHandler h;
private Proxy() {
}
而查看InvocationHandler发觉它就一个方法
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
而这个InvocationHandler对象是我们在创建代理类对象创建的匿名内部类对象.
所以,Proxy.newProxyInstance传递三个参数(类加载器,方法对象,h对象)创建代理对象,当我们通过代理对象调用方法时,本质就是调用super.h.invoke(this, m1, new Object[]{var1}),而这个h变量就是我们传递进去的匿名内部类对象赋值的,所以有趣的是,当我们用代理对象调用方法,比如jdkProxy.dance(),会去调用invoke方法,而invoke方法的第一个参数是代理对象本身,如果我们再invoke方法内部继续调用dance(),就会发生递归现象
由于jdk的动态代理方式创建代理对象必须使用接口,在企业开发中有时没有接口,需要对某个实现类进行代理,那么此时我们就不能再使用jdk动态代理而选择cglib动态代理.
cglib动态代理:通过对现有类的继承,这个继承类是动态创建的
需要被代理的类
public class WangBaoQiang {
public void act() {
System.out.println("表演");
}
}
使用cglib动态生成代理对象.(使用前记得导入cglib依赖)
public class Cglib {
public static void main(String[] args) {
WangBaoQiang wangBaoQiang = new WangBaoQiang();
/**
* 参数1:被代理对象的实现类
* 参数2:处理器,和jdk的动态代理中的invocationHandler的作用一样
*/
WangBaoQiang o = (WangBaoQiang) Enhancer.create(WangBaoQiang.class, new MethodInterceptor() {
//作用和jdk动态代理中invoke的作用一样
/**
*
* @param o 代理对象本身 没卵用
* @param method 代理对象将要代理的方法
* @param objects 方法中的参数
* @param methodProxy 代理后的方法 没卵用
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//方法增强
System.out.println("经纪人确认钱到账,安排宝强表演");
//保证原有方法的功能,即调用原有对象的原有方法
Object obj = method.invoke(wangBaoQiang, objects);
return obj;
}
});
//代理对象调用方法
o.act();
}
}
执行结果:
E:\develop\Java\jdk-8\bin\java.exe "-javaagent:E:\develop\JetBrains\IntelliJ IDEA 2019.1.4\lib\idea_rt.jar=14095:E:\develop\JetBrains\IntelliJ IDEA 2019.1.4\bin" -Dfile.encoding=UTF-8 -classpa
经纪人确认钱到账,安排宝强表演
表演
Process finished with exit code 0