热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

详解使用Java原生代理实现AOP实例

一说到AOP,大家一定会想到spring,因为这东西实在是太强大了.但是大家一定要清楚,AOP是一只编程思想,而Spring仅仅是AOP的一

一说到AOP,大家一定会想到spring,因为这东西实在是太强大了.但是大家一定要清楚,AOP是一只编程思想,而Spring仅仅是AOP的一种实现罢了.

首先百度下:

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

今天呢,咱们就一起用Java原生代理实现简单的AOP功能.

首先,你得需要了解基本的反射知识,否则可能会感到困惑.

不罗嗦了,直接开始撸码

首先,咱们先写一个简单的接口.名字叫AnimalInterface,用来声明规范动物的一些基本方法.

这些方法包括 设置名字,获取名字,叫声,属性(原谅我没文化,其实就是获得是陆栖还是水栖或者水陆两栖)

package proxy.imp;
public interface AnimalInterface {
  //设置名字
  void setName(String name);
  //获取名字
  String getName();
  //叫声
  void say();
  //获取栖性
  void getProperty();
}

然后咱们实现这个接口,创建一个名叫小黑的Dog

package proxy;

import proxy.imp.AnimalInterface;
public class DogImp implements AnimalInterface {
  private String name = "小黑";
  public DogImp() {
  }
  @Override
  public void setName(String name) {
    this.name = name;
  }
  @Override
  public String getName() {
    return this.name;
  }
  @Override
  public void say() {
    System.out.println("小狗:汪汪汪汪.....");
  }
  @Override
  public void getProperty() {
    System.out.println("小狗是陆地动物,但是会游泳哦");
  }
}

大家一定迫不及待了,怎么实现类似AOP的功能呢….

咱们先创建一个名为AOPHandle的类,让其实现InvocationHandler接口,不能使用invoke时使用proxy作为反射参数时,因为代理对象的接口,不同于对象,这种代理机制是面向接口,而不是面向类的,如果使用proxy,会造成无限递归.然后就是栈溢出,但是依旧能反射成功一次,这说明代理对象和对象的代理是不一样的,但是咱们可以通过proxy参数的proxy.getClass()获得class对象,然后获得被代理类的方法和参数,这也为注解注入,特定方法注入,属性注入提供了一种实现途径吧,关于这个,咱们后面再说..

package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class AOPHandle implements InvocationHandler{
  //保存对象
  private Object o;
  public AOPHandle(Object o) {
    this.o=o;
  }
  /**
   * 这个方法会自动调用,Java动态代理机制
   * 会传入下面是个参数
   * @param Object proxy 代理对象的接口,不同于对象
   * @param Method method 被调用方法
   * @param Object[] args 方法参数
   * 不能使用invoke时使用proxy作为反射参数时,因为代理对象的接口,不同于对象
   * 这种代理机制是面向接口,而不是面向类的
   **/
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //方法返回值
    Object ret=null;
    //打印方法名称
    System.err.println("执行方法:"+method.getName()+"n参数类型为:");
    //打印参数
    for(Class type:method.getParameterTypes())
      System.err.println(type.getName());
    //打印返回类型
    System.err.println("返回数据类型:"+method.getReturnType().getName());
    //反射调用方法
    ret=method.invoke(o, args);
    //声明结束
    System.err.println("方法执行结束");
    //返回反射调用方法的返回值
    return ret;
  }
}

动态代理已经搞定..然后就是咱们的AnimalFactory了..咱们继续

package proxy;
import java.lang.reflect.Proxy;
public class AnimalFactory {
  /***
   * 获取对象方法
   * @param obj
   * @return
   */
  private static Object getAnimalBase(Object obj){
    //获取代理对象
    return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
        obj.getClass().getInterfaces(), new AOPHandle(obj));
  }
  /***
   * 获取对象方法
   * @param obj
   * @return
   */
  @SuppressWarnings("unchecked")
  public static T getAnimal(Object obj){
    return (T) getAnimalBase(obj);
  }
  /***
   * 获取对象方法
   * @param className
   * @return
   */
  @SuppressWarnings("unchecked")
  public static  T getAnimal(String className){
    Object obj=null;
    try {
      obj= getAnimalBase(Class.forName(className).newInstance());
    } catch (Exception e) {
      e.printStackTrace();
    }
    return (T)obj;
  }
  /***
   * 获取对象方法
   * @param clz
   * @return
   */
  @SuppressWarnings("unchecked")
  public static  T getAnimal(Class clz){
    Object obj=null;
    try {
      obj= getAnimalBase(clz.newInstance());
    } catch (Exception e) {
      e.printStackTrace();
    }
    return (T)obj;
  }
}

终于到最后了…还差什么呢,大家来这里看看效果吧…

哈哈…小二,上个菜..哦~不对,是个测试类..哈哈////

package proxy;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
import proxy.AnimalFactory;
import proxy.imp.AnimalInterface;

@RunWith(BlockJUnit4ClassRunner.class)
public class AOPTest {

  @Test
  public void Test1() {
    AnimalInterface dog=AnimalFactory.getAnimal(DogImp.class);
    dog.say();
    System.out.println("我的名字是"+dog.getName());
    dog.setName("二狗子");
    System.out.println("我的名字是"+dog.getName());
  }
}

啥?什么,,到了最后说,,这又卵用,这不是坑爹么?就捕获一个这个玩意,什么用啊…

什么AOP,我怎么一点AOP的影子都没有看到,怎么切入自定义方法,就一个syso输入,往这忽悠观众来了?…..

好吧,那咱们继续…看看如何实现注入自定义方法…

首先增加一个接口,咱们就称为AOP注入接口吧.取名AOPMethod哈

创建after和before方法,接收Object proxy, Method method, Object[] args参数

这样就能做更多的事情叻…比如执行方法前,记录类状态,写入log.监控xx变量,,,

开启你的脑洞吧.

package proxy.imp;
import java.lang.reflect.Method;

public interface AOPMethod{
  //实例方法执行前执行的方法
  void after(Object proxy, Method method, Object[] args);
  //实例方法执行后执行的方法
  void before(Object proxy, Method method, Object[] args);
}

然后修改AOPHandle类,增加AOPMethod属性.

在修改构造方法,让在类初始化时获得AOPMethod实例.

最后修改invoke方法….直接上代码哈

package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import proxy.imp.AOPMethod;

public class AOPHandle implements InvocationHandler{
  //保存对象
  private AOPMethod method;
  private Object o;
  public AOPHandle(Object o,AOPMethod method) {
    this.o=o;
    this.method=method;
  }
  /**
   * 这个方法会自动调用,Java动态代理机制
   * 会传入下面是个参数
   * @param Object proxy 代理对象的接口,不同于对象
   * @param Method method 被调用方法
   * @param Object[] args 方法参数
   * 不能使用invoke时使用proxy作为反射参数时,因为代理对象的接口,不同于对象
   * 这种代理机制是面向接口,而不是面向类的
   **/
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object ret=null;
    //修改的地方在这里哦
    this.method.before(proxy, method, args);
    ret=method.invoke(o, args);
    //修改的地方在这里哦
    this.method.after(proxy, method, args);
    return ret;
  }
}

呼呼,大功告成,,看起来一切都么问题,萌萌哒..

赶紧更新下测试类…

package proxy;

import java.lang.reflect.Method;

import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
import proxy.imp.AOPMethod;
import proxy.imp.AnimalInterface;

@RunWith(BlockJUnit4ClassRunner.class)
public class AOPTest {

  public static void main(String[] args) {

    AnimalInterface dog = AnimalFactory.getAnimal(DogImp.class, new AOPMethod() {
      // 这里写方法执行前的AOP切入方法
      public void before(Object proxy, Method method, Object[] args) {
        System.err.println("我在" + method.getName() + "方法执行前执行");
      }

      // 这里系方法执行后的AOP切入方法
      public void after(Object proxy, Method method, Object[] args) {
        System.err.println("我在 " + method.getName() + "方法执行后执行");

      }
    });
    dog.say();
    String name1="我的名字是" + dog.getName();
    System.out.println(name1);
    dog.setName("二狗子");
    String name2="我的名字是"+dog.getName();
    System.out.println(name2);
  }
}

呼呼,亲们,是不是有注入的感觉了?是不是感觉把自己的方法切进去了???哈哈….

看起来一切都已经完美了,但是总觉得差了点什么?哦,对,缺少了类似于Spring那么样的配置文件..

其实那些已经很简单了,交给你们去做吧,设计好XML格式化就妥了,等等,你说什么,还不能拦截自定义方法?

不能像Spring那样拦截自定义方法?oh~~NO,其实已经可以了在before(Object proxy, Method method, Object[] args)中利用method和的给methodName就能做判断了.

当然,本例的并没有什么实用意义,更不能个各种完善的AOP框架相比,本文仅仅为您提供一种思路,但是一定要记住,再牛的东西也是一点点积累出来的

实例下载:http://xiazai.jb51.net/201701/yuanma/JavaAOP_jb51.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 本文介绍了互联网思维中的三个段子,涵盖了餐饮行业、淘品牌和创业企业的案例。通过这些案例,探讨了互联网思维的九大分类和十九条法则。其中包括雕爷牛腩餐厅的成功经验,三只松鼠淘品牌的包装策略以及一家创业企业的销售额增长情况。这些案例展示了互联网思维在不同领域的应用和成功之道。 ... [详细]
  • Spring框架《一》简介
    Spring框架《一》1.Spring概述1.1简介1.2Spring模板二、IOC容器和Bean1.IOC和DI简介2.三种通过类型获取bean3.给bean的属性赋值3.1依赖 ... [详细]
  • Sleuth+zipkin链路追踪SpringCloud微服务的解决方案
    在庞大的微服务群中,随着业务扩展,微服务个数增多,系统调用链路复杂化。Sleuth+zipkin是解决SpringCloud微服务定位和追踪的方案。通过TraceId将不同服务调用的日志串联起来,实现请求链路跟踪。通过Feign调用和Request传递TraceId,将整个调用链路的服务日志归组合并,提供定位和追踪的功能。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • Kali Linux 简介
    KaliLinux是世界渗透测试行业公认的优秀的网络安全审计工具集合,它可以通过对设备的探测来审计其安全性,而且功能完备,几乎包含了目前所 ... [详细]
  • 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之六 || API项目整体搭建 6.1 仓储模式
    代码已上传Github+Gitee,文末有地址  书接上文:前几回文章中,我们花了三天的时间简单了解了下接口文档Swagger框架,已经完全解放了我们的以前的Word说明文档,并且可以在线进行调 ... [详细]
  • C#设计模式之八装饰模式(Decorator Pattern)【结构型】
    一、引言今天我们要讲【结构型】设计模式的第三个模式,该模式是【装饰模式】,英文名称:DecoratorPattern。我第一次看到这个名称想到的是另外一个词语“装修”,我就说说我对“装修”的理 ... [详细]
author-avatar
淑香门蒂
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有