首先我们要明白代理的含义,假如有一天张三想要买衣服,他是不是有两种方式,第一:自己去生产衣服的地方买,第二:请一个代购,他只需要提要求,然后代购帮助他买,假设我自己就是一个代购,我知道一个工厂生产男装。
在代理中有三个重要的角色:被代理类,代理类,接口
在上面的例子中分别对应的就是,被代理类:生产男装的工厂,代理类:我自己,接口:提供服务
(如果这里都会了,请移步到下面动态代理原理分析)
静态代理
先说一下静态代理,静态代理是指在代码编写阶段就已经确定好了的,被代理类、代理类、接口这三个之间的关系
定义接口,里面包含一个提供服务的接口
-
public
interface Serve {
//一个提供服务的接口,工厂和代购都必须实现这个接口,提供服务
-
void service(float price);
//提供服务
-
}
定义一个被代理类,生产男装的工厂,他只负责生产让客户满意衣服
-
public
class RealityFactory implements Serve {
-
@Override
-
public void service(float price) {
-
System.out.println(
"根据您的要求,本工厂为您定制衣服,价格是:" + price);
-
}
-
}
定义一个代理类,相当于我自己,是一个代购,我会帮张三找到工厂,并告诉工厂张三的要求,把工厂生产出来的衣服邮寄到张三的家里
-
public
class Purchasing implements Serve {
-
Serve realityFactory;
-
public PurchasingAgency(Serve realityFactory) {
-
this.realityFactory= realityFactory;
//注入一个被代理类
-
}
-
@Override
-
public void service(float price) {
-
System.out.println(
"根据市场调研寻找到合适的工厂");
//前置增强
-
realityFactory.service(price);
//工厂只负责制作衣服
-
System.out.println(
"工厂制作完毕,我负责帮您邮寄到家");
//后置增强
-
}
-
}
测试一下
-
public
class Test{
-
public static void main(String[] args) {
-
Serve realityFactory =
new RealityFactory();
//定义被代理类工厂
-
Serve purchasing =
new Purchasing(realityFactory);
//定义代理类我自己,并将被代理类注入
-
purchasing.service(
20.0f);
//执行代理类的service方法,增强了被代理类作用
-
}
-
}
-
根据市场调研寻找到合适的工厂
-
根据您的要求,本工厂为您定制衣服,价格是:
20.0
-
工厂制作完毕,我负责帮您邮寄到家
通过静态代理我们可以看到,第一:被代理类实际上只有一个作用就是生产男装,但通过代理类代理之后,方法得到了增强,拥有了三个作用,寻找工厂,制作衣服,寄送衣服。第二:静态代理存在缺点,一个代理类只能为同一个接口的类提供增强,假如有不同的接口,你就需要定义很多的代理类,假如,有一天张三的老婆需要买衣服也找到了我,这样子,这个生产男装的工厂就没办法提供服务了,就需要新的工厂来提供服务。
动态代理
动态代理应运而生,它就可以帮我们解决接口不匹配的问题,可以为多个类提供增强
动态代理的底层原理就是通过反射动态构建了一个代理类,这样子就可以为每一个接口的
在例子中,动态代理类就相当于我自己开了一个代购公司,每次有客户来找我买衣服的时候,我就在公司里面找一个人来服务这个客户
在动态代理类中,接口和被代理类是和静态代理类一样的
定义接口,里面包含一个提供服务的接口,其子类生产男装
-
public
interface Serve {
//一个提供服务的接口,工厂必须实现这个接口,提供服务
-
void service(float price);
//提供服务
-
}
定义一个被代理类,生产男装的工厂,他只负责生产让客户满意衣服
-
public
class RealityFactory implements Serve {
-
@Override
-
public void service(float price) {
-
System.out.println(
"根据您的要求,本工厂为您定制男装,价格是:" + price);
-
}
-
}
主要就是下面不一样了,下面我们定义一个动态代理类,这里主要使用到两个主要的类:InvocationHandler和Proxy
InvocationHandler类提供真实的服务,最后实际执行的方法在InvocationHandler中,就相当于是一个我们的客户,为他们提供优质的服务
Proxy类用来动态的生成代理类,就相当于是代购公司中的职员,他们有丰富的资源,可以帮客户找到心仪的产品
定义一个动态代理类,必须实现InvocationHandler方法
-
public
class Mediation implements InvocationHandler{
//必须实现InvocationHandler接口
-
-
Object object;
//接收一个通用类
-
public Mediation(Object object) {
//将通用类注入
-
this.object = object;
-
}
-
@Override
-
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强方法
-
System.out.println(
"根据市场调研寻找到合适的工厂");
-
method.invoke(object, args);
//通过反射调用实际的方法,method为对应的方法,args为方法的参数,如果没有则为null
-
System.out.println(
"工厂制作完毕,我负责帮您邮寄到家");
-
return
null;
-
}
-
-
public Object getProxyInstance() {
//通过反射得到一个代理类的实例
-
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),
this);
-
}
-
}
测试一下
-
public
class Test{
-
public static void main(String[] args) {
-
Serve realityFactory =
new RealityFactory();
//实例化一个生产男装的工厂
-
Mediation mediation =
new Mediation(realityFactory);
//将这个工厂注入动态代理类
-
Serve serviceMediation = (Serve) mediation.getProxyInstance();
//通过Proxy类得到一个代理类的实例
-
serviceMediation.service(
20.0f);
//调用代理类的service方法,会将该方法映射到Mediation的invoke方法
-
}
-
}
结果
-
根据市场调研寻找到合适的工厂
-
根据您的要求,本工厂为您定制男装,价格是:
20.0
-
工厂制作完毕,我负责帮您邮寄到家
假如我们想要为另外一个接口代理呢?
定义另外一个接口,该接口是一个服务接口,其子类生产女装
-
public
interface ServeWomen {
//一个提供服务的接口,工厂必须实现这个接口,提供服务
-
void service(float price);
//提供服务
-
}
定义一个被代理类,假设这个类是一个工厂,主要生产女装
-
public
class WomenRealityFactory implements ServeWomen {
-
@Override
-
public void service(float price) {
-
System.out.println(
"根据您的要求,本工厂为您定制女装,价格是:" + price);
-
}
-
}
使用了动态代理,就不用再定义动态代理类,直接使用以前的动态代理类,写测试代码
-
public
class Test{
-
public static void main(String[] args) {
-
ServeWomen womenRealityFactory =
new WomenRealityFactory();
//实例化一个生产女装的工厂
-
Mediation mediation =
new Mediation(womenRealityFactory);
//将这个工厂注入动态代理类
-
ServeWomen serviceWomenMediation = (ServeWomen) mediation.getProxyInstance();
//通过Proxy类得到一个代理类的实例
-
serviceWomenMediation.service(
20.0f);
//调用代理类的service方法,会将该方法映射到Mediation的invoke方法
-
}
-
}
结果
-
根据市场调研寻找到合适的工厂
-
根据您的要求,本工厂为您定制女装,价格是:
20.0
-
工厂制作完毕,我负责帮您邮寄到家
使用动态代理的好处一下就体现出来了,只要编写了一次动态代理类,并且被代理类实现了一个接口,就可以为被代理类生成一个代理类的实例,这个就是JDK动态代理的实现方式。
JDK动态代理原理
在谈这个之前我们先来看看,一个类的生命周期
java源文件(.java文件):编译之后,就变成java字节码文件
java字节码(.class文件):类加载之后,变成一个Class对象
Class对象:实例化之后,变成一个实例对象
实例对象
卸载
到现在很多人很好奇,为什么通过Proxy类的静态方法newProxyInstance就可以得到一个ServeWomen的一个实例?通过Proxy类得到ServeWomen的实例到底是哪里来的?这个实例对象到底是哪个类实例化来的?
带着这些问题,我们开启Debug模式查看一下Proxy类生成的实例到底是哪个类,不看不知道,一看吓一跳,$Proxy0这个类是哪里来的?我们没有编写这个类啊,现在好了问题越来越复杂,我们只能去看一下Proxy类的静态方法newProxyInstance里面到底干了什么
我们点开newProxyInstance方法,我们传给了newProxyInstance方法三个参数:
ClassLoader loader,被代理类的类加载器
Class<?>[] interfaces,被代理类实现的接口的Class对象,可能有多个所以是数组
InvocationHandler h,动态代理类的实例
根据JDK代码里面的注释会发现,箭头指向的那一行代码就是核心的,生成代理类的代码,它把我们传递的类加载器和接口的Class对象往下面传递了,我们试着点进去
里面进行了接口数量的验证,重点代码就在get方法里面,我们试着点进去
首先在ConcurrentMap中查找是否之前已经创建过了,如果没有则自己去创建,我们点进去查看apply方法,这个方法是在接口里面定义的方法,按照下面的步骤查看实现类的定义
进到这个方法里面我们就看到了一个熟悉东西$Proxy,这个就是类的前缀,apply方法的前面进行了大量的验证重点代码在后面,我们滑到下面
根据代码的注释,我们很轻易的找到了生成Class对象的代码,底层就是这样子为你提供了一个实例对象,它直接跳过了java源文件,直接生成了.class文件,然后.class文件加载进入JVM,生成一个Class对象,然后通过Class对象生成一个实例对象
现在已经很清晰,既然可以找到生成.class文件的代码,那我们可不可以将.class文件保存到本地,然后通过反编译看一下这个类的源代码是怎么样的呢?当然可以
编写代码将.class文件保存到本地
-
public
class Bytecode {
-
public static void main(String[] args) {
-
String fileName =
"$ppp";
//class文件的名字
-
//这一句代码是在源码中找到的生成class文件的代码,第二个参数需要一个Class对象数组类型
-
byte[] classFile = ProxyGenerator.generateProxyClass(
-
fileName,
new Class[] {ServeWomen.class}, Modifier.FINAL);
-
-
FileOutputStream out =
null;
-
String filePath =
"G:\\"+fileName+
".class";
-
try {
-
out =
new FileOutputStream(filePath);
-
out.write(classFile);
//写入文件
-
out.flush();
-
}
catch (FileNotFoundException e) {
-
// TODO Auto-generated catch block
-
e.printStackTrace();
-
}
catch (IOException e) {
-
// TODO Auto-generated catch block
-
e.printStackTrace();
-
}
finally {
-
try {
-
if(out !=
null) {
-
out.close();
-
}
-
}
catch (IOException e) {
-
// TODO Auto-generated catch block
-
e.printStackTrace();
-
}
-
}
-
-
}
-
}
查看本地,果然保存下来了.class文件
使用反编译工具查看源码,源码如下
-
import com.sxt.server.dynamic.ServeWomen;
-
import java.lang.reflect.InvocationHandler;
-
import java.lang.reflect.Method;
-
import java.lang.reflect.Proxy;
-
import java.lang.reflect.UndeclaredThrowableException;
-
-
final
class $ppp extends Proxy implements ServeWomen {
-
private
static Method m1;
-
-
private
static Method m2;
-
-
private
static Method m3;
-
-
private
static Method m0;
-
-
public $ppp(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler); }
-
-
public final boolean equals(Object paramObject) {
-
try {
-
return ((Boolean)
this.h.invoke(
this, m1,
new Object[] { paramObject })).booleanValue();
-
}
catch (Error|RuntimeException error) {
-
throw
null;
-
}
catch (Throwable throwable) {
-
throw
new UndeclaredThrowableException(throwable);
-
}
-
}
-
-
public final String toString() {
-
try {
-
return (String)
this.h.invoke(
this, m2,
null);
-
}
catch (Error|RuntimeException error) {
-
throw
null;
-
}
catch (Throwable throwable) {
-
throw
new UndeclaredThrowableException(throwable);
-
}
-
}
-
-
public final void service(float paramFloat) {
-
try {
-
this.h.invoke(
this, m3,
new Object[] { Float.valueOf(paramFloat) });
-
return;
-
}
catch (Error|RuntimeException error) {
-
throw
null;
-
}
catch (Throwable throwable) {
-
throw
new UndeclaredThrowableException(throwable);
-
}
-
}
-
-
public final int hashCode() {
-
try {
-
return ((Integer)
this.h.invoke(
this, m0,
null)).intValue();
-
}
catch (Error|RuntimeException error) {
-
throw
null;
-
}
catch (Throwable throwable) {
-
throw
new UndeclaredThrowableException(throwable);
-
}
-
}
-
-
static {
-
try {
-
m1 = Class.forName(
"java.lang.Object").getMethod(
"equals",
new Class[] { Class.forName(
"java.lang.Object") });
-
m2 = Class.forName(
"java.lang.Object").getMethod(
"toString",
new Class[
0]);
-
m3 = Class.forName(
"com.sxt.server.dynamic.ServeWomen").getMethod(
"service",
new Class[] {
float.class });
-
m0 = Class.forName(
"java.lang.Object").getMethod(
"hashCode",
new Class[
0]);
-
return;
-
}
catch (NoSuchMethodException noSuchMethodException) {
-
throw
new NoSuchMethodError(noSuchMethodException.getMessage());
-
}
catch (ClassNotFoundException classNotFoundException) {
-
throw
new NoClassDefFoundError(classNotFoundException.getMessage());
-
}
-
}
-
}
我们发现这个类实现了我们自定义的接口ServeWomen,查看service方法,发现里面是h.invoke(),这个是不是很眼熟,是的,这个h,就是继承了Proxy类得到的,就是我们前面通过this传递下去的动态代理类的实例
所以当我们调用service方法时,实际上它调用的是,动态代理类中的invoke方法
你学会了没有/偷笑
转载:https://blog.csdn.net/OnlyloveCuracao/article/details/104889478