• Java设计模式之代理模式☞再谈JDK的动态代理


    前言

    为什么要再谈,因为动态代理是aop编程的核心。后面分析spring aop的源代码的最重要的理论基础。

    再谈动态代理

    首先动态代理需要哪些角色呢?

    1.抽象角色。这个抽象角色必须为接口。

    2.具体角色。这个具体角色必须实现抽象接口。

    3.IAdvice接口和BeforeAdviceImple实现类。

    4.InvocationHandler的实现类。这个类为动态代理的Handler类。

    5.产生代理的接口,抽象类,工厂类。

    6.场景类Client。

    1.我们先新增一个抽象角色ISubject接口。这个接口定义一个方法handle。代码如下所示:

    1 package com.example.pattern.proxy.dynamic.second;
    2 
    3 public interface ISubject {
    4 
    5     public void handle();
    6 }

    第5行,定义接口handle。

    2.定义一个具体角色RealSubject。这个角色实现ISubject接口。代码如下所示:

    1 package com.example.pattern.proxy.dynamic.second;
    2 
    3 public class RealSubject implements ISubject {
    4     @Override
    5     public void handle() {
    6         System.out.println("-----handle-----");
    7     }
    8 }

    第6行,处理handle业务逻辑。

    3.新增一个通知事件的接口和实现类,代码如下所示。

    1 package com.example.pattern.proxy.dynamic.second;
    2 
    3 public interface IAdvice {
    4 
    5     public void execute();
    6 }
    1 package com.example.pattern.proxy.dynamic.second;
    2 
    3 public class BeforeAdviceImpl implements IAdvice {
    4     @Override
    5     public void execute() {
    6         System.out.println("执行前置通知");
    7     }
    8 }

     第6行,定义execute业务前置逻辑。

    4.再来新增一个InvocationHandler的默认处理器。

     1 package com.example.pattern.proxy.dynamic.second;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Method;
     5 
     6 public class DefaultInvocationHandler implements InvocationHandler {
     7 
     8     private Object instance = null;
     9 
    10     public DefaultInvocationHandler(Object instance) {
    11         this.instance = instance;
    12     }
    13 
    14     @Override
    15     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    16         return method.invoke(this.instance, args);
    17     }
    18 }

     第8行,定义被代理对象的实例。

    5.产生代理的接口,抽象类,实现类。

    1 package com.example.pattern.proxy.dynamic.second;
    2 
    3 import java.lang.reflect.InvocationHandler;
    4 
    5 public interface IDynamicProxy<T> {
    6 
    7     public <T> T newProxyInstace(Class<T> clazz, InvocationHandler h);
    8 
    9 }
    package com.example.pattern.proxy.dynamic.second;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    public abstract class AbstractDynamixProxy<T> implements IDynamicProxy<T> {
    
        public abstract void before() ;
    
        @Override
        public T newProxyInstace(Class clazz, InvocationHandler h) {
    
            this.before();
    
            ClassLoader classLoader = clazz.getClassLoader();
            Class[] interfaces = clazz.getInterfaces();
    
            return  (T)Proxy.newProxyInstance(classLoader, interfaces, h);
        }
    }
     1 package com.example.pattern.proxy.dynamic.second;
     2 
     3 public class SubjectDynamicProxyImpl<ISubject> extends AbstractDynamixProxy<ISubject>{
     4 
     5     @Override
     6     public void before() {
     7 
     8         IAdvice advice = new BeforeAdviceImpl();
     9         advice.execute();
    10 
    11     }
    12 }

    ①有接口,有抽象类,有具体方法?我为什么要这么设计呢?为什么不是直接写在场景类中呢?那如果有10个场景需要,是不是在10出都要写相同或者相似的代码呢?如果一旦有改动,那么,改动的工作量不说,容易产生潜伏性bug。 接口是声明主要用途,抽象类是用来提取公共代码。具体类是为了构建个性化代码,比如before方法。 就是一个典型的钩子函数。说了这么多,这难道不是模板模式的应用吗?

    ②IDynamicProxy<T>这是一个泛型接口。T可以是一个接口或者普通类,具体是什么类型,由场景来类决定,这不就实现了代码非常灵活的复用吗?同时不也是提高了可读性吗?

    6.增加场景类Client。

     1 public class Client {
     2 
     3     public static void main(String[] args) {
     4         ISubject subject = new RealSubject();
     5 
     6         InvocationHandler invocationHandler = new DefaultInvocationHandler(subject);
     7 
     8         IDynamicProxy<ISubject> dynamicProxy = new SubjectDynamicProxyImpl();
     9         ISubject proxyInstance = dynamicProxy.newProxyInstace(subject.getClass(), invocationHandler);
    10 
    11         proxyInstance.handle();
    12     }
    13 }

    执行的结果如下图所示:

    1 执行前置通知
    2 -----handle-----

    我们为什么要使用IAdvice呢。这已经引入了aop中的一些术语,在什么地方执行什么行为,是不是可以理解 在连接点执行什么通知呢?这已经是一个简单的面向切面过程的示例,Advice是什么呢?也正是我们要去切入的类。

    
    

  • 相关阅读:
    LeetCode 24. Swap Nodes in Pairs (两两交换链表中的节点)
    LeetCode 1041. Robot Bounded In Circle (困于环中的机器人)
    LeetCode 1037. Valid Boomerang (有效的回旋镖)
    LeetCode 1108. Defanging an IP Address (IP 地址无效化)
    LeetCode 704. Binary Search (二分查找)
    LeetCode 744. Find Smallest Letter Greater Than Target (寻找比目标字母大的最小字母)
    LeetCode 852. Peak Index in a Mountain Array (山脉数组的峰顶索引)
    LeetCode 817. Linked List Components (链表组件)
    LeetCode 1019. Next Greater Node In Linked List (链表中的下一个更大节点)
    29. Divide Two Integers
  • 原文地址:https://www.cnblogs.com/candies123/p/10049112.html
Copyright © 2020-2023  润新知