本文已参与「新人创作礼」活动,一起开启掘金创作之路。
动态代理
什么是动态代理?
- 动态代理的角色和静态代理的一样
- 动态代理的代理类是动态生成的 ,静态代理的代理类是我们写的
- 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
- 基于接口的动态代理----JDK动态代理
- 基于类的动态代理--cglib
动态代理就是当有大量的类需要执行一些共同代码时,我们自己写太麻烦,那能不能直接使用java代码,自动生成一个类帮助我们批量的增强某些方法。 本文主要介绍JDK动态代理。
JDK原生的动态代理
【核心】:InvocationHandler和Proxy
具体从代码部分入手帮助大家理解。 我现在写了个singer接口,如下。
public interface Singer {
void sing();
}
现在有个男歌手,当然他要达到某个标准才能成为一个歌手,所以这个男歌手要实现singer这个接口,这个标准,最后成了一个真正的男歌手。 具体实现如下:
public class ManSinger implements Singer {
//歌手需要一个名字
private String name;
//构造器给他名字
public ManSinger(String name) {
this.name = name;
}
@Override
public void sing() {
System.out.println(name+"开始唱歌了!");
}
}
正如之前静态代理那块说的,歌手只会唱歌,举办演唱会其他事宜,包括协商价格、演唱会怎么举办歌手并不懂,所以他需要一个经纪人。我们就定义一个动态代理类来表示这个经纪人,如下。
public class Agent implements InvocationHandler {
//要代理的对象
private Singer singer;
public Agent(Singer singer) {
this.singer = singer;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("经纪人把把关...");
//singer.sing();
Object runObj = method.invoke(singer, args);
System.out.println("唱完了...");
return runObj;
}
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{Singer.class},this);
}
}
先声明一下需要代理的对象,我们需要代理的接口类型是Singer,这里可以理解成这个代理类负责去卖singer这个接口标准的插座。
invoke这个方法就是使用处理代理实例上的方法,这个方法有三个参数:
- 第一个参数proxy是要代理的实例;
- 第二个参数method是要处理的方法,对应于调用代理实例上的接口方法的实例。方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口;
- args包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean。
其实就是只要写invoke这个方法就可以了,正如我要代理singer这个接口实例,我就把singer传了进去,把代理要做的事情写在invoke方法前后,去增强这个接口方法。 而getProxy这个函数就是返回一个代理实例,给我们生成一个代理对象。下面说一下测试部分。
public class Client {
public static void main(String[] args) {
ManSinger luhan = new ManSinger("luhan");
Agent agent = new Agent(luhan);
//agent.setSinger(luhan);
Singer singer = (Singer)agent.getProxy();
singer.sing();
}
}
测试代码解释:这里就好比有一个男歌手luhan,然后他去找了个agent经纪人,或者说有个经纪人来找luhan了。然后他用自己的invoke来帮我们筹划演唱会的各种事宜,最后用getProxy把这个演唱会打包。