java AOP原理以及实例用法总结

AOP :

面向切面编程

在程序设计中,我们需要满足高耦合低内聚,所以编程需满足六大原则,一个法则.

AOP面向切面编程正是为了满足这些原则的一种编程思想.

一.装饰者模式:

当我们需要给对象增加功能时,为了满足单一职责原则,可利用装饰者模式编程,创建一个类用来装饰原来的类,这个类写需要在原来的功能上增加的功能.

比如:一个类里面有一个增加图书的功能,

@Service
public class BookSericeImpl implements BookSerice {
 @Override
 public void addOne(BokBean bokBean) {
  System.out.println("执行逻辑:插入一本书");
 }
 @Override
 public void deletOne(Long bookId) {
  System.out.println("执行逻辑:删除一本书");
 }
}

我们需要在这个基础上新增打印日志的功能,

public class BooklogServiceImpl implements BookSerice {
 private BookSerice bookSerice;
 public BooklogServiceImpl(BookSerice bookSerice) {
  this.bookSerice = bookSerice;
 }
 @Override
 public void addOne(BokBean bokBean) {

  System.out.println("准备新增一本书");
  this.bookSerice.addOne(bokBean);
  System.out.println("新增一本书完成");
 }
 @Override
 public void deletOne(Long bookId) {

  System.out.println("准备删除一本书");
  this.bookSerice.deletOne(323L);
  System.out.println("删除一本书完成");
 }
}

下面我们调用这个增强过后的的对象

public void test1(){

  //Aop :面向切面编程

  //使用装饰者模式设计对象
  BookSerice bookSerice = new BookSericeImpl();
  //把原来功能的对象通过构造方传给新增功能的类,并把新增功能类的对象赋给原来对象
  //这里新增功能类和原来的类都是实现了同一个接口.
  bookSerice = new BooklogServiceImpl(bookSerice);
  //调用新增功能类的方法,在这个方法里让构造方法传过去的对象调用原来的功能
  bookSerice.addOne(new BokBean());
 }

这样我们就在不改变原来代码的基础上新增了功能,并且也满足单一职责的原则,降低了代码的耦合性.

但是如果接口里面有很多方法,如果每个方法都需要增加日志功能,这样就会出现很多重复代码,并且装饰者模式不能同时为多个没有关系的类同时增强

所以java引入动态代理技术来增加功能.

二.动态代理

在java里动态代理有两个实现方式:

①针对有接口的类的代理,使用jdk中反射包下的动态代理

②针对没有接口的类的代理,使用第三方的jar包Enhancer

如果一个类既没有接口,又是final,那么不能进行增强

1.第一种实现:

基于接口的动态代理,使用java内部反射包增强

这种方式创建对象是目标对象的兄弟对象.

同样上面是实现了接口的两个功能的类:

@Service
public class BookSericeImpl implements BookSerice {
 @Override
 public void addOne(BokBean bokBean) {
  System.out.println("执行逻辑:插入一本书");
 }
 @Override
 public void deletOne(Long bookId) {
  System.out.println("执行逻辑:删除一本书");
 }
}

调用通过对象调用上面两个方法:

public void test2(){

 //创建需要代理的对象
 BookSerice bookSerice = new BookSericeImpl();
 //根据对象的类获取类加载器
 ClassLoader classLoader = bookSerice.getClass().getClassLoader();
 //获取被代理对象说实现的所有接口
 Class<?>[] interfaces = bookSerice.getClass().getInterfaces();
 //新建代理对象,里面参数需要(类加载器,一个对象所实现的接口,InvocationHandler接口类的对象)
 bookSerice = (BookSerice) Proxy.newProxyInstance(classLoader, interfaces, new LogHandler(bookSerice));
 bookSerice.addOne(new BokBean());
 bookSerice.deletOne(232L);
}

在创建代理对象的时候需要一个InvocationHandler接口类的对象,下面创建一个该类的实现类

public class LogHandler implements InvocationHandler {

 //通过构造方法接受一个没有被代理的原来的对象
 //通过下面的方法名的反射找到这个对象对应方法
 private Object target;
 public LogHandler(Object target) {
  this.target = target;
 }
 //当代理对象调用原方法的时候,就会调用这个invoke方法
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  String classname = target.getClass().getName();
  String methodName = method.getName();
  System.out.println(classname+"."+methodName+"方法开始执行");
  //这里实际是Method类通过方法名反射调用了原方法(addone)
  Object value = method.invoke(target, args);
  System.out.println(classname+"."+methodName+"方法执行完毕");
  return value;

 }
}

这样实现了动态代理之后,不管实现的接口里有多少个方法,你只需调用该方法,就会增强该方法,而不需要针对每个方法写一遍增强功能,

并且这个增强类LogHandler类和原来的实现类BookSericeImpl类并没有耦合性,这就是说不管你是什么接口类的实现类,只需要对该类的对象进行代理即可,就能对该类的方法添加上这个新增的功能

总的来说,这种动态代理实现方式就是利用反射技术,找到调用的方法名,针对这个方法进行增强.

如果当不需要对某方法增加功能时,就不用不带.

2.第二种实现:

基于类的动态代理,使用cglib框架.
这种方式创建的代理对象是目标对象的子类对象

第二种方式是利用第三方jar包来实现,下载CGLIB包:

利用jar包中的Enhancer类创建增强对象.

创建增强对象需要根据原对象的类名创建类增强器,还需要根据原对象的类型创建子类代理对象

属性通过增强对象set方法赋值,上一种方式是通过调用方法Proxy.newProxyInstance传参.

public void test3(){

  //创建需要代理增强的对象
  BookSerice bookSerice = new BookSericeImpl();
  Enhancer enhancer = new Enhancer();
  //用增强器对象创建类增强器
  enhancer.setClassLoader(bookSerice.getClass().getClassLoader());

  //因为创建的代理对象是目标对象的子类,所以这里填的就是目标对象的类
  enhancer.setSuperclass(bookSerice.getClass());

  //创建代理对象,这里需要的参数是Callback接口的对象,所以需要创建一个接口的实现类.
  enhancer.setCallback(new TimeMethodInterceptor(bookSerice));
  //把代理对象赋给原对象
  bookSerice = (BookSerice) enhancer.create();
  bookSerice.addOne(new BokBean());
  bookSerice.deletOne(1l);

 }

创建Callback接口的实现类,也就是功能增强部分,

这一部分跟第一种方式的实现是一样的,都是通过反射在添加功能过程中调用原方法.

//Callback接口没有实现方法,所以这里实现的是他的子接口
public class TimeMethodInterceptor implements MethodInterceptor {

 private Object target;

 public TimeMethodInterceptor(Object target) {
  this.target = target;
 }

 @Override
 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
  //记录当前系统时间
  //这个时间是从1970年1月1日 0点0分到现在的毫秒数
  long start = System.currentTimeMillis();
  Object value = method.invoke(target, objects);
  long time = System.currentTimeMillis() - start;
  System.out.println("当前时长"+time+"毫秒");
  return null;
 }
}

总结:

两种方法的区别:

第一种是用jdk内部方法创建代理对象,由于创建过程中需要一个对象的接口,所以只能针对有接口类的对象进行代理.

第二种是利用第三方jar包中的增强器(Enhancer)创建代理对象,通过set方法给需要的属性赋值.由于没有接口实现,所以创建的是对象的子类代理对象.

(0)

相关推荐

  • java Spring AOP详解及简单实例

    一.什么是AOP AOP(Aspect Oriented Programming)面向切面编程不同于OOP(Object Oriented Programming)面向对象编程,AOP是将程序的运行看成一个流程切面,其中可以在切面中的点嵌入程序. 举个例子,有一个People类,也有一个Servant仆人类,在People吃饭之前,Servant会准备饭,在People吃完饭之后,Servant会进行打扫,这就是典型的面向切面编程. 其流程图为: 二.Spring AOP实现: 1.People

  • Java JDK动态代理(AOP)的实现原理与使用详析

    本文主要给大家介绍了关于Java JDK动态代理(AOP)实现原理与使用的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍: 一.什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 代理模式UML图: 简单结构示意图: 为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别.通过代理类这中间一层,能有效控制对委托类对

  • 图解JAVA中Spring Aop作用

    假如没有aop,在做日志处理的时候,我们会在每个方法中添加日志处理,比如 但大多数的日子处理代码是相同的,为了实现代码复用,我们可能把日志处理抽离成一个新的方法.但是这样我们仍然必须手动插入这些方法. 但这样两个方法就是强耦合的,假如此时我们不需要这个功能了,或者想换成其他功能,那么就必须一个个修改. 通过动态代理,可以在指定位置执行对应流程.这样就可以将一些横向的功能抽离出来形成一个独立的模块,然后在指定位置 插入这些功能.这样的思想,被称为面向切面编程,亦即AOP. 为了在指定位置执行这些横

  • aop的实现原理_动力节点Java学院整理

    面向方面编程(Aspect Oriented Programming,简称AOP)是一种声明式编程(Declarative Programming).声明式编程是和命令式编程(Imperative Programming)相对的概念.我们平时使用的编程语言,比如C++.Java.Ruby.Python等,都属命令式编程.命令式编程的意思是,程序员需要一步步写清楚程序需要如何做什么(How to do What).声明式编程的意思是,程序员不需要一步步告诉程序如何做,只需要告诉程序在哪些地方做什么

  • 详解Java反射实现Aop代理

    利用反射生成JDK的动态代理,也就是AOP中的AOP代理,代替目标对象,从而在代码中织入增强. 定义代理接口 由于JDKf动态代理只能为接口创建动态代理,故先定义接口,假定我们需要对数据的Save方法添加事务处理,我们有一个UserDao接口,里面有一个Save方法,代码如下: public interface UserDao { public void save(); } 定义代理实现 下面具体来实现接口定义的Save方法,我们采用下面的代码来实现. public class UserDaoI

  • java基于spring注解AOP的异常处理的方法

    一.前言 项目刚刚开发的时候,并没有做好充足的准备.开发到一定程度的时候才会想到还有一些问题没有解决.就比如今天我要说的一个问题:异常的处理.写程序的时候一般都会通过try...catch...finally对异常进行处理,但是我们真的能在写程序的时候处理掉所有可能发生的异常吗? 以及发生异常的时候执行什么逻辑,返回什么提示信息,跳转到什么页面,这些都是要考虑到的. 二.基于@ControllerAdvice(加强的控制器)的异常处理 @ControllerAdvice注解内部使用@Except

  • Java核心库实现AOP过程

    这篇文章是关于Java的一个疑难杂症,通过利用Java核心库实现简单的AOP方法,并把实例代码做了分析对照,以下是全部内容: Spring是一个十分火热开源框架,而AOP(面向切面编程)则是Spring最重要的概念之一,为了更好的理解和学习AOP的思想,使用核心库来实现一次不失为一个好方法. 首先介绍一下AOP的概念,AOP(Aspect Oriented Programming),即面向切面编程,所谓的面向切面编程,就是从一个横切面的角度去设计代码的思想,传统的OOP思想是用封装继承和多态构造

  • java AOP原理以及实例用法总结

    AOP : 面向切面编程 在程序设计中,我们需要满足高耦合低内聚,所以编程需满足六大原则,一个法则. AOP面向切面编程正是为了满足这些原则的一种编程思想. 一.装饰者模式: 当我们需要给对象增加功能时,为了满足单一职责原则,可利用装饰者模式编程,创建一个类用来装饰原来的类,这个类写需要在原来的功能上增加的功能. 比如:一个类里面有一个增加图书的功能, @Service public class BookSericeImpl implements BookSerice { @Override p

  • Java HashMap原理及实例解析

    这篇文章主要介绍了Java HashMap原理及实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 示例 1 : HashMap的键值对 HashMap储存数据的方式是-- 键值对 package collection; import java.util.HashMap; public class TestCollection { public static void main(String[] args) { HashMap<String

  • Java Linkedlist原理及实例详解

    这篇文章主要介绍了Java Linkedlist原理及实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 定义:linkedlist属于链表结构,方便添加和删除元素,但查询不方便,适用于对收尾的操作. 具有具体的对象,使用对象调用具体的方法 add // 添加元素 //在中间添加元素 arr.add("H"); addFirst:在集合最前面添加元素 // 在链表头部添加元素 arr.addFirst("F")

  • java默认方法sqrt实例用法

    在接口中我们有许多方法可以实现,其中默认方法引起了大家的注意.每次想要实现类又不知道从何下手的小伙伴,除了可以使用抽象方法外,默认方法sqrt也是不错的选择.下面我们简单对一些方法进行介绍,然后带来具体的默认方法sqrt,在这之前我们先对其它方法进行简单的理解. 1.Java 8 允许我们使用default关键字,为接口声明添加非抽象的方法实现.这个特性又被称为扩展方法.下面是我们的第一个例子: interface Formula { double calculate(int a); defau

  • java SelectableChannel的使实例用法讲解

    1.说明 (1)SelectableChannel 是一个抽象类,它实现了 Channel 接口,这个类比较特殊. (2)SelectableChannel 可以被 Selector 用来多路复用,不过首先需要调用 selectableChannel.configureBlocking(false) 调整为非阻塞模式. 2.实例 SelectionKey register(Selector sel, int ops) SelectionKey register(Selector sel, int

  • java中gc算法实例用法

    在我们对gc中的算法有基本概念理解后,要把算法的理念实现还需要依托实际垃圾收集器的使用.因为光靠一些简单的原理不足以支撑整个程序的运行,在回收机制上有专门的收集器.下面我们就垃圾收集器的概念.使用注意事项.收集器图解进行介绍,然后带来两种常见的垃圾收集器供大家参考. 1.概念 垃圾收集器时之前列举的垃圾收集算法的具体实现. 2.注意事项 每一个回收器都存在Stop The World 的问题,只不过各个回收器在Stop The World 时间优化程度.算法的不同,可根据自身需求选择适合的回收器

  • java有界类型参数的实例用法

    java有界类型参数的使用 1.为了声明一个有界类型参数,列出类型参数的名称,然后是extends关键字,最后是它的上界. public class Box<T> { private T t; public void set(T t) { this.t = t; } public T get() { return t; } public <U extends Number> void inspect(U u){ System.out.println("T: "

  • Java内部类原理与用法实例总结

    本文实例讲述了Java内部类原理与用法.分享给大家供大家参考,具体如下: 一.非静态内部类 public class OutClass { private String name = "outclass"; public void show() { System.out.println(this.name); } public void innerShow() { InnerClass inner = new InnerClass(); inner.show(); inner.outS

  • Java 继承原理与用法实例分析

    本文实例讲述了Java 继承原理与用法.分享给大家供大家参考,具体如下: 继承的概念 继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类. 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为. 类的继承格式 在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下: class 父类 { } class 子类 extends 父类 { } 为什么需要继承 接下来

  • Java内部类原理、概述与用法实例详解

    本文实例讲述了Java内部类原理.概述与用法.分享给大家供大家参考,具体如下: 内部类的概述 /* 内部类概述: 把类定义在其他类的内部,这个类就被称为内部类. 举例:在类A中定义了一个类B,类B就是内部类. 内部的访问特点: A:内部类可以直接访问外部类的成员,包括私有. B:外部类要访问内部类的成员,必须创建对象. */ class Outer { private int num = 10; class Inner { public void show() { //内部类可以直接访问外部类的

随机推荐