动态代理

代理的基础类

1
2
3
4
5
6
7
8
9
10
public interface Subject {
void doSomething(String param);
}

public class RealSubject implements Subject {
@Override
public void doSomething(String param) {
System.out.println("RealSubject do something " + param);
}
}

静态代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class SubjectProxy implements Subject {

private Subject subject;
public SubjectProxy(Subject subject) {
this.subject = subject;
}

@Override
public void doSomething(String param) {
System.out.println("Do something before");
subject.doSomething(param);
System.out.println("Do something after");
}
}

JDK动态代理

JDK动态代理是jre提供的类库,可直接使用不依赖第三方,但JDK动态代理只能代理接口。首先创建一个代理类EnhaceInvocationHandler实现java.lang.reflect.InvocationHandler接口,重写invoke方法。在method.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
25
26
27
28
29
30
31
32
33
public class EnhaceInvocationHandler implements InvocationHandler {

private Object target;

public EnhaceInvocationHandler(Object target) {
this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (args != null) {
for (Object obj : args) {
System.out.println("args==" + obj.toString());
}
} else {
System.out.println("args==null");
}

try {
System.out.println("Do something before");
Object result = method.invoke(target, args);
System.out.println("Do something after");
return result;
} catch (Exception e) {
e.getCause().printStackTrace();
throw e;
}
}

public Object creatProxyObj() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
}

代理配置

1
2
3
4
5
6
7
8
9
Subject realSubject = new RealSubject();
Subject subject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(),
new Class[]{Subject.class},
new EnhaceInvocationHandler(realSubject));
subject.doSomething("AAAA");

EnhaceInvocationHandler handler = new EnhaceInvocationHandler(realSubject);
Subject subject = (Subject) handler.creatProxyObj();
subject.doSomething("AAAA");

CGLib代理

代理的目的是构造一个和被代理的对象同样行为的对象,一个对象的行为是在类中定义的,对象只是类的实例,故构造代理不一定非得通过持有、包装对象这一种方式。CGLib是通过继承父类所有的公有方法,然后重写这些方法,在重写时对这些方法增强。首先也是创建一个代理类CGLibProxy实现net.sf.cglib.proxy.MethodInterceptor接口重写intercept方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class CGLibProxy implements MethodInterceptor {

@Override
public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Do something before");
Object object = methodProxy.invokeSuper(obj, objects);
System.out.println("Do something after");
return object;
}

public Object creatProxyObj(Class<?> clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
}

在配置代理的地方与JDK动态代理略有区别。并不要求委托类必须实现接口,底层采用asm字节码生成框架生成代理类的字节码,EnhancerCGLib字节码增强器,可以方便的对类进行扩展,内部调用GeneratorStrategy.generate方法生成代理类的字节码,CGLib动态代理不仅仅可以代理接口,还可以代理非接口类

1
2
3
4
5
6
7
8
9
10
Subject realSubject = new RealSubject();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(realSubject.getClass());
enhancer.setCallback(new CGLibProxy());
Subject subject = (Subject) enhancer.create();
subject.doSomething("AAAA");

CGLibProxy proxy = new CGLibProxy();
Subject subject = (Subject) proxy.creatProxyObj(realSubject.getClass());
subject.doSomething("AAAA");

CGLib动态代理中生成的字节码更加复杂,生成的代理类是委托类的子类,且不能处理被final关键字修饰的方法JDK采用反射机制调用委托类的方法,CGLib采用类似索引的方式直接调用委托类方法