概述

上篇文章《Java反射——Class和ClassLoader 》,我们简单介绍了反射的基本概念及相关类。这里介绍下,反射的一个主要应用——动态代理。

动态代理

动态代理的实现,两种方式:JDK动态代理和CGLIB动态代理。
步骤都基本相同,获得代理类,执行调用方法进行方法增强。

代理模式类图如下:
在这里插入图片描述
此处Proxy代理了具体的对象(RealSubject),如果我们想让这种代理关系更普适,就引出了动态代理,即Proxy可以代理很多的对象,具体代理哪个对象在运行时才能确定。
Java中实现了这种方式,即JDK动态代理。

JDK

只能代理接口。

Proxy:通用的生成代理对象类,创建参数为InvocationHandler。
在这里插入图片描述

public class JDKProxy implements InvocationHandler{

    //需要代理的目标对象
    private Object target;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("动态代理开始");
        Object invoke = method.invoke(target, args);
        System.out.println("动态代理结束");
        return invoke;
    }

    /**
     * 获取代理对象
     * @param targetObject 目标对象
     * @return
     */
    private Object getJDKProxy(Object targetObject){
        this.target=targetObject;
        //JDK动态代理,只能针对实现了接口的类进行代理。
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this);
    }

    public static void main(String[] args) {
        JDKProxy jdkProxy=new JDKProxy();
        //获取代理对象
        AgencyService agencyService=(AgencyService)jdkProxy.getJDKProxy(new AgencyServiceImpl());
        //执行代理对象的方法
        agencyService.queryAgency(new AgencyInfo());

    }
}

CGLIB

可以代理类。


import com.family.model.AgencyInfo;
import com.family.service.AgencyService;
import com.family.service.impl.AgencyServiceImpl;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author 
 * @description
 * @date Created in 下午6:42 2019/7/25
 */
public class CGLIBProxy implements MethodInterceptor {

    private Object target;

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("CGLIB动态代理,开始");
        Object invoke=method.invoke(target,objects);
        System.out.println("CGLIB动态代理,结束");
        return invoke;
    }

    /**
     * 定义获取代理对象的方法
     * @param targetObject
     * @return
     */
    public Object getCglibProxy(Object targetObject){
        this.target=targetObject;
        //设置父类
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(targetObject.getClass());
        //设置回调
        enhancer.setCallback(this);
        //创建并返回代理对象
        Object result=enhancer.create();
        return result;
    }

    public static void main(String[] args) {
        CGLIBProxy cglibProxy=new CGLIBProxy();
        //获取代理对象
        AgencyService agencyService=(AgencyService)cglibProxy.getCglibProxy(new AgencyServiceImpl());
        agencyService.queryAgency(new AgencyInfo());
    }
}

API

1.Proxy

提供了创建动态代理类和示例的静态方法,也是所有动态代理类的超类。

针对接口创建代理类

动态代理类:(动态代理)类在被创建时,实现了一系列在运行时指定的接口。
代理接口:被代理类实现的接口。
代理实例:代理类的一个实例。

//根据传入的类加载器、代理的接口、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);
        }

        //获得代理类
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * 调用指定invocation handler的构造器
         */
        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);
        }
    }

2.InvocationHandler

作用:完成方法的拦截与代理。

当调用代理实例的方法时,下面的invoke()会被执行。
invoke()的参数说明:
proxy:代理实例
method:对应的接口方法
args:(在代理实例的方法调用中)传递的参数值的对象数组

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

3.MethodInterceptor

通用的回调,做拦截。

public interface MethodInterceptor
extends Callback
{
	 public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                               MethodProxy proxy) throws Throwable;
}

4.Enhancer

生成代理子类。动态生成的子类,会重写超类的非final方法,并且会有回调的钩子来实现用户自定义的拦截。

public class Enhancer extends AbstractClassGenerator
{
  //设置超类(生成类需要继承的类)
  public void setSuperclass(Class superclass) {
        if (superclass != null && superclass.isInterface()) {
            setInterfaces(new Class[]{ superclass });
        } else if (superclass != null && superclass.equals(Object.class)) {
            // affects choice of ClassLoader
            this.superclass = null;
        } else {
            this.superclass = superclass;
        }
    }
    //设置回调
     public void setCallback(final Callback callback) {
        setCallbacks(new Callback[]{ callback });
    }
    public void setCallbacks(Callback[] callbacks) {
        if (callbacks != null && callbacks.length == 0) {
            throw new IllegalArgumentException("Array cannot be empty");
        }
        this.callbacks = callbacks;
    }

	//获取/生成一个类
   public Object create() {
        classOnly = false;
        argumentTypes = null;
        return createHelper();
    }
      private Object createHelper() {
        preValidate();
        Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
                ReflectUtils.getNames(interfaces),
                filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
                callbackTypes,
                useFactory,
                interceptDuringConstruction,
                serialVersionUID);
        this.currentKey = key;
        Object result = super.create(key);
        return result;
    }
}

super.create(key)即AbstractClassGenerator中的create()

 protected Object create(Object key) {
        try {
            ClassLoader loader = getClassLoader();
            Map<ClassLoader, ClassLoaderData> cache = CACHE;
            ClassLoaderData data = cache.get(loader);
            if (data == null) {
                synchronized (AbstractClassGenerator.class) {
                    cache = CACHE;
                    data = cache.get(loader);
                    if (data == null) {
                        Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
                        data = new ClassLoaderData(loader);
                        newCache.put(loader, data);
                        CACHE = newCache;
                    }
                }
            }
            this.key = key;
            Object obj = data.get(this, getUseCache());
            if (obj instanceof Class) {
                return firstInstance((Class) obj);
            }
            return nextInstance(obj);
        } catch (RuntimeException e) {
            throw e;
        } catch (Error e) {
            throw e;
        } catch (Exception e) {
            throw new CodeGenerationException(e);
        }
    }

小结

动态代理,可以动态的对指定方法进行增强。动态代理的两种实现方式:JDK动态代理和CGLIB动态代理。

JDK动态代理只可以为接口去完成操作,采用的是反射机制,无需引入其他jar包。
CGLIB对指定的目标生成一个子类,并覆盖其中方法实现增强,采用的是继承。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐