JDK动态代理的实现----详细易懂
场景
假设A原本只负责做两件事情doLogin()
、doLogout()
,后来需要A在doLogin()
前后都要打印一次日志,但是这不是A要负责的业务范围,于是A就找来B,他俩就签订了一份协议(告诉代理类我的哪些方法需要被代理、增强),让B来完成doLogin()
并且前后打印日志。
在这个场景中,B代理了A的doLogin
业务,并对业务进行了增强。A就是被代理类,B就是代理类,那份协议就是我们要定义的接口(interface);
下面就根据这个场景实现动态代理
代码实现
1.根据上面的场景,我们先把接口(协议)定义出来:
//定义接口,指明需要代理的方法
public interface Subject {
void doLogin();
}
2. 让A实现接口Subject,
public class A implements Subject{
@Override
public void doLogin() {
System.out.println("doLogin>>>>>>>>>>>>>>>");
}
public void doLogout(){
System.out.println("doLogout>>>>>>>>>>>>>");
}
}
3. 重点来了,接下来我们需要实现InvocationHandler
接口,它是代理逻辑执行器,不是代理类,它的作用是实现代理类的逻辑:
至于为什么要实现这个接口,可以看一下:jdk动态代理源码解析;
有一些刚刚了解动态代理的小伙伴会把这个实现类误当做是代理类,InvocationHandler
的实现类就是用来实现代理逻辑的,通过重写invoke()方法,对被代理的方法进行增强(比如:上面代码中,我们可以在执行代理方法前后加入其他业务逻辑)。
4. 获取代理对象:
为了便利,我将获取代理对象的业务封装了一个类,通过静态方法getProxy()
获取代理对象:
通过java.lang.reflect.Proxy
的静态方法newProxyInstance(...)
获取我们想要的代理对象
newProxyInstance()
需要的参数如下:
ClassLoader loader
:类加载器;
Class<?>[] interfaces
:代理类需要实现的接口集合(就是被代理类实现的接口);
InvocationHandler h
:代理类会根据传进来的接口去实现需要实现的接口方法,但是接口方法的内部逻辑需要依赖InvocationHandler
(就是上面实现InvocationHandler
接口的类的invoke()
中的内容);
5. 测试
上面代码中proxy就是A的代理对象,并且通过idea的提示可以看到,proxy只能调用doLogin()方法,并没有doLogout()方法,原因就是我们在接口(协议)中只定义了doLogin()方法(在这里之所以多说这么一句,是因为我在放学习jdk动态代理时出现过的疑问:怎么控制被代理类中的哪些方法需要被代理增强?原因就在这);
执行结果:
6.总结
实现JDK的动态代理功能主要步骤:
1). 分析业务场景,确定被代理类的业务需要和要被代理增强的方法;
2). 被代理类至少要实现一个接口,并且该接口中定义了需要被代理的方法;
3). 通过实现InvocationHandler
接口并重写invoke()
方法来实现被代理方法的业务扩展;
4). 通过java.lang.reflect.Proxy
类的静态方法newProxyInstance()
获取代理对象;
(以上内容有不足的地方欢迎大佬们指正,感谢!)
接下来这篇文章是对Proxy.newProxyInstance源码的分析: