在 Java 中动态代理和代理都很常见,几乎是所有主流框架都用到过的知识。在面试中也是经常被提到的话题,于是便总结了本文。
Java动态代理的基本原理为:被代理对象需要实现某个接口(这是前提),代理对象会拦截对被代理对象的方法调用,在其中可以全然抛弃被代理对象的方法实现而完成另外的功能,也可以在被代理对象方法调用的前后增加一些额外的功能。
动态代理可以为其他对象提供一个代理以控制对某个对象的访问。
代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
JDK 动态代理
动态代理的核心其实就是代理对象的生成,即 Proxy.newProxyInstance(classLoader, proxyInterface, handler)。
让我们进入newProxyInstance方法观摩下,核心代码其实就三行。
这个方法需要三个参数:
- ClassLoader,用于加载代理类的 Loader 类,通常这个 Loader 和被代理的类是同一个 Loader 类。
- Interfaces,是要被代理的那些那些接口。
- InvocationHandler,就是用于执行除了被代理接口中方法之外的用户自定义的操作,他也是用户需要代理的最终目的。用户调用目标方法都被代理到 InvocationHandler 类中定义的唯一方法 invoke 中。
1
2
3
4
5
6
|
//获取代理类
Class cl = getProxyClass(loader, interfaces);
//获取带有InvocationHandler参数的构造方法
Constructor cons = cl.getConstructor(constructorParams);
//把handler传入构造方法生成实例
return
(Object) cons.newInstance(
new
Object[] { h });
|
一个典型的动态代理创建对象过程可分为以下四个步骤:
1、通过实现InvocationHandler接口创建调用处理器
1
|
IvocationHandler handler =
new
InvocationHandlerImpl(...);
|
2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
1
|
Class clazz = Proxy.getProxyClass(classLoader,
new
Class[]{...});
|
3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
1
|
Constructor constructor = clazz.getConstructor(
new
Class[]{InvocationHandler.
class
});
|
4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
1
|
Interface Proxy = (Interface)constructor.newInstance(
new
Object[] (handler));
|
为了简化对象创建过程,Proxy类中的newProxyInstance方法封装了2~4,只需两步即可完成代理对象的创建。
1
2
|
Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject.
class
.getClassLoader(),
new
Class[]{Subject.
class
},
new
InvocationHandlerImpl (real));
|
生成的proxySubject继承Proxy类实现Subject接口。实现的Subject的方法实际是调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的方法(Object result=method.invoke(proxied,args));
重点Proxy.newProxyInstance,源码分析,会在其他文档中单独总结记录。类Proxy的getProxyClass方法调用ProxyGenerator的 generateProxyClass方法产生ProxySubject.class的二进制数据。
创建代理对象时序图
获取代理类
getProxyClass(loader, interfaces)方法用于获取代理类,它主要做了三件事情:
在当前类加载器的缓存里搜索是否有代理类,没有则生成代理类并缓存在本地JVM里。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
// 缓存的key使用接口名称生成的List
Object key = Arrays.asList(interfaceNames);
synchronized
(cache) {
do
{
Object value = cache.get(key);
// 缓存里保存了代理类的引用
if
(value
instanceof
Reference) {
proxyClass = (Class) ((Reference) value).get();
}
if
(proxyClass !=
null
) {
// 代理类已经存在则返回
return
proxyClass;
}
else
if
(value == pendingGenerationMarker) {
// 如果代理类正在产生,则等待
try
{
cache.wait();
}
catch
(InterruptedException e) {
}
continue
;
}
else
{
//没有代理类,则标记代理准备生成
cache.put(key, pendingGenerationMarker);
break
;
}
}
while
(
true
);
}
|
生成并加载代理类
代理类的生成主要是以下这两行代码:
1
2
3
4
|
//生成代理类的字节码文件并保存到硬盘中(默认不保存到硬盘)
proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);
//使用类加载器将字节码加载到内存中
proxyClass = defineClass0(loader, proxyName,proxyClassFile,
0
, proxyClassFile.length);
|
代理类的生成过程
ProxyGenerator.generateProxyClass()方法属于sun.misc包下,Oracle并没有提供源代码,但是我们可以使用
JD-GUI这样的反编译软件打开jre\lib\rt.jar来一探究竟,以下是其核心代码的分析。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//添加接口中定义的方法,此时方法体为空
for
(
int
i =
0
; i <
this
.interfaces.length; i++) {
localObject1 =
this
.interfaces[i].getMethods();
for
(
int
k =
0
; k < localObject1.length; k++) {
addProxyMethod(localObject1[k],
this
.interfaces[i]);
}
}
//添加一个带有InvocationHandler的构造方法
MethodInfo localMethodInfo =
new
MethodInfo(
"<init>"
,
"(Ljava/lang/reflect/InvocationHandler;)V"
,
1
);
//循环生成方法体代码(省略)
//方法体里生成调用InvocationHandler的invoke方法代码。(此处有所省略)
this
.cp.getInterfaceMethodRef(
"InvocationHandler"
,
"invoke"
,
"Object; Method; Object;"
)
//将生成的字节码,写入硬盘,前面有个if判断,默认情况下不保存到硬盘。
localFileOutputStream =
new
FileOutputStream(ProxyGenerator.access$
000
(
this
.val$name) +
".class"
);
localFileOutputStream.write(
this
.val$classFile);
|
生成的代理类源码
那么通过以上分析,我们可以推出动态代理为我们生成了一个这样的代理类。把方法doSomeThing的方法体修改为调用LogInvocationHandler的invoke方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public
class
ProxyBusiness
extends
Proxy
implements
IBusiness, IBusiness2 {
private
LogInvocationHandler h;
@Override
public
void
doSomeThing2() {
try
{
Method m = (h.target).getClass().getMethod(
"doSomeThing2"
,
null
);
h.invoke(
this
, m,
null
);
}
catch
(Throwable e) {
// 异常处理(略)
}
}
@Override
public
boolean
doSomeThing() {
try
{
Method m = (h.target).getClass().getMethod(
"doSomeThing"
,
null
);
return
(Boolean) h.invoke(
this
, m,
null
);
}
catch
(Throwable e) {
// 异常处理(略)
}
return
false
;
}
public
ProxyBusiness(LogInvocationHandler h) {
this
.h = h;
}
|
测试代理的代码如下:
1
2
3
4
5
6
7
|
//测试
public
static
void
main(String[] args) {
//构建AOP的Advice
LogInvocationHandler handler =
new
LogInvocationHandler(
new
Business());
new
ProxyBusiness(handler).doSomeThing();
new
ProxyBusiness(handler).doSomeThing2();
}
|
下面看一个自定义代理的实现。
被代理类接口
1
2
3
|
public
interface
Subject {
public
void
doSomething();
}
|
被代理类
1
2
3
4
5
6
|
//目标对象
public
class
RealSubject
implements
Subject{
public
void
doSomething() {
System.out.println(
"call doSomething()"
);
}
}
|
调用处理器(切面)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public
class
ProxyHandler
implements
InvocationHandler {
private
Object proxied;
public
ProxyHandler( Object proxied ) {
this
.proxied = proxied;
}
public
Object invoke( Object proxy, Method method, Object[] args )
throws
Throwable {
//在转调具体目标对象之前,可以执行一些功能处理
System.out.println(
"doSomething before"
);
//转调具体目标对象的方法
return
method.invoke( proxied, args);
//在转调具体目标对象之后,可以执行一些功能处理
System.out.println(
"doSomething after"
);
}
}
|
测试我们的代理实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public
class
DynamicProxy {
public
static
void
main( String args[] ) {
RealSubject real =
new
RealSubject();
Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject.
class
.getClassLoader(),
new
Class[]{Subject.
class
},
new
ProxyHandler(real));
proxySubject.doSomething();
//write proxySubject class binary data to file
createProxyClassFile();
}
public
static
void
createProxyClassFile() {
String name =
"ProxySubject"
;
byte
[] data = ProxyGenerator.generateProxyClass( name,
new
Class[] { Subject.
class
} );
try
{
FileOutputStream out =
new
FileOutputStream( name +
".class"
);
out.write( data );
out.close();
}
catch
( Exception e ) {
e.printStackTrace();
}
}
}
|
运行结果:
1
2
3
|
doSomething before
call doSomething()
doSomething after
|
Proxy 接口
Proxy 的主要静态变量
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// 映射表:用于维护类装载器对象到其对应的代理类缓存
private
static
Map loaderToCache =
new
WeakHashMap();
// 标记:用于标记一个动态代理类正在被创建中
private
static
Object pendingGenerationMarker =
new
Object();
// 同步表:记录已经被创建的动态代理类类型,主要被方法 isProxyClass 进行相关的判断
private
static
Map proxyClasses = Collections.synchronizedMap(
new
WeakHashMap());
// 关联的调用处理器引用
protected
InvocationHandler h;
Proxy的构造方法
// 由于 Proxy 内部从不直接调用构造函数,所以 private 类型意味着禁止任何调用
private
Proxy() {}
// 由于 Proxy 内部从不直接调用构造函数,所以 protected 意味着只有子类可以调用
protected
Proxy(InvocationHandler h) {
this
.h = h;}
|
ProxySubject 源码
创建的代理类 ProxySubject.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
import
java.lang.reflect.*;
public
final
class
ProxySubject
extends
Proxy
implements
Subject{
private
static
Method m1;
private
static
Method m0;
private
static
Method m3;
private
static
Method m2;
public
ProxySubject(InvocationHandler invocationhandler){
super
(invocationhandler);
}
public
final
boolean
equals(Object obj){
try
{
return
((Boolean)
super
.h.invoke(
this
, m1,
new
Object[] {
obj
})).booleanValue();
}
catch
(Error _ex) {
}
catch
(Throwable throwable){
throw
new
UndeclaredThrowableException(throwable);
}
}
public
final
int
hashCode() {
try
{
return
((Integer)
super
.h.invoke(
this
, m0,
null
)).intValue();
}
catch
(Error _ex) {
}
catch
(Throwable throwable){
throw
new
UndeclaredThrowableException(throwable);
}
}
/*关键部分*/
public
final
void
doSomething() {
try
{
// Proxy类中protected InvocationHandler h;关联的调用处理器引用
super
.h.invoke(
this
, m3,
null
);
return
;
}
catch
(Error _ex) {
}
catch
(Throwable throwable) {
throw
new
UndeclaredThrowableException(throwable);
}
}
public
final
String toString() {
try
{
return
(String)
super
.h.invoke(
this
, m2,
null
);
}
catch
(Error _ex) {
}
catch
(Throwable throwable){
throw
new
UndeclaredThrowableException(throwable);
}
}
static
{
try
{
m1 = Class.forName(
"java.lang.Object"
).getMethod(
"equals"
,
new
Class[] {
Class.forName(
"java.lang.Object"
)
});
m0 = Class.forName(
"java.lang.Object"
).getMethod(
"hashCode"
,
new
Class[
0
]);
m3 = Class.forName(
"Subject"
).getMethod(
"doSomething"
,
new
Class[
0
]);
m2 = Class.forName(
"java.lang.Object"
).getMethod(
"toString"
,
new
Class[
0
]);
}
catch
(NoSuchMethodException nosuchmethodexception) {
throw
new
NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch
(ClassNotFoundException classnotfoundexception){
throw
new
NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
|
CGLib 动态代理
动态字节码生成。使用动态字节码生成技术实现AOP原理是在运行期间目标字节码加载后,生成目标类的子类,将切面逻辑加入到子类中,所以使用Cglib实现AOP不需要基于接口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
public
static
void
main(String[] args) {
byteCodeGe();
}
public
static
void
byteCodeGe() {
//创建一个织入器
Enhancer enhancer =
new
Enhancer();
//设置父类
enhancer.setSuperclass(Business.
class
);
//设置需要织入的逻辑
enhancer.setCallback(
new
LogIntercept());
//使用织入器创建子类
IBusiness2 newBusiness = (IBusiness2) enhancer.create();
newBusiness.doSomeThing2();
}
/**
* 记录日志
*/
public
static
class
LogIntercept
implements
MethodInterceptor {
@Override
public
Object intercept(Object target, Method method, Object[] args, MethodProxy proxy)
throws
Throwable {
//执行原有逻辑,注意这里是invokeSuper
Object rev = proxy.invokeSuper(target, args);
//执行织入的日志
if
(method.getName().equals(
"doSomeThing2"
)) {
System.out.println(
"记录日志"
);
}
return
rev;
}
}
|
转自:https://www.xttblog.com/?p=2732