Java实现AOP面向切面编程的实例教程_java

介绍

众所周知,AOP(面向切面编程)是Spring框架的特色功能之一。通过设置横切关注点(cross cutting concerns),AOP提供了极高的扩展性。那AOP在Spring中是怎样运作的呢?当你只能使用core java,却需要AOP技术时,这个问题的解答变得极为关键。不仅如此,在高级技术岗位的面试中,此类问题也常作为考题出现。这不,我的朋友最近参加了一个面试,就被问到了这样一个棘手的问题——如何在不使用Spring及相关库,只用core Java的条件下实现AOP。因此,我将在本文中提供一份大纲,帮助大家了解如何只用core Java实现一个AOP(当然啦,这种AOP在功能上有一定的局限性)。注意,本文不是一篇有关Spring AOP与Java AOP的对比研究,而是有关在core Java中借助固有的设计模式实现AOP的教程。

想必读者已经知道AOP是什么,也知道在Spring框架中如何使用它,因此本文只着眼于如何在不用Spring的前提下实现AOP。首先,我们得知道,Spring是借助了JDK proxy和CGlib两种技术实现AOP的。JDK dynamic proxy提供了一种灵活的方式来hook一个方法并执行指定的操作,但执行操作时得有一个限制条件:必须先提供一个相关的接口以及该接口的实现类。实践出真知,让我们透过一个案例来理解这句吧!现在有一个计算器程序,用于完成一些数学运算。让我们来考虑下除法功能,此时的问题是:如果core framework 已经具备了一份实现除法的代码,我们能否在代码执行时劫持(highjack)它并执行额外的校验呢?答案是肯定的,我将用下面提供的代码片段来证明这点。首先来看基础接口的代码:

public interface Calculator {
  public int calculate( int a , int b);
}

该接口实现类的代码如下:

public class CalculatorImpl implements Calculator {
  @Override
  public int calculate(int a, int b) {
    return a/b;
  }
}

假设我们既不能修该上面的代码,也不能对核心库进行任何改动,怎样才能完美地实现校验功能呢?不如试下JDK dynamic proxy的功能吧。

public class SomeHandler implements InvocationHandler {

// Code omitted for simplicity…..

  @Override
  public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
// Your complex business validation and logic
    Object result = method.invoke(targetObject ,params);
    return result;
  }

}

让我们通过测试类来看看由JDK dynamic proxy实现的校验功能的效果如何。

public static void main(String[] args) {
    CalculatorImpl calcImpl = new CalculatorImpl();
    Calculator proxied = (Calculator)ProxyFactory.getProxy (Calculator.class, calcImpl,
        new SomeHandler(calcImpl));
    int result = proxied.calculate(20, 10);
    System.out.println("FInal Result :::" + result);
  }

从结果可以看出,简单地实现功能强大的InvocationHandler接口,我们便能得到一个hooking implementation。按照JDK文档的描述,InvocationHandler接口是借助一个代理实例(proxy instance)来处理一个方法调用的。

现在我们已经知道,InvocationHandler的invoke()方法能够帮助我们解决问题。那么再来解决一个新问题——怎样才能在方法执行的前后执行操作呢?说的更具体一些,我们能通过添加多个aop(before、after、around)来hook一个方法吗(译注:原文为add multiple aops,但我认为Handler是充当Aspect的角色)?答案同样是肯定的。按照以下的步骤建立一个精简的代码模板便能满足这样的需求:

  • 创建一个抽象类,用于将aop应用于目标对象上。
  • 创建名为BeforeHandler 和 AfterHandler的两个aop。前者在方法执行之前工作,而后者则在方法执行结束后工作。
  • 创建一个代理类,使所有的aop handler和目标对象只需作为参数传入,就能创建一个hook。
  • 加入你自己的业务逻辑或者横切关注点。
  • 最后,通过传入相关的参数创建代理对象(proxy object)。

两种实现AOP的方式: 

1,JDK提供的动态代理实现  
接口 

public interface UserBean
{
  void getUser();
  void addUser();
  void updateUser();
  void deleteUser();
}

原始实现类 

public class UserBeanImpl implements UserBean
{
  private String user = null;
  public UserBeanImpl()
  {
  }
  public UserBeanImpl(String user)
  {
    this.user = user;
  }
  public String getUserName()
  {
    return user;
  }
  public void getUser()
  {
    System.out.println("this is getUser() method!");
  } 

  public void setUser(String user)
  {
    this.user = user;
    System.out.println("this is setUser() method!");
  }
  public void addUser()
  {
    System.out.println("this is addUser() method!");
  } 

  public void updateUser()
  {
    System.out.println("this is updateUser() method!");
  }
  public void deleteUser()
  {
    System.out.println("this is deleteUser() method!");
  }
}

代理类  

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.cignacmc.finance.bean.UserBeanImpl; 

public class UserBeanProxy implements InvocationHandler
{
  private Object targetObject; 

  public UserBeanProxy(Object targetObject)
  {
    this.targetObject = targetObject;
  } 

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
  {
    UserBeanImpl userBean = (UserBeanImpl) targetObject;
    String userName = userBean.getUserName();
    Object result = null; 

    //权限判断
    if(userName != null && !"".equals(userName))
    {
      result = method.invoke(targetObject, args);
    } 

    return result;
  }
}

 
测试类  

import java.lang.reflect.Proxy; 

import com.cignacmc.finance.bean.UserBean;
import com.cignacmc.finance.bean.UserBeanImpl;
import com.cignacmc.finance.proxy.UserBeanProxy; 

public class ProxyExe
{
  public static void main(String[] args)
  {
    System.out.println("Proved.............");
    UserBeanImpl targetObject = new UserBeanImpl("Bob Liang");
    UserBeanProxy proxy = new UserBeanProxy(targetObject);
    //生成代理对象
    UserBean object = (UserBean)Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
        targetObject.getClass().getInterfaces(), proxy);
    object.addUser(); 

    System.out.println("NO Proved.............");
    targetObject = new UserBeanImpl();
    proxy = new UserBeanProxy(targetObject);
    //生成代理对象
    object = (UserBean)Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
        targetObject.getClass().getInterfaces(), proxy);
    object.addUser(); 

  }
}

 
输出:  

Proved.............
this is addUser() method!
NO Proved.............

 
从上面这个例子可以成功拦截了调用的方法addUser()并对其做了相应的处理  
 

2, 通过cglib创建代理类

好处是不要求我们的目标对象实现接口 
原始类 

public class ClientBean
{
  private String name = null; 

  public ClientBean()
  { 

  } 

  public ClientBean(String name)
  {
    this.name = name;
  } 

  public void addClient()
  {
    System.out.println("this is addClient() method!");
  } 

  public void deleteClient()
  {
    System.out.println("this is deleteClient() method!");
  } 

  public void getClient()
  {
    System.out.println("this is getClient() method!");
  } 

  public void updateClient()
  {
    System.out.println("this is updateClient() method!");
  } 

  public String getClientName()
  {
    return name;
  } 

  public void setClientName(String name)
  {
    this.name = name;
  }
}

代理类 

import java.lang.reflect.Method; 

import com.cignacmc.finance.bean.ClientBean; 

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; 

public class CGLibProxy implements MethodInterceptor
{
  private Object targetObject; 

  public Object createProxyObject(Object targetObject)
  {
    this.targetObject = targetObject;
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(this.targetObject.getClass());
    enhancer.setCallback(this);
    return enhancer.create();
  } 

  public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable
  {
    ClientBean clientBean = (ClientBean)targetObject;
    String userName = clientBean.getClientName();
    Object result = null; 

    if(userName != null && !"".equals(userName))
    {
      result = method.invoke(targetObject, args);
    }
    return result;
  }
}

测试类  

import java.lang.reflect.Proxy; 

import com.cignacmc.finance.bean.ClientBean;
import com.cignacmc.finance.bean.UserBean;
import com.cignacmc.finance.bean.UserBeanImpl;
import com.cignacmc.finance.proxy.CGLibProxy;
import com.cignacmc.finance.proxy.UserBeanProxy; 

public class ProxyExe
{
  public static void main(String[] args)
  {
    System.out.println(".............CGLIB Proxy....................");
    System.out.println("Proved....................");
    CGLibProxy cproxy = new CGLibProxy();
    ClientBean clientBean = (ClientBean)cproxy.createProxyObject(new ClientBean("Bob Liang"));
    clientBean.addClient(); 

    System.out.println("NO Proved....................");
    cproxy = new CGLibProxy();
    clientBean = (ClientBean)cproxy.createProxyObject(new ClientBean());
    clientBean.addClient(); 

  }
}

 
输出: 

.............CGLIB Proxy....................
Proved....................
this is addClient() method!
NO Proved.................... 

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
aop
aop面向切面编程、面向切面编程aop例子、面向切面的编程 aop、aop切面编程实例、面向切面编程 实例,以便于您获取更多的相关知识。

时间: 2024-10-06 07:03:57

Java实现AOP面向切面编程的实例教程_java的相关文章

java基于AspectJ(面向切面编程)编码示例分享_java

一.基本概念 AspectJ是一种面向切面程序设计的基于Java 的实现.它向 Java 中加入了连接点(Join Point)这个新概念,其实它也只是现存的一个 Java概念的名称而已.它向 Java 语言中加入少许新结构:切点(pointcut).通知(Advice).类型间声明(Inter-type declaration)和方面(Aspect).切点和通知动态地影响程序流程,类型间声明则是静态的影响程序的类等级结构,而切面则是对所有这些新结构的封装. 基于切面.连接点.切点.通知的概念如

MVC AOP面向切面编程简单介绍及实例_java

MVC AOP面向切面编程 AOP这个词相信大家都没有接触太多过,但是实际上你们已经有所接触了,就在设计模式中.AOP所用的思想其实和设计模式是一样的,即在不修改原代码的情况下统一增加或者修改功能.还有,AOP大多用在spring里面,但是本文所写的只是在MVC中的应用,要注意. 一.简介         所谓AOP(Aspect Oriented Programming的缩写)意为面向切面的编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中

Guice框架-AOP(@面向切面编程)

2.AOP 面向切面编程 2.1 AOP入门 在前面的章节主要讲Guice的依赖注入,有了依赖注入的基础后我们再来看Guice的AOP.我们先从一个例子入手,深入浅出的去理解Guice的AOP的原理和实现. 首先我们定义服务Service,这个服务有一个简单的方法sayHello,当然了我们有一个服务的默认实现ServiceImpl,然后使用@ImplementedBy将服务和默认实现关联起来,同时将服务的实现标注为单例模式. 1 @ImplementedBy(ServiceImpl.class

spring aop面向切面编程:如何来做一个强大的日志记录功能

这个东西怎么做:spring aop 面向切面编程 如何来做一个强大的日志记录功能模板; 昨天经理把这个任务交给我,让我为公司现在的项目加上一个详细的日志记录功能模板,对所有的操作,至少是增删改运作进行一个记录,其要记录操作者,以及执行的方法,IP,以及操作的方法的参数. 我以前做过类似的功能,不过是在filter里做的,通过filter来检查action请求,记录请求中的参数及action名字.但是今天公司这个是要求用spring aop来做,这样就可以在spring里对要进行的日志记录方法进

Javascript aop(面向切面编程)之around(环绕)分析

  这篇文章主要介绍了Javascript aop(面向切面编程)之around(环绕) ,需要的朋友可以参考下 Aop又叫面向切面编程,其中"通知"是切面的具体实现,分为before(前置通知).after(后置通知).around(环绕通知),用过spring的同学肯定对它非常熟悉,而在js中,AOP是一个被严重忽视的技术点.但是利用aop可以有效的改善js代码逻辑,比如前端框架dojo和yui3中AOP则被提升至自定义事件的一种内在机制,在源码中随处可见.得益于这种抽象使得doj

yui3的AOP(面向切面编程)和OOP(面向对象编程)

  这篇文章主要介绍了yui3的AOP(面向切面编程)和OOP(面向对象编程),需要的朋友可以参考下 首先请把手放胸前成沉思状:我上了生活,还是被生活上了自己? 没想出答案把,恩,可以读下文了.从语义角度讲,同一事物的不同表述可以反映人的主观视角的不同,从哲学角度将,世界观影响方法论,我们看事物的角度不同,有时会得出截然相悖的结论,从而会影响我们的做事方式和行为准则,现实生活如此,在丰富多彩的编程语言中更是如此,编程模式充满了对现实世界的各种模拟,包括是面向过程,面向对象,还有面向切面.我们大概

Javascript aop(面向切面编程)之around(环绕)

Aop又叫面向切面编程,其中"通知"是切面的具体实现,分为before(前置通知).after(后置通知).around(环绕通知),用过spring的同学肯定对它非常熟悉,而在js中,AOP是一个被严重忽视的技术点.但是利用aop可以有效的改善js代码逻辑,比如前端框架dojo和yui3中AOP则被提升至自定义事件的一种内在机制,在源码中随处可见.得益于这种抽象使得dojo的自定义事件异常强大和灵活.dojo中aop的实现在dojo/aspect模块中,主要有三个方法:before.

yui3的AOP(面向切面编程)和OOP(面向对象编程)_YUI.Ext相关

首先请把手放胸前成沉思状:我上了生活,还是被生活上了自己? 没想出答案把,恩,可以读下文了.从语义角度讲,同一事物的不同表述可以反映人的主观视角的不同,从哲学角度将,世界观影响方法论,我们看事物的角度不同,有时会得出截然相悖的结论,从而会影响我们的做事方式和行为准则,现实生活如此,在丰富多彩的编程语言中更是如此,编程模式充满了对现实世界的各种模拟,包括是面向过程,面向对象,还有面向切面.我们大概已经非常熟悉面向过程和面向对象,切面的英文是Aspects(有时译作方面,我感觉用切面更能贴切的表达A

Javascript aop(面向切面编程)之around(环绕)分析_javascript技巧

Aop又叫面向切面编程,其中"通知"是切面的具体实现,分为before(前置通知).after(后置通知).around(环绕通知),用过spring的同学肯定对它非常熟悉,而在js中,AOP是一个被严重忽视的技术点.但是利用aop可以有效的改善js代码逻辑,比如前端框架dojo和yui3中AOP则被提升至自定义事件的一种内在机制,在源码中随处可见.得益于这种抽象使得dojo的自定义事件异常强大和灵活.dojo中aop的实现在dojo/aspect模块中,主要有三个方法:before.