Java反射——Proxy和动态代理

我就是我 2023-07-02 04:25 65阅读 0赞

概述

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

动态代理

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

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

JDK

只能代理接口。

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

  1. public class JDKProxy implements InvocationHandler{
  2. //需要代理的目标对象
  3. private Object target;
  4. @Override
  5. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  6. System.out.println("动态代理开始");
  7. Object invoke = method.invoke(target, args);
  8. System.out.println("动态代理结束");
  9. return invoke;
  10. }
  11. /**
  12. * 获取代理对象
  13. * @param targetObject 目标对象
  14. * @return
  15. */
  16. private Object getJDKProxy(Object targetObject){
  17. this.target=targetObject;
  18. //JDK动态代理,只能针对实现了接口的类进行代理。
  19. return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this);
  20. }
  21. public static void main(String[] args) {
  22. JDKProxy jdkProxy=new JDKProxy();
  23. //获取代理对象
  24. AgencyService agencyService=(AgencyService)jdkProxy.getJDKProxy(new AgencyServiceImpl());
  25. //执行代理对象的方法
  26. agencyService.queryAgency(new AgencyInfo());
  27. }
  28. }

CGLIB

可以代理类。

  1. import com.family.model.AgencyInfo;
  2. import com.family.service.AgencyService;
  3. import com.family.service.impl.AgencyServiceImpl;
  4. import net.sf.cglib.proxy.Enhancer;
  5. import net.sf.cglib.proxy.MethodInterceptor;
  6. import net.sf.cglib.proxy.MethodProxy;
  7. import java.lang.reflect.Method;
  8. /**
  9. * @author
  10. * @description
  11. * @date Created in 下午6:42 2019/7/25
  12. */
  13. public class CGLIBProxy implements MethodInterceptor {
  14. private Object target;
  15. @Override
  16. public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
  17. System.out.println("CGLIB动态代理,开始");
  18. Object invoke=method.invoke(target,objects);
  19. System.out.println("CGLIB动态代理,结束");
  20. return invoke;
  21. }
  22. /**
  23. * 定义获取代理对象的方法
  24. * @param targetObject
  25. * @return
  26. */
  27. public Object getCglibProxy(Object targetObject){
  28. this.target=targetObject;
  29. //设置父类
  30. Enhancer enhancer=new Enhancer();
  31. enhancer.setSuperclass(targetObject.getClass());
  32. //设置回调
  33. enhancer.setCallback(this);
  34. //创建并返回代理对象
  35. Object result=enhancer.create();
  36. return result;
  37. }
  38. public static void main(String[] args) {
  39. CGLIBProxy cglibProxy=new CGLIBProxy();
  40. //获取代理对象
  41. AgencyService agencyService=(AgencyService)cglibProxy.getCglibProxy(new AgencyServiceImpl());
  42. agencyService.queryAgency(new AgencyInfo());
  43. }
  44. }

API

1.Proxy

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

针对接口创建代理类

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

  1. //根据传入的类加载器、代理的接口、invocationHandler返回动态代理类实例。
  2. public static Object newProxyInstance(ClassLoader loader,
  3. Class<?>[] interfaces,
  4. InvocationHandler h)
  5. throws IllegalArgumentException
  6. {
  7. Objects.requireNonNull(h);
  8. //克隆代理接口
  9. final Class<?>[] intfs = interfaces.clone();
  10. //校验代理类的访问权限
  11. final SecurityManager sm = System.getSecurityManager();
  12. if (sm != null) {
  13. checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
  14. }
  15. //获得代理类
  16. Class<?> cl = getProxyClass0(loader, intfs);
  17. /*
  18. * 调用指定invocation handler的构造器
  19. */
  20. try {
  21. if (sm != null) {
  22. checkNewProxyPermission(Reflection.getCallerClass(), cl);
  23. }
  24. //获取代理类的构造方法
  25. final Constructor<?> cons = cl.getConstructor(constructorParams);
  26. final InvocationHandler ih = h;
  27. if (!Modifier.isPublic(cl.getModifiers())) {
  28. AccessController.doPrivileged(new PrivilegedAction<Void>() {
  29. public Void run() {
  30. cons.setAccessible(true);
  31. return null;
  32. }
  33. });
  34. }
  35. //调用构造方法,创建实例
  36. return cons.newInstance(new Object[]{h});
  37. } catch (IllegalAccessException|InstantiationException e) {
  38. throw new InternalError(e.toString(), e);
  39. } catch (InvocationTargetException e) {
  40. Throwable t = e.getCause();
  41. if (t instanceof RuntimeException) {
  42. throw (RuntimeException) t;
  43. } else {
  44. throw new InternalError(t.toString(), t);
  45. }
  46. } catch (NoSuchMethodException e) {
  47. throw new InternalError(e.toString(), e);
  48. }
  49. }

2.InvocationHandler

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

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

  1. public interface InvocationHandler {
  2. public Object invoke(Object proxy, Method method, Object[] args)
  3. throws Throwable;
  4. }

3.MethodInterceptor

通用的回调,做拦截。

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

4.Enhancer

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

  1. public class Enhancer extends AbstractClassGenerator
  2. {
  3. //设置超类(生成类需要继承的类)
  4. public void setSuperclass(Class superclass) {
  5. if (superclass != null && superclass.isInterface()) {
  6. setInterfaces(new Class[]{ superclass });
  7. } else if (superclass != null && superclass.equals(Object.class)) {
  8. // affects choice of ClassLoader
  9. this.superclass = null;
  10. } else {
  11. this.superclass = superclass;
  12. }
  13. }
  14. //设置回调
  15. public void setCallback(final Callback callback) {
  16. setCallbacks(new Callback[]{ callback });
  17. }
  18. public void setCallbacks(Callback[] callbacks) {
  19. if (callbacks != null && callbacks.length == 0) {
  20. throw new IllegalArgumentException("Array cannot be empty");
  21. }
  22. this.callbacks = callbacks;
  23. }
  24. //获取/生成一个类
  25. public Object create() {
  26. classOnly = false;
  27. argumentTypes = null;
  28. return createHelper();
  29. }
  30. private Object createHelper() {
  31. preValidate();
  32. Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
  33. ReflectUtils.getNames(interfaces),
  34. filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
  35. callbackTypes,
  36. useFactory,
  37. interceptDuringConstruction,
  38. serialVersionUID);
  39. this.currentKey = key;
  40. Object result = super.create(key);
  41. return result;
  42. }
  43. }

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

  1. protected Object create(Object key) {
  2. try {
  3. ClassLoader loader = getClassLoader();
  4. Map<ClassLoader, ClassLoaderData> cache = CACHE;
  5. ClassLoaderData data = cache.get(loader);
  6. if (data == null) {
  7. synchronized (AbstractClassGenerator.class) {
  8. cache = CACHE;
  9. data = cache.get(loader);
  10. if (data == null) {
  11. Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
  12. data = new ClassLoaderData(loader);
  13. newCache.put(loader, data);
  14. CACHE = newCache;
  15. }
  16. }
  17. }
  18. this.key = key;
  19. Object obj = data.get(this, getUseCache());
  20. if (obj instanceof Class) {
  21. return firstInstance((Class) obj);
  22. }
  23. return nextInstance(obj);
  24. } catch (RuntimeException e) {
  25. throw e;
  26. } catch (Error e) {
  27. throw e;
  28. } catch (Exception e) {
  29. throw new CodeGenerationException(e);
  30. }
  31. }

小结

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

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

发表评论

表情:
评论列表 (有 0 条评论,65人围观)

还没有评论,来说两句吧...

相关阅读

    相关 java动态代理Proxy

    动态代理,实现了方法开闭原则,把实现类交给代理实现,把接口交给代理实现,把对象交给代理操作 代理代理的三种形态:接口,类,对象 三种代理实现方式: 接口: //

    相关 Java反射动态代理

    反射和动态代理放有一定的相关性,但单纯的说动态代理是由反射机制实现的,其实是不够全面不准确的,动态代理是一种功能行为,而它的实现方法有很多。要怎么理解以上这句话,请看下文。