原始代码的写法

既然要通过代码来演示,那必须要有例子,这里我的例子为:

有一个接口Dao有insert、delete、update三个方法,在insert与update被调用的前后,打印调用前的毫秒数与调用后的毫秒数

首先定义一个Dao接口:

public interface Dao {

    public void insert();

    public void delete();

    public void update();

}

然后定义一个实现类DaoImpl:
public class DaoImpl implements Dao {

    @Override
public void insert() {
System.out.println("DaoImpl.insert()");
} @Override
public void delete() {
System.out.println("DaoImpl.delete()");
} @Override
public void update() {
System.out.println("DaoImpl.update()");
} }
最原始的写法,我要在调用insert()与update()方法前后分别打印时间,就只能定义一个新的类包一层,在调用insert()方法与update()方法前后分别处理一下
,新的类我命名为ServiceImpl,其实现为:
public class ServiceImpl {

    private Dao dao = new DaoImpl();

    public void insert() {
System.out.println("insert()方法开始时间:" + System.currentTimeMillis());
dao.insert();
System.out.println("insert()方法结束时间:" + System.currentTimeMillis());
} public void delete() {
dao.delete();
} public void update() {
System.out.println("update()方法开始时间:" + System.currentTimeMillis());
dao.update();
System.out.println("update()方法结束时间:" + System.currentTimeMillis());
} }

这是最原始的写法,这种写法的缺点也是一目了然:

方法调用前后输出时间的逻辑无法复用,如果有别的地方要增加这段逻辑就得再写一遍
如果Dao有其它实现类,那么必须新增一个类去包装该实现类,这将导致类数量不断膨胀。

使用AOP

最后来看一下使用AOP的方式,首先定义一个时间处理类,我将它命名为TimeHandler:

public class TimeHandler {
  public void printTime(ProceedingJoinPoint pjp) {
Signature signature = pjp.getSignature();
if (signature instanceof MethodSignature) {
MethodSignature methodSignature = (MethodSignature)signature;
Method method = methodSignature.getMethod();
System.out.println(method.getName() + "()方法开始时间:" + System.currentTimeMillis());
      try {
pjp.proceed();
System.out.println(method.getName() + "()方法结束时间:" + System.currentTimeMillis());
} catch (Throwable e) {
        e.printStackTrace();
}
}
}
}
切面方法printTime本身可以不用定义任何的参数,但是有些场景下需要获取调用方法的类、方法签名等信息,此时可以
在printTime方法中定义JointPoint,Spring会自动将参数注入,可以通过JoinPoint获取调用方法的类、方法签名等信息
。由于这里我用的aop:around,要保证方法的调用,这样才能在方法调用前后输出时间,因此不能直接使用JoinPoint,
因为JoinPoint没法保证方法调用。此时可以使用ProceedingJoinPoint,ProceedingPointPoint的proceed()方法可以保
证方法调用,但是要注意一点,ProceedingJoinPoint只能和aop:around搭配,换句话说,如果aop.xml中配置的是aop:before,
然后printTime的方法参数又是ProceedingJoinPoint的话,Spring容器启动将报错。 接着看一下ApplicationContext.xml的配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
  <bean id="daoImpl" class="org.xrq.spring.action.aop.DaoImpl" />
   <bean id="timeHandler" class="org.xrq.spring.action.aop.TimeHandler" />
  <aop:config>
    <aop:pointcut id="addAllMethod" expression="execution(* org.xrq.spring.action.aop.Dao.*(..))" />
    <aop:aspect id="time" ref="timeHandler">
    <aop:before method="printTime" pointcut-ref="addAllMethod" />
    <aop:after method="printTime" pointcut-ref="addAllMethod" />
    </aop:aspect>
  </aop:config>
</beans> 测试代码很简单:
public class AopTest {

    @Test
@SuppressWarnings("resource")
public void testAop() {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring/aop.xml"); Dao dao = (Dao)ac.getBean("daoImpl");
dao.insert();
System.out.println("----------分割线----------");
dao.delete();
System.out.println("----------分割线----------");
dao.update();
} }
到此我总结一下使用AOP的几个优点:

  切面的内容可以复用,比如TimeHandler的printTime方法,任何地方需要打印方法执行前的时间与方法执行后的时间,都可以使用TimeHandler的printTime方法
避免使用Proxy、CGLIB生成代理,这方面的工作全部框架去实现,开发者可以专注于切面内容本身
代码与代码之间没有耦合,如果拦截的方法有变化修改配置文件即可。

 
 
 

使用AOP的好处的更多相关文章

  1. .Net中的AOP系列之构建一个汽车租赁应用

    返回<.Net中的AOP>系列学习总目录 本篇目录 开始一个新项目 没有AOP的生活 变更的代价 使用AOP重构 本系列的源码本人已托管于Coding上:点击查看. 本系列的实验环境:VS ...

  2. [原创]java WEB学习笔记105:Spring学习---AOP介绍,相关概念,使用AOP,利用 方法签名 编写 AspectJ 切入点表达式

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  3. C# AOP框架入门

    AOP面向切面编程(Aspect Oriented Programming),是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.Spring框架用的核心技术就是AOP,是函数式编程的一 ...

  4. Spring学习之AOP总结帖

    AOP(面向方面编程),也可称为面向切面编程,是一种编程范式,提供从另一个角度来考虑程序结构从而完善面向对象编程(OOP). 在进行 OOP 开发时,都是基于对组件(比如类)进行开发,然后对组件进行组 ...

  5. springMVC之AOP

    AOP(Aspect-Oriented Programming,面向切面编程) 切面(Aepect):横切关注点(跨越应用程序多个模块的功能)被模块化的对象: 通知(Advice):切面必须要完成的工 ...

  6. Spring学习(二)——Spring中的AOP的初步理解[转]

      [前面的话] Spring对我太重要了,做个关于web相关的项目都要使用Spring,每次去看Spring相关的知识,总是感觉一知半解,没有很好的系统去学习一下,现在抽点时间学习一下Spring. ...

  7. AOP和IOC理解

    在百度上看到一篇很有意思的文章,是对AOP的一种解释,如下:(摘自:百度文库的 AOP和IOC最容易理解的说明(Spring知识小计)): IOC,依赖倒置的意思, 所谓依赖,从程序的角度看,就是比如 ...

  8. spring(二) AOP之AspectJ框架的使用

    前面讲解了spring的特性之一,IOC(控制反转),因为有了IOC,所以我们都不需要自己new对象了,想要什么,spring就给什么.而今天要学习spring的第二个重点,AOP.一篇讲解不完,所以 ...

  9. JavaScript实现AOP(面向切面编程)

    什么是AOP? AOP(面向切面编程)的主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,这些跟业务逻辑无关的功能通常包括日志统计.安全控制.异常处理等.把这些功能抽离出来之后, 再通过" ...

随机推荐

  1. 洛谷 [P1314] 聪明的质检员(NOIP2011 D2T2)

    ###一道二分答案加前缀和### 题目中已经暗示的很明显了 "尽可能靠近" " 最小值" 本题的主要坑点在于 long long 的使用 ##abs函数不支持l ...

  2. HTTP面试题都在这里

    HTTP常见面试题 Http与Https的区别: Http与Https的区别: HTTP 的URL 以http:// 开头,而HTTPS 的URL 以https:// 开头 HTTP 是不安全的,而 ...

  3. 使用Docker link搭建PHP开发环境

    一般我们会把nginx.php都安装在同一个容器,为了扩展方便,我们希望nginx和php分开.那么就可以使用docker link命令实现这一目的. 需要的镜像: nginx 1.12.2 php( ...

  4. bzoj 3669: [Noi2014]魔法森林

    bzoj 3669: [Noi2014]魔法森林 Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号 ...

  5. fiddler 抓取 nodejs

      nodejs 代理指向 fiddler   var options = {       ........ }; options.path = 'http://' + options.host + ...

  6. Effective Java 第三版——33. 优先考虑类型安全的异构容器

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  7. ASP.NET Core的身份认证框架IdentityServer4--(1)服务配置

    官网文档地址:点我点我 准备 创建一个名为IdentityServer的ASP.NET Core Web Api 项目,端口5000 创建一个名为Api的ASP.NET Core Web Api 项目 ...

  8. WebView性能优化--独立进程

    Android允许一个app同时存在多个进程,可以根据需要把不同的模块放到不同进程中处理. 一.WebView独立进程的好处 1.有效增大App的运存,减少由webview引起的内存泄露对主进程内存的 ...

  9. 1.11 str 字符串

    字符串属于不可变序列,是 文本序列. 字符串的声明 >>> #字符串的声明既可以用单引号也可以用双引号,这两个能方法在效果上是一样的 >>> s = '' > ...

  10. 快速入门vue-cli配置

    作为一名使用了一段时间Vue.js的新手,相信和不少初入Vue的朋友一样,都对Vue-cli的配置一知半解.后来通过对webpack的学习,也算是对脚手架的配置有了一定的了解,所以也想把这段时间自己的 ...