关于Java动态代理的一点想法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于Java动态代理的一点想法相关的知识,希望对你有一定的参考价值。
如有错误请指正
1. 动态代理的作用:
1. 虚拟机生成的动态代理对象可以轻松地对原有方法进行各种重写
2. 若没有动态代理,想实现重写,必须做一个继承基类的子类
2. 实例演示:
package com.didi.test;
public interface Person {
String skill();
String play();
}
package com.didi.test;
public class Programmer implements Person{
@Override
public String skill() {
System.out.println("coding-------------------------");
return "调用skill方法";
}
@Override
public String play() {
return null;
}
}
package com.didi.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
Programmer programmer;
public MyInvocationHandler(Programmer programmer) {
this.programmer = programmer;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before------------");
System.out.println(proxy.getClass().getName());
Object obj = method.invoke(programmer);
System.out.println("after----------------------");
if(!method.getName().equals("skill")){
return "调用娱乐方法";
}
return obj;
}
}
package com.didi.test;
import java.lang.reflect.Proxy;
public class ProxTest {
public static void main(String[] args) {
Programmer p = new Programmer();
Person programmerProxy = (Person)Proxy.newProxyInstance(
ProxTest.class.getClassLoader(),
p.getClass().getInterfaces(),
new MyInvocationHandler(p));
System.out.println("动态代理类的父类:" + programmerProxy.getClass().getSuperclass().getName());
String mes = programmerProxy.play();
System.out.println(mes);
}
}
控制台打印:
动态代理类的父类:java.lang.reflect.Proxy
before------------
com.sun.proxy.$Proxy0
after----------------------
调用娱乐方法
3. 底层实现原理
1. 如下源码:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
2. 源码解析
Proxy.newProxyInstance产生代理类对象,这个方法做了两件重要的事情,首先生成实现传入接口的实现类,然后通过反射创建对象,创建对象时传入一个参数,即我们自己实现的MyInvocationHandler
3. 具体运行情况
当运行代理对象的方法时,虚拟机做如下处理:
1.收集三个参数:代理对象的引用,当前调用方法的方法名,方法的参数
2.调用MyInvocationHandler的invoke方法,参数为上一步收集的参数
4. 实际应用
1. 日志,事务管理
2. 远程过程调用RPC,远程调用时,具体实现在服务端,这时我们在invoke中实现通信即可(调用方法时,让远端的方法被调用,将结果发挥即可),这一切都是通过invoke中的socket通信实现的
啰嗦一下:
通过动态代理可以轻松地对一个类进行方法增强,改造,自定义
以上是关于关于Java动态代理的一点想法的主要内容,如果未能解决你的问题,请参考以下文章