Java动态代理
来源:互联网 发布:二次元手办淘宝 编辑:程序博客网 时间:2024/06/10 00:14
最近在看spring的aop源码时,用到了动态代理模式,仅记录用于方便理解动态代理。
先上代码
1.接口类
package com.cx.proxy;/** * Created by cumt_cx on 2017/1/3. */public interface HelloWorld { void SaySomeThing(String someThing);}
2.实现类
package com.cx.proxy;/** * Created by cumt_cx on 2017/1/3. */public class HelloWorldImpl implements HelloWorld { @Override public void SaySomeThing(String someThing) { System.out.println("Yes You Do ["+someThing+"]"); }}3.增强的横切逻辑:增强类,实现InvocationHandle接口
package com.cx.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;/** * Created by cumt_cx on 2017/1/3. */public class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object obj) { this.target = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("method :"+method.getName()+" is invoked"); return method.invoke(target,args); }}4.调用
package com.cx.proxy;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationHandler;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Proxy;/** * Created by cumt_cx on 2017/1/3. */public class ProxyDemo { public static void main(String args[]) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //one way Class<?> proxyClass = Proxy.getProxyClass(ProxyDemo.class.getClassLoader(), HelloWorld.class); final Constructor<?> cons = proxyClass.getConstructor(InvocationHandler.class); final InvocationHandler ih = new MyInvocationHandler(new HelloWorldImpl()); HelloWorld helloWorld = (HelloWorld) cons.newInstance(ih); helloWorld.SaySomeThing("This is invoke,I am Coding"); //other way HelloWorld helloWorld1 = (HelloWorld) Proxy .newProxyInstance(ProxyDemo.class.getClassLoader(), new Class<?>[] { HelloWorld.class }, new MyInvocationHandler (new HelloWorldImpl())); helloWorld1.SaySomeThing("This is invoke,Another Way ,I am Coding Too "); }}
JDK中具体的动态代理类是怎么产生
代理生成过程主要分为2步
- 代理类字节码生成
- 把字节码通过传入的类加载器加载到虚拟机中
具体细分则如下
获取动态代理类通过Proxy类的getProxyClass方法
@CallerSensitivepublic static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException{ final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } return getProxyClass0(loader, intfs);
代码直观的看到通过调用getProxyClass0方法
/** * Generate a proxy class. Must call the checkProxyAccess method * to perform permission checks before calling this. */private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // If the proxy class defined by the given loader implementing // the given interfaces exists, this will simply return the cached copy; // otherwise, it will create the proxy class via the ProxyClassFactory return proxyClassCache.get(loader, interfaces);}proxyClassCache的定义如下
/** * a cache of proxy classes */private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());实际是在ProxyClassFactory的apply方法中实现的
/** * A factory function that generates, defines and returns the proxy class given * the ClassLoader and array of interfaces. */private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>>{ // prefix for all proxy class names private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ Class<?> interfaceClass = null; try { interfaceClass = Class.forName(intf.getName(), false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != intf) { throw new IllegalArgumentException( intf + " is not visible from class loader"); } /* * Verify that the Class object actually represents an * interface. */ if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } /* * Verify that this interface is not a duplicate. */ if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; // package to define proxy class in int accessFlags = Modifier.PUBLIC | Modifier.FINAL; /* * Record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non-public proxy interfaces are in the same package. */ for (Class<?> intf : interfaces) { int flags = intf.getModifiers(); if (!Modifier.isPublic(flags)) { accessFlags = Modifier.FINAL; String name = intf.getName(); int n = name.lastIndexOf('.'); String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); if (proxyPkg == null) { proxyPkg = pkg; } else if (!pkg.equals(proxyPkg)) { throw new IllegalArgumentException( "non-public interfaces from different packages"); } } } if (proxyPkg == null) { // if no non-public proxy interfaces, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } /* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { /* * A ClassFormatError here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). */ throw new IllegalArgumentException(e.toString()); } }}
最后把字节码通过传入的类加载器加载到JVM中: defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
至此,已经生成了动态代理类,具体每个代理方法:逻辑都差不多就是 h.invoke,主要是调用我们定义好的invocatinoHandler逻辑,触发目标对象target上对应的方法;
0 0
- Java 代理,动态代理
- [Java] Java 动态代理
- java代理及动态代理
- java代理模式--动态代理
- Java静态代理、动态代理
- Java 代理之 动态代理
- Java 代理与动态代理
- java静态代理,动态代理
- 代理模式&java动态代理
- Java代理与动态代理
- Java静态代理动态代理
- JAVA代理模式--动态代理
- java 代理和动态代理
- JAVA动态代理 代理模式
- Java动态代理--jdk代理
- Java动态代理--cglib代理
- Java 代理与动态代理
- java代理模式-动态代理
- 祝你好运
- WebService工作原理 与 性能测试结论
- (HDU 5927)Auxiliary Set 思维题 <2016CCPC东北地区大学生程序设计竞赛 - 重现赛 >
- 架构师到底该不该写代码
- 查看mysql语句运行时间
- Java动态代理
- ldr和ldr伪指令
- OpenGL ES 3.0 Programming Guide(second edition)针对中文版翻译的补充——第一章
- 中间缓存变量机制
- Activity的生命周期和启动模式
- linux停止正在执行脚本
- Java中wait与notify的正确使用
- 使用异步 I/O 大大提高应用程序的性能《转载》
- Linux上C语言的自我学习一(文件编程-操作篇)