Java的面向AOP编程

一、 引言

AOP(Aspect-Oriented Programming,面向切面的编程),是一种新型的编程范式,主张关注软件流程中的一个切面,将同样功能的代码整合打包在一起,降低系统的耦合性,增强其扩展性。

传统的软件设计,往往采取事件驱动模型带来类似的效果,通过在可能的事件切入点插入事件回调函数,将对应位置插入外置代码。

函数式编程,也有类似的解决方案,通过函数传递,将对应位置的扩展上新的功能。

Java作为一门严谨的传统式开发语言,以安全性和可靠性为第一标准,语言并没有过多的新特性支持,Java8仅支持到lambda表达式,为了使Java具有更强大的编程模型,Spring等框架使用gclib库实现了面向切面的编程模型。

二、 CGLIB 和 ASM

CGLIB 是一个强大的,高性能,高质量的Code生成类库,被广泛的用作动态代理技术。CGLIB 包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类,新的字节码可以被Java虚拟机直接加载运行。

其实动态代理并不是CGLIB的专利,早在JDK1.3版起,就引入了动态代理库,Spring AOP 编程时就可以进行选择,使用JDK提供的动态代理库,或者是引入CGLIB库。

下面举一个实例,来说明一些如何使用CGLIB库,将我们本来应该正常执行的函数调用,进行截断操作。

package com.abs.testcglib;

public class Service {
    String name;

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

    public void sayHello() {
        System.out.println("Hello "+name);
    }
}

首先,我们创建一个服务类,其中有一个sayHello() 方法,我们希望将这个方法截断,以添加其余组件的一些处理功能,例如持久化组件希望在此添加一条记录一类的功能。

package com.abs.testcglib;

public class Main {
    public static void main(String[] args) {
        Service s = new Service("Sxf");
        s.sayHello();
    }
}

在Main函数中调用一下,可以看的Hello Sxf 的输出。

但我们怎么截断呢?首先就要创建一个代理类,所谓代理,就是你让这个代理类,代你调用这个类的函数。

创建一个代理类:

package com.abs.testcglib;

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

import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("方法名:"+method.getName());
        Service a = (Service) o;
        a.name = "Wah";
        System.out.println("哈哈,我要改名");
        Object result = methodProxy.invokeSuper(o, args);
        return result;
    }
}

这个代理类的功能,就是将传统的Java直接的函数调用,包上一次外壳,因为Java本身的函数调用是系统完成的,很难由你大段他,但代理类不同,你可以明确的看的调用了哪个函数,并且可以根据这点,轻松的在函数调用前后,插入你希望插入的代码。

public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy)

这个函数大概是整个代理调用中最关键的一个函数了,o这个参数表示了该函数所在的对象,args是调用的参数,Method则是反射到的方法。最后一个则是代理的实例。

我们对函数的打断功能,则都在这个函数里实现。

当然,由于是通过代理实现,对象的构建也有所不同,所以我们自己写一个static函数作为构造函数使用。

package com.abs.testcglib;

import net.sf.cglib.proxy.Enhancer;

public class Service {
    String name;

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

    public void sayHello() {
        System.out.println("Hello "+name);
    }

    public static Service getProxyInstance(CglibProxy myProxy, String name) {
        Enhancer en = new Enhancer();
        // 设置父类和回调
        en.setSuperclass(Service.class);
        en.setCallback(myProxy);
        // 调用其构造函数,需要传入对应的Class列表和参数Object列表
        return (Service) en.create(new Class[] {String.class}, new Object[] {name});
    }
}

而Main函数中也应该这样使用该对象:

package com.abs.testcglib;

public class Main {
    public static void main(String[] args) {
        Service s = new Service("Sxf");
        s.sayHello();

        Service s2 = Service.getProxyInstance(new CglibProxy(), "Sxf");
        s2.sayHello();
    }
}

我们发现,两种方式创建出的对象,使用上几乎一样,唯一不同的就是构造函数时,我们进行了部分修改,其余部分,不影响我们的对象正常传递,存储等功能。

最终效果:

三、 Spring AOP 的实现

其实看来刚才CGLIB的实现,再看著名的Spring框架,就会发现两者的实现方式几乎完全一样,只不过Spring框架多增加了一些概念和功能。

下面我们写一个Target 类,这是一个被代理的目标对象,其中有一个execute()方法,现在使用 AOPexecute()方法做日志输出。在执行execute()方法前,做日志输出。

public class Target {
    public void execute(String name){
        System.out.println("executeMethod is here" + name);
    }
}

通知可以拦截目标对象的 execute()方法,并执行日志输出。创建通知的代码如下:

public class LoggerExecute implements MethodInterceptor {
    public Object invoke(MethodInvocation arg0) throws Throwable {
        before();
        arg0.proceed();
        return null;
    }
    private void before() {
        System.out.println("executeMethod is exe!");
    }
}

创建代理的方法也几乎一样:

public static void main(String[] args) {
    //创建目标对象
    Target target = new Target();
    //创建代理
    ProxyFactory di=new ProxyFactory();
    di.addAdvice(new BeforeExecute());
    di.setTarget(target);
    Target proxy=(Target)di.getProxy();
    //代理执行execute()方法
    proxy.execute(" ni hao");
}

当然Spring的切入点和其配置文件关联十分紧密,用Spring框架能够将系统的更多固定参数丢到配置文件中去,或者直接使用注解也可以。

时间: 2024-07-30 20:23:47

Java的面向AOP编程的相关文章

java中面向接口编程

面向接口编程详解(一)——思想基础 我想,对于各位使用面向对象编程语言的程序员来说,“接口”这个名词一定不陌生,但是不知各位有没有这样的疑惑:接口有什么用途?它和抽象类有什么区别?能不能用抽象类代替接口呢?而且,作为程序员,一定经常听到“面向接口编程”这个短语,那么它是什么意思?有什么思想内涵?和面向对象编程是什么关系?本文将一一解答这些疑问. 1.面向接口编程和面向对象编程是什么关系 首先,面向接口编程和面向对象编程并不是平级的,它并不是比面向对象编程更先进的一种独立的编程思想,而是附属于面向

JavaEE开发之Spring中的依赖注入与AOP编程

一.快速创建Mava管理的Spring工程 因为本篇博客是讨论关于Spring的东西,所以我们就不创建WebApp的工程了.我们使用Spring来快速的创建一个Maven管理的工程.如下所示找到File->New->Maven Project选项来创建一个新的Maven Project,具体如下所示: 下方我们选择创建一个简单的Maven工程,跳过模板的选择.上篇博客我们在创建Maven工程时,是没有选择下方这个选项的,然后我们选择了一个WebApp的模板.而本篇博客,我们不需要WebApp的

Java实战之03Spring-03Spring的核心之AOP(Aspect Oriented Programming 面向切面编程)

三.Spring的核心之AOP(Aspect Oriented Programming 面向切面编程) 1.AOP概念及原理 1.1.什么是AOP OOP:Object Oriented Programming面向对象编程 AOP:Aspect Oriented Programming面向切面编程 1.2.代理 充分理解:间接 主要作用:拦截被代理对象执行的方法,同时对方法进行增强. 1.2.1.静态代理 特点:代理类是一个真实存在的类.装饰者模式就是静态代理的一种体现形式. 1.2.2.动态代

Java 面向切面编程 AOP

本文内容 实例 引入 原始方法 装饰者模式 JDK 动态代理和 cglib 代理 直接使用 AOP 框架 下载 demo 实例 引入 package com.cap.aop;   public interface ICalculator { public double add(double num1, double num2) throws Exception;   public double sub(double num1, double num2) throws Exception;   p

java aop面向切面编程

最近一直在学java的spring boot,一直没有弄明白aop面向切面编程是什么意思.看到一篇文章写得很清楚,终于弄明白了,原来跟python的装饰器一样的效果.http://www.cnblogs.com/yanbincn/archive/2012/06/01/2530377.html Aspect Oriented Programming  面向切面编程.解耦是程序员编码开发过程中一直追求的.AOP也是为了解耦所诞生. 具体思想是:定义一个切面,在切面的纵向定义处理方法,处理完成之后,回

Java——面向切面编程,Spring中的AOP编程

面向切面编程 AOP思想:将横向重复代码,纵向抽取出来 AOP体现--Filter AOP体现--拦截器 AOP体现--动态代理 Spring中实现AOP思想 原理:Spring可以为容器中管理的对象生成代理对象 代理分为动态代理和cglib代理: 动态代理(优先) 被代理对象必须要实现接口,才能产生代理对象,如果没有接口将不能使用动态代理技术,换句话说,就是代理对象和被代理要实现同一接口 cglib代理 第三方代理技术,cglib代理,可以对任何类生成代理,代理的原理是对目标对象进行继承代理,

[Spring实战系列](16)面向切面编程(AOP)概述

1. 简介 在软件中,有些行为对于大多数应用都是通用的.日志,安全和事务管理的确很重要,但他们是都是应用对象主动参与的行为呢?如果让应用对象只关注自己所针对的业务领域问题,而其他方面的问题由其他应用对象来处理,这样会不会更好? 在软件开发中,分布于应用中多处的功能被称为横切关注点.通常,这些横切关注点从概念上是与应用的业务逻辑相分离的(但是往往直接嵌入到应用的业务逻辑中).将这些横切关注点与业务逻辑相分离是面向切面编程索要解决的. 上图展示了一个被划分为模块的典型应用.每个模块的核心功能都是为特

Spring框架——AOP(面向切面编程)详解

 1 AOP概述 ●AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传统 OOP(Object-Oriented Programming,面向对象编程)的补充. ●AOP编程操作的主要对象是切面(aspect),而切面模块化横切关注点. ●在应用AOP编程时,仍然需要定义公共功能,但可以明确的定义这个功能应用在哪里,以什么方式应用,并且不必修改受影响的类.这样一来横切关注点就被模块化到特殊的类里--这样的类我们通常称之为"切面".

Spring面向切面编程(AOP)

1 spring容器中bean特性 Spring容器的javabean对象默认是单例的. 通过在xml文件中,配置可以使用某些对象为多列. Spring容器中的javabean对象默认是立即加载(立即实例化:spring加载完成,立即创建对象) scope:属性 singleton:默认值为单例,默认也是立即加载,在加载完成spring容器的时候,bean对象已经创建完成 prototype:多例的,默认懒加载,spring容器加载完成的时候,不会创建bean的对象,只有从容器获得bean对象的