JDK动态代理
代理类实现InvocationHandler接口
- 通过反射实现
- 被代理类必须实现某个接口
代码示例:
// ------------- 代理类 -------------
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@Slf4j
public class ProxyTest implements InvocationHandler {
private Object proxy;
public void setProxy(Object proxy) {
this.proxy = proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.info("{}--方法执行前", method.getName());
Object object = method.invoke(this.proxy, args);
log.info("{}--方法执行后", method.getName());
return object;
}
public Object createProxyObj() {
return Proxy.newProxyInstance(proxy.getClass().getClassLoader(), proxy.getClass().getInterfaces(), this);
}
}
// ------------- 调用 -------------
public static void main(String[] args) {
String s = new String("test");
ProxyTest test = new ProxyTest();
test.setProxy(s);
CharSequence s1 = (CharSequence)test.createProxyObj();
log.info("call before");
s1.length();
log.info("call end");
}
// 输出内容:
// call before
// length--方法执行前
// length--方法执行后
// call end
CGLIB动态代理
代理类实现InvocationHandler接口
- 通过继承代理
- 被代理类必须可以被继承,且方法可以被覆盖
// ------------- 代理类 -------------
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
@Slf4j
public class ProxyTest implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
log.info("{}--方法执行前", method.getName());
Object object = methodProxy.invokeSuper(o, objects);
log.info("{}--方法执行后", method.getName());
return object;
}
}
// ------------- 被代理类 -------------
@Slf4j
public class Test {
public void test1() {
log.info("test1方法被执行");
}
// final修饰的方法不能被子类覆盖,无法代理
public final void test2() {
log.info("test2方法被执行");
}
}
// ------------- 调用 -------------
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Test.class);
enhancer.setCallback(new ProxyTest());
Test test2 = (Test) enhancer.create();
log.info("test1 call before");
test2.test1();
log.info("test1 call end");
log.info("test2 call before");
test2.test2();
log.info("test2 call end");
}
// 输出内容:
// test1 call before
// test1--方法执行前
// test1方法被执行
// test1--方法执行后
// test1 call end
// test2 call before
// test2方法被执行
// test2 call end
javassist动态代理
ProxyFactory创建
ProxyFactory方式分别为基于接口和类,对应JDK代理方式和CGLib代理方式
基于接口
// ------------- 代理类 -------------
import javassist.util.proxy.MethodHandler;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Method;
@Slf4j
public class ProxyTest implements MethodHandler {
private Object proxy;
public void setProxy(Object proxy) {
this.proxy = proxy;
}
@Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
log.info("{}--方法执行前", thisMethod.getName());
Object object = thisMethod.invoke(this.proxy, args);
log.info("{}--方法执行后", thisMethod.getName());
return object;
}
}
// ------------- 调用 -------------
public static void main(String[] args) throws Exception {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setInterfaces(new Class[]{CharSequence.class});
Class<?> proxyClass = proxyFactory.createClass();
CharSequence s1 = (CharSequence) proxyClass.getDeclaredConstructor().newInstance();
String s = new String("test");
ProxyTest test = new ProxyTest();
test.setProxy(s);
((ProxyObject) s1).setHandler(test);
log.info("call before");
s1.length();
log.info("call end");
}
// 输出内容:
// call before
// length--方法执行前
// length--方法执行后
// call end
基于类
// ------------- 代理类 -------------
import javassist.util.proxy.MethodHandler;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Method;
@Slf4j
public class ProxyTest implements MethodHandler {
@Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
log.info("{}--方法执行前", thisMethod.getName());
Object object = proceed.invoke(self, args);
log.info("{}--方法执行后", thisMethod.getName());
return object;
}
}
// ------------- 被代理类 -------------
@Slf4j
public class Test {
public void test1() {
log.info("test1方法被执行");
}
// final修饰的方法不能被子类覆盖,无法代理
public final void test2() {
log.info("test2方法被执行");
}
}
// ------------- 调用 -------------
public static void main(String[] args) throws Exception {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setSuperclass(Test.class);
proxyFactory.setFilter((m) -> !m.getName().equals("finalize"));
Class c = proxyFactory.createClass();
Object proxy = c.newInstance();
((Proxy)proxy).setHandler(new ProxyTest());
Test test = (Test) proxy;
log.info("test1 call before");
test.test1();
log.info("test1 call end");
log.info("test2 call before");
test.test2();
log.info("test2 call end");
}
// 输出内容:
// test1 call before
// test1--方法执行前
// test1方法被执行
// test1--方法执行后
// test1 call end
// test2 call before
// test2方法被执行
// test2 call end
字节码生成代理类
字节码生成代理类就是动态生成代理类,通过实现接口或继承类对其代理;下面代码举例一个继承类的方式
// ------------- 被代理类 -------------
@Slf4j
public class Test {
public void test() {
log.info("test方法被执行");
}
}
// ------------- 代理并调用 -------------
public static void main(String[] args) throws Exception {
ClassPool mPool = ClassPool.getDefault();
CtClass mCtc = mPool.makeClass("ProxyTest");
mPool.insertClassPath(new ClassClassPath(Test.class));
mCtc.setSuperclass(mPool.get(Test.class.getName()));
mCtc.addConstructor(CtNewConstructor.defaultConstructor(mCtc));
mCtc.addField(CtField.make("public " + Test.class.getName() + " proxyObj;", mCtc));
String src = "public void test() { "
+ "System.out.println(\"test 方法执行前\");"
+ "proxyObj.test();"
+ "System.out.println(\"test 方法执行后\"); "
+ "}";
mCtc.addMethod(CtNewMethod.make(src, mCtc));
Class<?> pc = mCtc.toClass();
Test bytecodeProxy = (Test) pc.getDeclaredConstructor().newInstance();
Field filed = bytecodeProxy.getClass().getField("proxyObj");
filed.set(bytecodeProxy, new Test());
log.info("call before");
bytecodeProxy.test();
log.info("call end");
}
// 输出内容:
// call before
// test 方法执行前
// test方法被执行
// test 方法执行后
// call end