分析版本jdk1.8
在分析jdk动态代理之前,先来了解java WeakReference弱引用的使用。运行期创建目标对象的代理非常耗时,使用缓存来存储生成的代理类显得尤为重要。jdk动态代理使用弱引用指向cache中的代理类,以便代理类对象能够被GC回收。
在java中,当一个对象O被创建时,它被放在Heap里,当GC运行的时候,如果发现没有任何引用指向O,O就会被回收以腾出内存空间,或者说,一个对象被回收,必须满足两个条件:1)没有任何引用指向它;2)GC被运行。在现实情况写代码的时候, 我们往往通过把所有指向某个对象的referece置空来保证这个对象在下次GC运行的时候被回收 (可以用java -verbose:gc来观察gc的行为)。
- Object c = new Car();
- c=null;
但是, 也有特殊例外. 当使用cache的时候, 由于cache的对象正是程序运行需要的, 那么只要程序正在运行, cache中的引用就不会被GC给(或者说, cache中的reference拥有了和主程序一样的life cycle). 那么随着cache中的reference越来越多, GC无法回收的object也越来越多, 无法被自动回收. 当这些object需要被回收时, 回收这些object的任务只有交给程序编写者了. 然而这却违背了GC的本质(自动回收可以回收的objects).所以, java中引入了weak reference. 相对于前面举例中的strong reference:
- Object c = new Car(); //只要c还指向car object, car object就不会被回收
- WeakReference<Car> weakCar = new WeakReference(Car)(car);
当要获得weak reference引用的object时, 首先需要判断它是否已经被回收:
- weakCar.get();
- package weakreference;
- /**
- * @author ywchen
- */
- public class Car {
- private double price;
- private String colour;
- public Car(double price, String colour){
- this.price = price;
- this.colour = colour;
- }
- public double getPrice() {
- return price;
- }
- public void setPrice(double price) {
- this.price = price;
- }
- public String getColour() {
- return colour;
- }
- public void setColour(String colour) {
- this.colour = colour;
- }
- public String toString(){
- return colour +"car costs $"+price;
- }
- }
- package weakreference;
- import java.lang.ref.WeakReference;
- /**
- * @author ywchen
- */
- public class TestWeakReference {
- public static void main(String[] args) {
- Car car = new Car(22000,"silver");
- WeakReference<Car> weakCar = new WeakReference<Car>(car);
- int i=0;
- while(true){
- if(weakCar.get()!=null){
- i++;
- System.out.println("Object is alive for "+i+" loops - "+weakCar);
- }else{
- System.out.println("Object has been collected.");
- break;
- }
- }
- }
- }
ReferenceQueue
在weak reference指向的对象被回收后, weak reference本身其实也就没有用了. java提供了一个ReferenceQueue来保存这些所指向的对象已经被回收的reference. 用法是在定义WeakReference的时候将一个ReferenceQueue的对象作为参数传入构造函数.
jdk动态代理
面向对象编程(OOP)有一些弊端,为多个不具有继承关系的对象引入同一个公共行为,例如日志、安全监测等,需要在每个对象里引入公共行为,导致程序中产生大量重复代码。不便于维护。所以就有了一个面向对象编程的补充,即面向切面编程(AOP),AOP所关注的是横向,OOP关注的是纵向。AOP的实现,可采用JDK动态代理、CGLIB代理。
JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现来完成目标对象的代理。
CBLIB代理:实现原理类似于JDK动态代理,它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层依靠ASM(开源的字节码编辑类库)操作字节码实现,性能比JDK强。
jdk动态代理实现示例
1. 新建委托类
- /**
- * 目标对象实现的接口,用JDK来生成代理对象一定要实现一个接口
- * @author yawenchen
- * @since 2016-11-15
- *
- */
- public interface UserService {
- /**
- * 目标方法
- */
- public abstract void add();
- }
- /**
- * 目标对象
- * @author yawenchen
- * @since 2016-11-15
- *
- */
- public class UserServiceImpl implements UserService {
- /* (non-Javadoc)
- * @see dynamic.proxy.UserService#add()
- */
- public void add() {
- System.out.println("--------------------add---------------");
- }
- }
2. 实现InvocationHandlerj接口
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- /**
- * 实现自己的InvocationHandler
- * @author ywchen
- * @since 2016-11-15
- *
- */
- public class MyInvocationHandler implements InvocationHandler {
- // 目标对象
- private Object target;
- /**
- * 构造方法
- * @param target 目标对象
- */
- public MyInvocationHandler(Object target) {
- super();
- this.target = target;
- }
- /**
- * 执行目标对象的方法
- */
- 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;
- }
- /**
- * 获取目标对象的代理对象
- * @return 代理对象
- */
- public Object getProxy() {
- return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
- target.getClass().getInterfaces(), this);
- }
- }
public Object invoke(Object proxy, Method method, Object[] args)
参数说明:Proxy表示通过Proxy.newProxyInstance()生成的代理类对象。Method表示目标对象被调用的方法。Args表示目标对象被调用方法的输入参数。
3. 通过Proxy类静态函数生成代理对象
- public class ProxyTest {
- public static void main(String[] args) {
- //实例化目标对象
- UserService userService = new UserSericeImpl();
- //实例化InvocationHander
- MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
- //根据目标对象生成代理对象
- UserService proxy = (UserService)invocationHandler.getProxy();
- //调用代理对象的方法
- proxy.add();
- }
- }
执行结果
------------------before------------------
--------------------add---------------
-------------------after------------------
动态代理原理
- /**
- * loader :类加载器
- * interfaces:目标对象实现的接口
- * h:InvocationHandler的实现类
- */
- 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);
- }
- //调用代理对象的构造函数(代理对象的构造函数$Proxy0(InvocationHandler h),通过字节码反编译可以查看生成的代理类)
- 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;
- }
- });
- }
- //生成代理类的实例,并把MyInvocationHander的实例作为构造函数参数传入
- 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);
- }
- }
进到getProxyClass0方法
- 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为WeakCache的实例化对象,在Proxy类中定义,表示代理类的缓存。定义如下:
- private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
KeyFactory、ProxyClassFactory是WeakCache的内部静态类。实现了BiFunction接口。WeakCache实例化时作为构造函数参数传入,继承关系如下:
主要的代码如下:
- public interface BiFunction<T, U, R> {
- R apply(T t, U u);
- }
- 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.
- */
- //确保接口的类对象与类加载器加载的类对象相同,且由同一个加载器加载。《深入理解java虚拟机》提到,类加载器虽然只用于实现类的加载动作,但在java程序起的作用远不止于类的加载。对于任何一个类,都需要由加载它的的类加载器和这个类本身一同确立其在java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间,通俗点,比较两个类是否相等,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那这两个类就必定不相等。interfaceClass = Class.forName(intf.getName(), false, loader);验证类是否相等,实现原理如上所述。
- 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.非public修饰的代理接口,需要定义在相同的包中,如果非public修饰的接口不在相同包,会因访问权限的限制而无法访问。intf.getModifiers()返回的是一个整数,用不同的位开关表示接口中public/final修饰符的使用情况。
- */
- 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; //代理对象的包名,如com.aop
- } 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());
- }
- }
- }
- /**
- *映射接口数组到最后键的函数
- * 接口数组映射到最优键对象上(如实例化Key1时,接口作为Key1的构造函数参数,保存到Key1中), 同时,Key1/Key2/KeyX继承了WeakReference弱引用类类,因此接口所在的类对象被弱引用
- */
- private static final class KeyFactory
- implements BiFunction<ClassLoader, Class<?>[], Object>
- {
- @Override
- public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
- switch (interfaces.length) {
- case 1: return new Key1(interfaces[0]); // the most frequent
- case 2: return new Key2(interfaces[0], interfaces[1]);
- case 0: return key0;
- default: return new KeyX(interfaces);
- }
- }
- }
WeakCache类中定义的map变量如下:
- private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map = new ConcurrentHashMap<>();
双层map映射,第一层key为ClassLoader,第二层key为接口的弱引用对象,value为代理类的Class对象。怎么看出是弱引用的呢,value中存放的值是一个类,该类继承了弱引用类WeakReference,我们的代理类在对象实例化时,通过构造函数传入。为对象添加引用,可看WeakReference用法。
第一层是类加载器,第二层才是类对象,为什么不用一层,代理类对象作为键呢,这里就涉及到类加载器的使用。记住一点,类的唯一性是由类加载器和类本身共同决定的。
对Supplier接口,Factory类进行说明,接下来的代码中会用到。
调用proxyClassCache.get(loader, interfaces),进入WeakCache的get方法。代码如下:- public V get(K key, P parameter) {
- Objects.requireNonNull(parameter);
- expungeStaleEntries();
- //refQueue的类型为ReferenceQueue,存放对象的弱引用,CacheKey继承了WeakReference,因此key(ClassLoader)所在对象被弱引用,对象的应用存放在队列refQueue中。
- Object cacheKey = CacheKey.valueOf(key, refQueue);
- // lazily install the 2nd level valuesMap for the particular cacheKey
- //生成第一层key,从缓存中获取valuesMap,如果为空,则新建ConcurrentHashMap实例,把当前加载器和ConcurrentHashMap实例放到缓存中。
- ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
- if (valuesMap == null) {
- ConcurrentMap<Object, Supplier<V>> oldValuesMap
- = map.putIfAbsent(cacheKey,
- valuesMap = new ConcurrentHashMap<>());
- if (oldValuesMap != null) {
- valuesMap = oldValuesMap;
- }
- }
- // create subKey and retrieve the possible Supplier<V> stored by that
- // subKey from valuesMap
- //subKeyFactory是Proxy类的内部静态类KeyFactory的实例对象
- //valueFactory是Proxy类的内容静态类ProxyClassFactory的实例对象
- //subKeyFactory.apply(key, parameter)返回接口的弱引用对象。subKey,即接口的弱引用对象作为第二层映射的键
- Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
- Supplier<V> supplier = valuesMap.get(subKey);
- Factory factory = null;
- while (true) {
- if (supplier != null) {
- // supplier might be a Factory or a CacheValue<V> instance,supplier不为空,缓存中存在代理类
- V value = supplier.get();
- if (value != null) { //value不为空,即代理类存在,将代理类返回。
- return value;
- }
- }
- // else no supplier in cache
- // or a supplier that returned null (could be a cleared CacheValue
- // or a Factory that wasn't successful in installing the CacheValue)
- // lazily construct a Factory
- if (factory == null) {
- factory = new Factory(key, parameter, subKey, valuesMap);
- }
- if (supplier == null) {
- supplier = valuesMap.putIfAbsent(subKey, factory);
- if (supplier == null) {
- // successfully installed Factory
- supplier = factory;
- }
- // else retry with winning supplier
- } else {
- if (valuesMap.replace(subKey, supplier, factory)) {
- // successfully replaced
- // cleared CacheEntry / unsuccessful Factory
- // with our Factory
- supplier = factory;
- } else {
- // retry with current supplier
- supplier = valuesMap.get(subKey);
- }
- }
- }
- }
上面执行流程中,主要的两个步骤为:
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); subKey为接口对象的弱引用。 进入Proxy类的内部静态类KeyFactory,查看apply方法(本文前面提到的KeyFactory类)。
V value = supplier.get(); value为缓存中的代理类对象,Supplier是个接口,实现代码是在接口的实现类Factory中, 进入WeakCache类的内部类Factory,查看get方法。如下:Supplier是接口
- public interface Supplier<T> {
- /**
- * Gets a result.
- *
- * @return a result
- */
- T get();
- }
- }
- private final class Factory implements Supplier<V> {
- private final K key;
- private final P parameter;
- private final Object subKey;
- private final ConcurrentMap<Object, Supplier<V>> valuesMap;
- Factory(K key, P parameter, Object subKey,
- ConcurrentMap<Object, Supplier<V>> valuesMap) {
- this.key = key;
- this.parameter = parameter;
- this.subKey = subKey;
- this.valuesMap = valuesMap;
- }
- @Override
- public synchronized V get() { // serialize access
- // re-check
- Supplier<V> supplier = valuesMap.get(subKey);
- if (supplier != this) {
- // something changed while we were waiting:
- // might be that we were replaced by a CacheValue
- // or were removed because of failure ->
- // return null to signal WeakCache.get() to retry
- // the loop
- return null;
- }
- // else still us (supplier == this)
- // create new value
- V value = null;
- try {
- //valueFactory.apply(key, parameter) 返回代理类对象,即Class对象。
- //如果value不为空,说明缓存中已经存在代理类,可以直接返回。
- //通过前面的判断,已经能确定缓存中存在代理类,否则,程序是走不到这里来的。
- value = Objects.requireNonNull(valueFactory.apply(key, parameter));
- } finally {
- if (value == null) { // remove us on failure
- valuesMap.remove(subKey, this);
- }
- }
- // the only path to reach here is with non-null value
- assert value != null;
- // wrap value with CacheValue (WeakReference)
- CacheValue<V> cacheValue = new CacheValue<>(value);
- // try replacing us with CacheValue (this should always succeed)
- if (valuesMap.replace(subKey, this, cacheValue)) {
- // put also in reverseMap
- reverseMap.put(cacheValue, Boolean.TRUE);
- } else {
- throw new AssertionError("Should not reach here");
- }
- // successfully replaced us with new CacheValue -> return the value
- // wrapped by it
- return value;
- }
- }