程序员基本都知道有个模式叫代理模式,其实质就是调用由代理类发起,再由代理类来进行调用真实的业务类来调用,实现业务控制,在代理类的处理中,可以在真实的业务类调用前面和后面进行逻辑处理;
而动态代理跟普通的代理模式在代码编写上是有区别的,动态代理的代理类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方法里;这里贴下源码
@CallerSensitive 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); } //生成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缓存代理class private 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); }