什么是代理
想要弄清楚动态代理,首先得明白代理是什么。下面直接看静态代理的小Demo,解释代理的含义。
1.定义一个Star("明星")接口
package com.study.staticProxy;
public interface Star {
void conversation();
void signContract();
void bookTicket();
void sing();
void collectMoney();
}
2.定义一个类JayZ("周杰伦")实现 Star 接口
package com.study.staticProxy;
public class JayZ implements Star {
@Override
public void conversation() {
System.out.println("JayZ.conversation()");
}
@Override
public void signContract() {
System.out.println("JayZ.signContract()");
}
@Override
public void bookTicket() {
System.out.println("JayZ.bookTicket()");
}
@Override
public void sing() {
System.out.println("***周杰伦在唱歌****");
}
@Override
public void collectMoney() {
System.out.println("JayZ.collectMoney()");
}
}
3.定义一个类StarProxy(类似"经纪人"的角色)实现Star接口
package com.study.staticProxy;
public class StarProxy implements Star {
//
private Star star;
//这两步是关键步骤
public StarProxy(Star star) {
this.star=star;
}
@Override
public void conversation() {
System.out.println("StarProxy.conversation()");
}
@Override
public void signContract() {
System.out.println("StarProxy.signContract()");
}
@Override
public void bookTicket() {
System.out.println("StarProxy.bookTicket()");
}
@Override
public void sing() {
star.sing();
}
@Override
public void collectMoney() {
System.out.println("StarProxy.collectMoney()");
}
}
4.定义Client("用户")测试类
package com.study.staticProxy;
public class Client {
public static void main(String[] args) {
Star jayz=new JayZ();
Star proxy=new StarProxy(jayz);
proxy.conversation();
proxy.signContract();
proxy.bookTicket();
proxy.sing();
proxy.collectMoney();
}
}
输出结果:
StarProxy.conversation()
StarProxy.signContract()
StarProxy.bookTicket()
***周杰伦在唱歌****
StarProxy.collectMoney()
代理就是一种“中介”,类比上面现实生活的例子,“经纪人”就是“明星”的代理。“明星”的核心业务只管好sing()唱歌就行,其他琐碎的事,交给经纪人来做。代理这种设计模式的意义也在于此,它可以使真正的业务逻辑和琐碎的流程分开,每个类专注自己所要做的事。感叹面向对象编程的奇妙,只需一个接口,两个实现类,就可实现如此深远的意义!
代理的分类
- 静态代理,前面的栗子(静态定义代理类,我们自己定义的代理类)。
- 动态代理(指由程序自动生成代理类):JDK自带的动态代理,Javaassist字节码操作库实现,CGLIB,ASM(底层使用指令,可维护性较差)
JDK的动态代理
好了,对代理有个概念之后,现在来谈谈JDK的动态代理。
- 什么叫动态的代理?-->就是指代理对象是个“变量”,它可以根据需求再产生
- 怎么产生动态代理呢?-->首先,想产生对象,那么必须得有个模板,那就是“类”。而类又是怎么来的呢,通常,我们是通过类加载器加载硬盘上的.class文件加载到内存中,准确的说是方法区中,类的信息就是这样来的。然后,再通过类信息在堆中创建出对应的Class对象。而现在硬盘上,我们可没有代理类的.class文件哦,其实我们是根据程序Proxy.newInstance()创建出对应的类信息以及类对象。
还是用上面的栗子,Star接口、JayZ类不变
1.添加StarHandler处理类(注意:处理类不是代理类)
package com.study.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class StarHandler implements InvocationHandler{
private Star star;
public StarHandler(Star star) {
this.star=star;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("谈判");
if(method.getName().equals("sing")) {
method.invoke(star, args);
}
System.out.println("付钱");
return null;
}
}
2.修改原来的Client测试类:
package com.study.dynamicProxy;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
Star jayz=new JayZ();
StarHandler handler=new StarHandler(jayz);
Star proxy=(Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[] {Star.class}, handler);
proxy.conversation();
System.out.println("-----------------");
proxy.sing();
}
}
打印结果:
谈判
付钱
-----------------
谈判
***周杰伦在唱歌****
付钱
StarHandler类:
- 实现InvocationHandle接口的类是一个“中间类”,或者说是“处理类”,本身不是代理类,作用是:把真正的对象和代理对象连接起来,就像混凝土一样把两块砖连接起来。
Proxy.newProxyInstance(loader, interfaces, h)
- 第一个参数类加载器,无所谓哪个类的类加载器;
- 第二参数是想要在字节码里面加载的接口,以便于得到接口的方法;
- 第三个参数InvocationHandle ih相当于是.class字节码里面的属性,以便接口各个方法调用ih.invoke()方法。从内存的角度就很好理解了(画栈堆方法区图)。
主要作用:
- 创建一个“新的”类信息(字节码信息,在字节码里面加载相关的接口);
- 在根据此类信息创建对象于堆上;
- 把堆中的对象赋给栈中的方法。
栈堆图分析:如下图所示,“新的”Proxy代理类的信息结构
当客户端调用proxy.sing()时,就是在调用方法区里面的sing()方法,从而会激活处理类StarHandler的invoke()方法,再根据invoke()方法里的条件判断,看是否激活method.invoke(star, args)。
此处主要用到了反射和类加载的知识,首先得把这两块的知识点摸个明白。
好了,主要流程已经讲完了,纪念一下我第一篇博客!