zoukankan      html  css  js  c++  java
  • 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是什么呢?也正是我们要去切入的类。

    
    
  • 相关阅读:
    c++关于析构的那点小事(个人吐槽向
    我分析内存泄漏的一道作业题,已解决
    大一上学期的一点小疑惑,代码验证ok
    C++类型转换
    c++形参改变实参(对指针的理解
    c++整型->字符型转换
    [转]二重积分换元法的一种简单证明 (ps:里面的符号有点小错误,理解就好。。。
    c++实现矩阵类矩阵行列式,伴随矩阵,逆矩阵
    假期周计划2.0
    大道至简
  • 原文地址:https://www.cnblogs.com/sunshine798798/p/10049112.html
Copyright © 2011-2022 走看看