在面向对象编程时,经常会遇到一些需要统一处理的东西,比如每个方法的耗时打印、数据库的事物管理、以及一些其他的切面功能,这些功能如果加入到每个类里,就会有很多的重复代码,而且不便于维护。因此产生了代理对象,将这些需要统一处理的功能加入到代理对象中,统一由代理对象进行管理。
比如下面的一个图书类:
/**
* 被代理对象接口
*/
public interface BookInterface {
void add();
void print();
}
/**
* 被代理对象实现类
*/
public class BookInterfaceImpl implements BookInterface{
public void add() {
System.out.println("add book!");
}
public void print() {
System.out.println("print method");
}
}
现在需要在每个方法前或者后增加一定的处理,通过静态代理、动态代理分别怎么实现?
静态代理的实现方法是,通过新建一个代理对象实现被代理对象的接口,重写被代理对象的方法,加入增强处理;示例代码如下:
/**
* 静态代理对象
*/
public class StaticPoxyBook implements BookInterface{
//被代理对象
private BookInterface target;
public StaticPoxyBook(BookInterface target){
this.target = target;
}
@Override
public void add(){
System.out.println("静态代理前处理");
target.add();
}
@Override
public void print() {
System.out.println("静态代理前处理");
target.print();
}
}
测试代码
import org.junit.Before;
import org.junit.Test;
public class MainClass {
BookInterface bookInterface ;
@Before
public void testBefore(){
bookInterface = new BookInterfaceImpl();
}
@Test
public void testStaticProxy(){
//静态代理:通过初始化代理对象,调用代理对象的相同的方法,实现增强功能
StaticPoxyBook staticPoxyBook = new StaticPoxyBook(bookInterface);
staticPoxyBook.add();
}
}
jdk动态代理是通过新建一个代理对象,在代理对象实现InvocationHandler接口,并重写invoke方法,实现增强处理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* jdk动态代理对象
*/
public class DynamicProxyBook implements InvocationHandler {
Object target;
public Object getInstance(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前处理");
return method.invoke(target, args);
}
}
测试代码(为了生成动态的class代理文件,这里用main方法测试)
public static void main(String[] args) {
BookInterface bookInterface = new BookInterfaceImpl();
//生成$Proxy0的class文件(生成class路径在src同级目录下的com\sun里)
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
DynamicProxyBook dynamicProxyBook = new DynamicProxyBook();
//动态代理:通过getInstance代理对象,调用代理接口,实现增强功能
BookInterface bookInterfaceProxy = (BookInterface) dynamicProxyBook.getInstance(bookInterface);
bookInterfaceProxy.add();
}
动态代理生成的class文件,如下
package com.sun.proxy;
import com.proxy.test.BookInterface;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
/**
* 生成的代理对象和被代理对象实现同一接口
* 拥有我们新建的代理对象的引用 paramInvocationHandler
*/
public final class $Proxy0 extends Proxy implements BookInterface {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject) {
try {
return ((Boolean) this.h.invoke(this, m1, new Object[]{paramObject})).booleanValue();
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void print() {
try {
this.h.invoke(this, m4, null);
return;
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString() {
try {
return (String) this.h.invoke(this, m2, null);
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
/**
* 调用方法时,实际调用的是我们新建的DynamicProxyBook的invoke方法
*/
public final void add() {
try {
this.h.invoke(this, m3, null);
return;
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode() {
try {
return ((Integer) this.h.invoke(this, m0, null)).intValue();
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m4 = Class.forName("com.proxy.test.BookInterface").getMethod("print", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.proxy.test.BookInterface").getMethod("add", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException localNoSuchMethodException) {
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
} catch (ClassNotFoundException localClassNotFoundException) {
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
通过生成的class文件,可以知道jdk动态代理只能代理接口。
和jdk的类似,代理对象实现MethodInterceptor 接口,然后重写intercept方法,实现增强处理。
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* cglib动态代理对象
*/
public class CglibDymicProxyBook implements MethodInterceptor {
Object target;
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib前处理");
return methodProxy.invokeSuper(o, objects);
}
}
测试代码
public static void main(String[] args) {
BookInterface bookInterface = new BookInterfaceImpl();
//生成代理的class文件
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D://code");
CglibDymicProxyBook cglibDymicProxyBook = new CglibDymicProxyBook();
//动态代理:通过getInstance代理对象,调用代理接口,实现增强功能
BookInterface bookInterfaceProxy = (BookInterface) cglibDymicProxyBook.getInstance(bookInterface);
bookInterfaceProxy.add();
}