JDK动态代理原理分析
interface Foo {
void foo();
}
class Target implements Foo {
@Override
public void foo() {
System.out.println("foo..");
}
}
public class A13 {
public static void main(String[] args) {
$Proxy0 proxy = new $Proxy0();
proxy.foo();
}
}
public class $Proxy0 {
}
如果$Proxy0就是jdk创建的动态代理对象
我要增强foo方法,可以这样
public class $Proxy0 {
public void foo() {
System.out.println("增强");
new Target().foo();
}
}
但是我们希望通过public static void main(String[] args)来控制增强,那么我们的代码改成了这样
interface Foo {
void foo();
}
class Target implements Foo {
@Override
public void foo() {
System.out.println("foo..");
}
}
interface InvocationHandler {
void invoke();
}
public class A13 {
public static void main(String[] args) {
$Proxy0 proxy = new $Proxy0(() -> {
System.out.println("增强");
new Target().foo();
});
proxy.foo();
}
}
public class $Proxy0 {
private InvocationHandler h;
public $Proxy0(InvocationHandler invocationHandler){
h = invocationHandler;
}
public void foo() {
h.invoke();
}
}
现在有一个问题这个只能增强foo这个方法,当要增强别的方法,就不能这么写了。于是我在代理类里面通过反射创建了存放当前方法的参数
public class $Proxy0 implements Foo {
private InvocationHandler h;
public $Proxy0(InvocationHandler invocationHandler) {
h = invocationHandler;
}
@Override
public void foo() {
try {
Method method = Foo.class.getMethod("foo");
h.invoke(method, new Object[0]);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
@Override
public void bar() {
try {
Method method = Foo.class.getMethod("bar");
h.invoke(method, new Object[0]);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
interface Foo {
void foo();
void bar();
}
interface InvocationHandler {
void invoke(Method method, Object[] args) throws RuntimeException, IllegalAccessException, InvocationTargetException;
}
public class A13 {
static class Target implements Foo {
@Override
public void foo() {
System.out.println("foo..");
}
@Override
public void bar() {
System.out.println("bar..");
}
}
public static void main(String[] args) {
$Proxy0 proxy = new $Proxy0(new InvocationHandler() {
@Override
public void invoke(Method method, Object[] args) throws RuntimeException, IllegalAccessException, InvocationTargetException {
Target target = new Target();
System.out.println("增强");
// new Target().foo();
method.invoke(target, args);
}
});
proxy.foo();
proxy.bar();
}
}
现在我们这个软件又有一个问题就是无法返回参数这时我们需要改变一下InvocationHandler的invoke方法让他返回Object,同时我们由于我们不能每次调用方法都去反射获取方法,可以生成一个静态变量,方便方法的调用
static public Method foo;
static public Method bar;
static {
try {
bar = Foo.class.getMethod("bar");
foo = Foo.class.getMethod("foo");
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
interface Foo {
void foo();
int bar();
}
/*interface InvocationHandler {
void invoke(Method method, Object[] args) throws RuntimeException, IllegalAccessException, InvocationTargetException;
}*/
public class A13 {
static class Target implements Foo {
@Override
public void foo() {
System.out.println("foo..");
}
@Override
public int bar() {
System.out.println("bar..");
return 100;
}
}
public static void main(String[] args) {
$Proxy0 proxy = new $Proxy0(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
Target target = new Target();
System.out.println("增强");
// new Target().foo();
return method.invoke(target, args);
}
});
proxy.foo();
int bar = proxy.bar();
System.out.println(bar);
}
}
public class $Proxy0 implements Foo {
private InvocationHandler h;
public $Proxy0(InvocationHandler invocationHandler) {
h = invocationHandler;
}
@Override
public void foo() {
try {
h.invoke(this, foo, new Object[0]);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
@Override
public int bar() {
try {
Object invoke = h.invoke(this, bar, new Object[0]);
return (int) invoke;
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
static public Method foo;
static public Method bar;
static {
try {
bar = Foo.class.getMethod("bar");
foo = Foo.class.getMethod("foo");
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
JDK反射调用会利用JVM中的ASM指令生成字节码,同时由于反射调用类方法是比较消耗性能的,在jdk中超过16次的反射调用jvm就会给他生成一个动态代理类来提供反射调用
cglib动态代理的实现原理
cglib动态代理是基于子类继承父类的代理
这是我们创建的代理类
public class Proxy extends Target {
private MethodInterceptor methodInterceptor;
public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
this.methodInterceptor = methodInterceptor;
}
static Method save0;
static Method save1;
static Method save2;
static {
try {
save0 = Target.class.getMethod("save");
save1 = Target.class.getMethod("save", int.class);
save2 = Target.class.getMethod("save", long.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
// >>>>>>>>>带增强功能的方法
@Override
public void save() {
try {
methodInterceptor.intercept(this, save0, new Object[0], save0Proxy);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
@Override
public void save(int i) {
try {
methodInterceptor.intercept(this, save1, new Object[]{i}, save1Proxy);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
@Override
public void save(long j) {
try {
methodInterceptor.intercept(this, save2, new Object[]{j}, save2Proxy);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
他继承了这个接口
public class Target {
public void save() {
System.out.println("save...");
}
public void save(int i){
System.out.println("save(int)");
}
public void save(long i){
System.out.println("save(long)");
}
}
调用
public class A13 {
public static void main(String[] args) {
Proxy proxy = new Proxy();
Target target = new Target();
proxy.setMethodInterceptor(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before");
// return method.invoke(target, objects);//反射调用
return methodProxy.invokeSuper(o, objects);
}
});
proxy.save();
proxy.save(1);
proxy.save(1L);
}
}
可以很直观的感觉到cglib不再需要通过接口来增强方法。同时cglib通过FastClass的两个实现来不需要通过反射来增强ProxyFastClass(代理类)和TargetFastClass(目标类),FastClass有两个重要的方法getIndex(获取代理类方法的编号)和invoke(调用原始方法)一个代理类只需要创建两个FastClass可以匹配多个方法,比jdk(一个方法对应一个类)产生数目少一些
public class TargetFastClass {
static Signature s0 = new Signature("save","()V");
static Signature s1 = new Signature("save","(I)V");
static Signature s2 = new Signature("save","(J)V");
//获取目标方法的编号
public int getIndex(Signature signature) {
if (s0.equals(signature)){
return 0;
} else if (s1.equals(signature)) {
return 1;
} else if (s2.equals(signature)) {
return 2;
} else {
throw new RuntimeException("without this parameter");
}
}
public Object invoke(int index,Object target,Object[] args) {
if (index == 0){
((Target) target).save();
return null;
} else if (index == 1) {
((Target) target).save((int) args[0]);
return null;
} else if (index == 2) {
((Target) target).save((long) args[0]);
return null;
} else {
throw new RuntimeException("without this parameter");
}
}
public static void main(String[] args) {
TargetFastClass targetFastClass = new TargetFastClass();
int index = targetFastClass.getIndex(new Signature("save", "()V"));
targetFastClass.invoke(index,new Target(),new Object[0]);
}
}
ublic class ProxyFastClass {
static Signature s0 = new Signature("saveSuper","()V");
static Signature s1 = new Signature("saveSuper","(I)V");
static Signature s2 = new Signature("saveSuper","(J)V");
//获取代理类方法的编号
public int getIndex(Signature signature) {
if (s0.equals(signature)){
return 0;
} else if (s1.equals(signature)) {
return 1;
} else if (s2.equals(signature)) {
return 2;
} else {
throw new RuntimeException("without this parameter");
}
}
public Object invoke(int index,Object proxy,Object[] args) {
if (index == 0){
((Proxy) proxy).saveSuper();
return null;
} else if (index == 1) {
((Proxy) proxy).saveSuper((int) args[0]);
return null;
} else if (index == 2) {
((Proxy) proxy).saveSuper((long) args[0]);
return null;
} else {
throw new RuntimeException("without this parameter");
}
}
public static void main(String[] args) {
ProxyFastClass proxyFastClass = new ProxyFastClass();
int index = proxyFastClass.getIndex(new Signature("saveSuper", "()V"));
System.out.println(index);
proxyFastClass.invoke(index,new Proxy(),new Object[0]);
}
}