动态代理源码解析之JDK
来源:互联网 发布:怎么能开淘宝店铺 编辑:程序博客网 时间:2024/05/17 09:16
程序员基本都知道有个模式叫代理模式,其实质就是调用由代理类发起,再由代理类来进行调用真实的业务类来调用,实现业务控制,在代理类的处理中,可以在真实的业务类调用前面和后面进行逻辑处理;
而动态代理跟普通的代理模式在代码编写上是有区别的,动态代理的代理类class是动态生成的;
动态代理的应用场景很广,最被人熟知的当属spring的AOP,AOP的应用场景非常广泛,比如权限控制,缓存等等
动态代理的实现有:jdk动态代理和cglib动态代理,本篇博文尝试从源码角度来看看jdk动态代理是怎么实现的
先来看看jdk动态代理怎么用,上代码
UserService
public interface UserService { void add();}
UserServiceImpl
public class UserServiceImpl implements UserService { @Override public void add() { System.out.println("add"); }}
MyInvocationHandler
public class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { super(); this.target = target; } public Object getProxy() { return Proxy.newProxyInstance(Thread.currentThread() .getContextClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("----- before -----"); Object result = method.invoke(target, args); System.out.println("----- after -----"); return result; }}
Test
public class Test { public static void main(String[] args) { UserService userService = new UserServiceImpl(); MyInvocationHandler invocationHandler = new MyInvocationHandler( userService); UserService proxy = (UserService) invocationHandler.getProxy(); proxy.add(); }}
main方法执行结果
----- before -----add----- after -----
jdk动态代理代理类需要实现
java.lang.reflect.InvocationHandler
接口,从包名可以看出,jdk动态代理应该是用反射来实现的
看看代码
- 在main方法中new了一个实现类来赋值给接口,而不是直接定义实现类,最重要的原因是jdk动态代理只支持接口的动态代理,被代理的类都必须要有接口
- 动态代理的入口是getProxy()方法,getProxy()方法实现为:newProxyInstance,接受参数:
(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
;这里的ClassLoader为当前线程上下文的ClassLoader,interfaces为被代理类的所有接口数组 看到这里,想必jdk动态代理的核心逻辑就在这个newProxyInstance方法里;这里贴下源码
@CallerSensitivepublic 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); } //生成class的核心逻辑 Class<?> cl = getProxyClass0(loader, intfs); // 生成完以后,那就是根据生成的class来产生代理实例 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); }}
- 这里小小吐槽下,jdk源码也用很多简写,个人不大推崇这种写法,比如:intfs
- 再看getProxyClass0方法,用到的WeakCache后面专门写文章讲解,这里知道是用来做缓存的就行
//采用WeakCache缓存代理classprivate static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } //get方法先去缓存查找,如果没找到那么用ProxyClassFactory来生成 //再进入get方法看,第一行代码就是Objects.requireNonNull(interfaces); //从这里看出jdk动态代理中被代理的类必须实现接口 return proxyClassCache.get(loader, interfaces);}
未完(时间关系后续补)
阅读全文
1 0
- 动态代理源码解析之JDK
- JDK动态代理源码解析
- jdk动态代理源码解析
- jdk的动态代理源码解析
- JDK动态代理(源码解析)
- Java--JDK动态代理核心源码解析
- aop源码解析辅助-jdk动态代理
- JDK动态代理源码例子解析
- JDK动态代理源码分析之二
- jdk动态代理解析
- JDK动态代理解析
- java动态代理Proxy源码解析(Jdk 1.6)
- 基于jdk动态代理的实现与源码解析
- 动态代理之JDK
- 动态代理源码解析
- jdk动态代理源码学习
- JDK动态代理源码Proxy
- JDK动态代理源码分析
- Kill Process
- [PAT-乙级]1035.插入与归并
- swift——复合类型——函数——函数类型
- 数据挖掘十大算法
- C++ 函数
- 动态代理源码解析之JDK
- Java8 实战学习 — Lambda 表达式
- redhat5.5 安装 glibc2.18 步骤及问题小结
- js中substring()与substr()方法的区别
- Hibernate(五):Hibernate映射——一对一单向关联映射
- 欢迎使用CSDN-markdown编辑器
- 仿照JAVA vector模型写一个SuperArray
- 1115: 数字统计
- C++作业6