📄 proxyfactory.java
字号:
/* * Javassist, a Java-bytecode translator toolkit. * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved. * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. Alternatively, the contents of this file may be used under * the terms of the GNU Lesser General Public License Version 2.1 or later. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. */package javassist.util.proxy;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Constructor;import java.lang.reflect.Member;import java.lang.reflect.Modifier;import java.security.ProtectionDomain;import java.util.HashMap;import java.util.WeakHashMap;import java.util.Iterator;import java.util.Map;import java.util.Set;import java.lang.ref.WeakReference;import javassist.CannotCompileException;import javassist.bytecode.*;/* * This class is implemented only with the lower-level API of Javassist. * This design decision is for maximizing performance. *//** * Factory of dynamic proxy classes. * * <p>This factory generates a class that extends the given super class and implements * the given interfaces. The calls of the methods inherited from the super class are * forwarded and then <code>invoke()</code> is called on the method handler * associated with the generated class. The calls of the methods from the interfaces * are also forwarded to the method handler. * * <p>For example, if the following code is executed, * * <ul><pre> * ProxyFactory f = new ProxyFactory(); * f.setSuperclass(Foo.class); * MethodHandler mi = new MethodHandler() { * public Object invoke(Object self, Method m, Method proceed, * Object[] args) throws Throwable { * System.out.println("Name: " + m.getName()); * return proceed.invoke(self, args); // execute the original method. * } * }; * f.setFilter(new MethodFilter() { * public boolean isHandled(Method m) { * // ignore finalize() * return !m.getName().equals("finalize"); * } * }); * Class c = f.createClass(); * Foo foo = (Foo)c.newInstance(); * ((ProxyObject)foo).setHandler(mi); * </pre></ul> * * <p>Then, the following method call will be forwarded to MethodHandler * <code>mi</code> and prints a message before executing the originally called method * <code>bar()</code> in <code>Foo</code>. * * <ul><pre> * foo.bar(); * </pre></ul> * * <p>The last three lines of the code shown above can be replaced with a call to * the helper method <code>create</code>, which generates a proxy class, instantiates * it, and sets the method handler of the instance: * * <ul><pre> * : * Foo foo = (Foo)f.create(new Class[0], new Object[0], mi); * </pre></ul> * * <p>To change the method handler during runtime, * execute the following code: * * <ul><pre> * MethodHandler mi2 = ... ; // another handler * ((ProxyObject)foo).setHandler(mi2); * </pre></ul> * * <p>You can also specify the default method handler: * * <ul><pre> * ProxyFactory f2 = new ProxyFactory(); * f2.setSuperclass(Foo.class); * f2.setHandler(mi); // set the default handler * Class c2 = f2.createClass(); * </pre></ul> * * <p>The default handler is implicitly attached to an instance of the generated class * <code>c2</code>. Calling <code>setHandler</code> on the instance is not necessary * unless another method handler must be attached to the instance. * * <p>The following code is an example of method handler. It does not execute * anything except invoking the original method: * * <ul><pre> * class SimpleHandler implements MethodHandler { * public Object invoke(Object self, Method m, * Method proceed, Object[] args) throws Exception { * return proceed.invoke(self, args); * } * } * </pre></ul> * * <p>A proxy object generated by <code>ProxyFactory</code> is serializable * if its super class or interfaces implement a <code>java.io.Serializable</code>. * However, a serialized proxy object will not be compatible with future releases. * The serialization support should be used for short-term storage or RMI. * * @see MethodHandler * @since 3.1 */public class ProxyFactory { private Class superClass; private Class[] interfaces; private MethodFilter methodFilter; private MethodHandler handler; private Class thisClass; /** * If the value of this variable is not null, the class file of * the generated proxy class is written under the directory specified * by this variable. For example, if the value is * <code>"."</code>, then the class file is written under the current * directory. This method is for debugging. * * <p>The default value is null. */ public String writeDirectory; private static final Class OBJECT_TYPE = Object.class; private static final String HOLDER = "_methods_"; private static final String HOLDER_TYPE = "[Ljava/lang/reflect/Method;"; private static final String METHOD_FILTER_FIELD = "_method_filter"; private static final String HANDLER = "handler"; private static final String NULL_INTERCEPTOR_HOLDER = "javassist.util.proxy.RuntimeSupport"; private static final String DEFAULT_INTERCEPTOR = "default_interceptor"; private static final String HANDLER_TYPE = 'L' + MethodHandler.class.getName().replace('.', '/') + ';'; private static final String HANDLER_SETTER = "setHandler"; private static final String HANDLER_SETTER_TYPE = "(" + HANDLER_TYPE + ")V"; /** * If true, a generated proxy class is cached and it will be reused * when generating the proxy class with the same properties is requested. * The default value is true. * * @since 3.4 */ public static boolean useCache = true; private static WeakHashMap proxyCache = new WeakHashMap(); static class CacheKey { String classes; MethodFilter filter; private int hash; WeakReference proxyClass; MethodHandler handler; public CacheKey(Class superClass, Class[] interfaces, MethodFilter f, MethodHandler h) { classes = getKey(superClass, interfaces); hash = classes.hashCode(); filter = f; handler = h; proxyClass = null; } public int hashCode() { return hash; } public boolean equals(Object obj) { if (obj instanceof CacheKey) { CacheKey target = (CacheKey)obj; return target.filter == filter && target.handler == handler && target.classes.equals(classes); } else return false; } static String getKey(Class superClass, Class[] interfaces) { StringBuffer sbuf = new StringBuffer(); if (superClass != null) sbuf.append(superClass.getName()); sbuf.append(':'); if (interfaces != null) { int len = interfaces.length; for (int i = 0; i < len; i++) sbuf.append(interfaces[i].getName()).append(','); } return sbuf.toString(); } } /** * Constructs a factory of proxy class. */ public ProxyFactory() { superClass = null; interfaces = null; methodFilter = null; handler = null; thisClass = null; writeDirectory = null; } /** * Sets the super class of a proxy class. */ public void setSuperclass(Class clazz) { superClass = clazz; } /** * Obtains the super class set by <code>setSuperclass()</code>. * * @since 3.4 */ public Class getSuperclass() { return superClass; } /** * Sets the interfaces of a proxy class. */ public void setInterfaces(Class[] ifs) { interfaces = ifs; } /** * Obtains the interfaces set by <code>setInterfaces</code>. * * @since 3.4 */ public Class[] getInterfaces() { return interfaces; } /** * Sets a filter that selects the methods that will be controlled by a handler. */ public void setFilter(MethodFilter mf) { methodFilter = mf; } /** * Generates a proxy class. */ public Class createClass() { if (thisClass == null) { ClassLoader cl = getClassLoader(); synchronized (proxyCache) { if (useCache) createClass2(cl); else createClass3(cl); } } return thisClass; } private void createClass2(ClassLoader cl) { CacheKey key = new CacheKey(superClass, interfaces, methodFilter, handler); /* * Excessive concurrency causes a large memory footprint and slows the * execution speed down (with JDK 1.5). Thus, we use a jumbo lock for * reducing concrrency. */ // synchronized (proxyCache) { HashMap cacheForTheLoader = (HashMap)proxyCache.get(cl); if (cacheForTheLoader == null) { cacheForTheLoader = new HashMap(); proxyCache.put(cl, cacheForTheLoader); cacheForTheLoader.put(key, key); } else { CacheKey found = (CacheKey)cacheForTheLoader.get(key); if (found == null) cacheForTheLoader.put(key, key); else { key = found; Class c = isValidEntry(key); // no need to synchronize if (c != null) { thisClass = c; return; } } } // } // synchronized (key) { Class c = isValidEntry(key); if (c == null) { createClass3(cl); key.proxyClass = new WeakReference(thisClass); } else thisClass = c; // } } private Class isValidEntry(CacheKey key) { WeakReference ref = key.proxyClass; if (ref != null) { Class c = (Class)ref.get(); if(c != null) return c; } return null; } private void createClass3(ClassLoader cl) { try { ClassFile cf = make(); if (writeDirectory != null) FactoryHelper.writeFile(cf, writeDirectory); thisClass = FactoryHelper.toClass(cf, cl, getDomain()); setField(DEFAULT_INTERCEPTOR, handler); setField(METHOD_FILTER_FIELD, methodFilter); } catch (CannotCompileException e) { throw new RuntimeException(e.getMessage(), e); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -