代理模式--静态代理--动态代理

╰+哭是因爲堅強的太久メ 2022-12-02 10:42 338阅读 0赞

在谈aop实现原理前,我们先说一下设计模式中的代理模式

1. 代理: 由代理类代理目标类执行目标类的方法。与装饰器模式的区别是 代理模式主要是控制对目标象的访问也可以增强对象的方法。但装饰器模式主要是对被装饰对象的扩展。

优点:

  1. 在执行目标对象创建及目标方法前后过程中 增加扩展代码 增加扩展性(aop切面)
  2. 决定对象的创建与方法的执行。智能化

2. 静态代理

  1. 提前创建代理对象
  1. 抽象接口(定义公共方法) 2 目标对象 3 代理对象
  2. 目标对象和代理对象都实现抽象接口。
  3. 代理对象掌握目标对象的引用

    // 抽象接口
    public interface Subject {

    1. String getName();

    }

    // 目标对象类
    public class RealSubject implements Subject {

    1. String name;
    2. public RealSubject(String name) {
    3. this.name = name;
    4. }
    5. public String getName() {
    6. return this.name;
    7. }

    }

    // 代理对象
    public class ProxySubject implements Subject {

    1. RealSubject realSubject;
    2. String name;
    3. public ProxySubject(String name) {
    4. this.name = name;
    5. }
    6. public String getName() {
    7. String result = null;
    8. System.out.println("目标方法执行前扩展");
    9. try {
    10. // 对象不存在创建对象。控制对象的访问
    11. if (realSubject == null) {
    12. realSubject = new RealSubject(this.name);
    13. }
    14. result = realSubject.getName();
    15. System.out.println("目标方法执行返回结果后执行扩展" + result);
    16. } catch (Exception e) {
    17. System.out.println("目标方法执行异常扩展");
    18. }
    19. System.out.println("目标方法执行后扩展");
    20. return result;
    21. }

    }
    // 执行

    1. public static void main(String[] a) {
    2. Subject subject = new ProxySubject("刘志强");
    3. System.out.println(subject.getName());
    4. }

缺点:每个类都要创建代理类 工作量大。

3. 动态代理

  1. 运行时由jdk通过反射机制创建代理对象(jdk代理)
  1. 编写动态代理处理类

    public class DynamicProxyHandler implements InvocationHandler {

    1. private Object object;
    2. public DynamicProxyHandler(final Object object) {
    3. this.object = object;
    4. }
  1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  2. Object result = null;
  3. System.out.println("目标方法执行前扩展");
  4. try {
  5. result = method.invoke(object, args);
  6. System.out.println("目标方法执行返回结果后执行扩展" + result);
  7. } catch (Exception e) {
  8. System.out.println("目标方法执行异常扩展");
  9. }
  10. System.out.println("目标方法执行后扩展");
  11. return result;
  12. }
  13. }
  1. 运行

    public static void main(String[] a) {

    1. Subject subject = new RealSubject("刘志强");
    2. subject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(), new
    3. Class[]{ Subject.class}, new DynamicProxyHandler(subject));
    4. System.out.println(subject.getName());
    5. }
  2. 优点: 不需要给每个目标类创建代理类

  3. 然后我们在看看newProxyInstance 是如何创建对象的

    public static Object newProxyInstance(ClassLoader loader,

    1. Class<?>[] interfaces,
    2. InvocationHandler h)
    3. throws IllegalArgumentException
    4. {
    5. Objects.requireNonNull(h);
    6. final Class<?>[] intfs = interfaces.clone();
    7. final SecurityManager sm = System.getSecurityManager();
    8. if (sm != null) {
    9. checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    10. }
    11. /* * 查找或生成指定的代理类。 */
    12. Class<?> cl = getProxyClass0(loader, intfs);
    13. /* * 使用指定的调用处理程序调用其构造函数。 */
    14. try {
    15. if (sm != null) {
    16. checkNewProxyPermission(Reflection.getCallerClass(), cl);
    17. }
    18. // 获取构造方法
    19. final Constructor<?> cons = cl.getConstructor(constructorParams);
    20. final InvocationHandler ih = h;
    21. if (!Modifier.isPublic(cl.getModifiers())) {
    22. AccessController.doPrivileged(new PrivilegedAction<Void>() {
    23. public Void run() {
    24. cons.setAccessible(true);
    25. return null;
    26. }
    27. });
    28. }
    29. // 创建实例
    30. return cons.newInstance(new Object[]{ h});
    31. } catch (IllegalAccessException|InstantiationException e) {
    32. throw new InternalError(e.toString(), e);
    33. } catch (InvocationTargetException e) {
    34. Throwable t = e.getCause();
    35. if (t instanceof RuntimeException) {
    36. throw (RuntimeException) t;
    37. } else {
    38. throw new InternalError(t.toString(), t);
    39. }
    40. } catch (NoSuchMethodException e) {
    41. throw new InternalError(e.toString(), e);
    42. }
    43. }

下面再说下JDKProxy和CGLIBProxy

  1. CGLIB代理的由来及介绍

    来自百度介绍
    JDK的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的继承的类,该怎么办?
    CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。
    CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。

aop是基于jdk代理和CGLIB代理实现的切面编程

发表评论

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

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

相关阅读