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

专业术语:

    1. Joinpoint(连接点): 所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
    2. Pointcut(切入点): 所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.
    3. Advice(通知/增强): 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
    4. Introduction(引介): 引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.
    5. Target(目标对象): 代理的目标对象
    6. Weaving(织入): 是指把增强应用到目标对象来创建新的代理对象的过程.
       spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入.
    7. Proxy(代理): 一个类被AOP织入增强后,就产生一个结果代理类Aspect(切面): 是切入点和通知(引介)的结合

动态代理:AOP的核心是java的动态代理技术,比它更简单。

看一个例子

一个类有几个简单的方法

 package com.atguigu.spring.aop.helloword;

 public class Calculator implements Calcul{

     public int add(int i,int j){
return i+j;
};
public int sub(int i,int j){
return i-j;
};
public int div(int i,int j){
return i/j;
};
public int mul(int i,int j){
return i*j;
};
}

如果要你给每个方法都加上日志,好在执行的时候知道调用了哪个方法、什么参数和什么结果,那就得这样

 package com.atguigu.spring.aop.helloword;

 public class Calculator implements Calcul{

     public int add(int i,int j){
System.out.println("The method add begins with: ["+i+","+j+"]");
System.out.println("The method add ends with: "+(i+j));
return i+j;
};
public int sub(int i,int j){
System.out.println("The method sub begins with: ["+i+","+j+"]");
System.out.println("The method sub ends with: "+(i-j));
return i-j;
};
public int div(int i,int j){
System.out.println("The method div begins with: ["+i+","+j+"]");
System.out.println("The method div ends with: "+i/j);
return i/j;
};
public int mul(int i,int j){
System.out.println("The method mul begins with: ["+i+","+j+"]");
System.out.println("The method mul ends with: "+i*j);
return i*j;
};
}

看每一个方法的日志,都是很规范的,很整齐的。但就是太麻烦了,太重复了。而且要改日志的格式,那就得一个一个的改,这样肯定不行。应该要把日志提取出来,让它重复使用。思想如下:

 package com.atguigu.spring.aop.helloword;

 public int Allmethod(Method method,int j,int j){
System.out.println("The method "+method+" begins with: ["+i+","+j+"]");
int result=method(i.j);
System.out.println("The method "+method+" ends with: "result); }

这样,代码就整洁多了,要改日志也只要改一次。其实这个例子不是很准确,好像是一种聚合式代理。学AOP,一定要先学动态代理

  推荐一个视频,讲动态代理原理:http://www.imooc.com/learn/214

  这个包含了学spring需要先学的各个知识:http://stamen.iteye.com/blog/1507535

AspectJ:java社区最完整最完善的AOP框架;

AspectJ支持的5种类型的通知注解:

  @Before:前置通知,在方法执行之前执行

  @After:后置通知,在方法执行之后执行

  @AfterRunning:返回通知,在方法返回结果后执行

  @AfterThrowing:异常通知,在方法抛出异常之后执行

  @Around:环绕通知,围绕着方法执行

Spring也有自身的AOP框架。可以使用基于AspectJ注解或基于XMl配置的AOP。

注解方式:

1、除spring基本jar包,额外需要加入jar包:aopalliance、aspectj.weaver、aop.RELRESE、aspects.RELEASE

2、配置自动扫描

     <!-- 自动扫描,加入IOC容器 -->
<context:component-scan base-package="com.atguigu.spring.aop.impl"></context:component-scan> <!-- 是Aspect注解起作用:自动为匹配的类生产代理对象 -->
<aop:aspect-autoproxy></aop:aspect-autoproxy>

3、创建接口和实现类

 package com.atguigu.spring.aop.impl;
//接口
public interface Calculator { public int add(int i,int j);
public int sub(int i,int j);
public int div(int i,int j);
public int mul(int i,int j);
}
 package com.atguigu.spring.aop.impl;
//实现类
import org.springframework.stereotype.Component;
//加入注解
@Component
public class CalculatorImpl implements Calculator{ public int add(int i,int j){
return i+j;
};
public int sub(int i,int j){
return i-j;
};
public int div(int i,int j){
return i/j;
};
public int mul(int i,int j){
return i*j;
}
}

创建日志切面:

 package com.atguigu.spring.aop.impl;

 import org.springframework.stereotype.Component;
import org.springframework.test.context.transaction.BeforeTransaction; //吧这个类申明为一个切面:要把该类放入到IOC容器、再声明为一个切面
@Aspect
@Component
public class LogginfAspect {
//声明该方法是一个前置通知,在目标方法开始前执行
//@Before("excution(修饰符 + 返回类型 + 类名,去参数名)")
@Before("excution(public int com.atguigu.spring.aop.impl.CalculatorImpl.add(int, int))");
public void befored(){
System.out.println("The method begins: ");
}
}

最后调用main方法

 public class Main {

     public static void main(String[] args) {

         ApplicationContext ctx=new ClassPathXmlApplicationContext("application.xml");
Calculator cal = (Calculator) ctx.getBean(Calculator.class);
int result=cal.add(3,6);
System.out.println("result: "+result);
} }

结果:

若要获取类名,参数等,在切面改就行:

 //吧这个类申明为一个切面:要把该类放入到IOC容器、再声明为一个切面
@Aspect
@Component
public class LogginfAspect {
//声明该方法是一个前置通知,在目标方法开始前执行
//@Before("excution(public + 全类名,去参数名)")
@Before("excution(public int com.atguigu.spring.aop.impl.CalculatorImpl.add(int, int))");
public void beforedMethod(JoinPoint joinPoint){
String methodName=joinPoint.getSignature().getName();
List<Object> args = Arrays.arrays(joinPoint.getArgs())
System.out.println("The method "+ methodName +"begins: "+args);
}
}

结果:

@Before("excution(public int com.atguigu.spring.aop.impl.CalculatorImpl.add(int, int))");

这句话,只是在add方法才有用,变成所有方法:把add改成*:

@Before("excution(public int com.atguigu.spring.aop.impl.CalculatorImpl.*(int, int))");

同样,还可以改成这样

@Before("excution(* int com.atguigu.spring.aop.impl.CalculatorImpl.*(int, int))");

@Before("excution(* com.atguigu.spring.aop.impl.CalculatorImpl.*(int, int))");(表示前面两个都是*)

注意:

  对于后置通知

  对于返回通知:

  对于异常通知:

  对于环绕通知,它的功能最强大,可以包含前面所以的通知,但并不意味着最常用

  注意:如果有多个切面,有默认的先后执行顺序。可以用@Order(num)定义优先级,num越小,优先级越高。

  注意:使用切入点,后面的切面就可以使用这个切点,写法更整洁。

如:前置通知写成:@Before("declareJointPointExpression()");

  后置通知写成:@After("declareJointPointExpression()");

  其他的同理。

再看一下笔记:

Spring学习记录(十二)---AOP理解和基于注解配置的更多相关文章

  1. 我的Spring学习记录(二)

    本篇就简单的说一下Bean的装配和AOP 本篇的项目是在上一篇我的Spring学习记录(一) 中项目的基础上进行开发的 1. 使用setter方法和构造方法装配Bean 1.1 前期准备 使用sett ...

  2. Spring学习记录(十四)---JDBC基本操作

    先看一些定义: 在Spring JDBC模块中,所有的类可以被分到四个单独的包:1.core即核心包,它包含了JDBC的核心功能.此包内有很多重要的类,包括:JdbcTemplate类.SimpleJ ...

  3. Spring学习记录(十)---使用FactoryBean配置Bean

    之前学了,配置bean可以用普通全类名配置.用工厂方法配置,FactoryBean又是什么呢 有时候配置bean要用到,IOC其他Bean,这时,用FactoryBean配置最合适. FactoryB ...

  4. HTTP协议学习---(十二)理解转发与重定向

    解释一 转发是服务器行为,重定向是客户端行为.为什么这样说呢,这就要看两个动作的工作流程: 转发过程:客户浏览器发送http请求---->web服务器接受此请求-->调用内部的一个方法在容 ...

  5. 我的Spring学习记录(四)

    虽然Spring管理这我们的Bean很方便,但是,我们需要使用xml配置大量的Bean信息,告诉Spring我们要干嘛,这还是挺烦的,毕竟当我们的Bean随之增多的话,xml的各种配置会让人很头疼. ...

  6. 我的Spring学习记录(五)

    在我的Spring学习记录(四)中使用了注解的方式对前面三篇做了总结.而这次,使用了用户登录及注册来对于本人前面四篇做一个应用案例,希望通过这个来对于我们的Spring的使用有一定的了解. 1. 程序 ...

  7. Spring学习记录(十三)---基于xml文件配置AOP

    上一篇讲了用注解配置AOP,现在讲用xml怎么配置AOP 其实逻辑是一样的,只是用xml的方法,要把这种逻辑写出来,告诉spring框架去执行. 例子:这里的例子和上一篇的例子一样.换成xml方式 / ...

  8. Spring Cloud(十二):分布式链路跟踪 Sleuth 与 Zipkin【Finchley 版】

    Spring Cloud(十二):分布式链路跟踪 Sleuth 与 Zipkin[Finchley 版]  发表于 2018-04-24 |  随着业务发展,系统拆分导致系统调用链路愈发复杂一个前端请 ...

  9. Lua和C++交互 学习记录之二:栈操作

    主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3  参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 1 ...

随机推荐

  1. sublime常用快捷键

    自己觉得比较实用的sublime快捷键: Ctrl + /  ---------------------注释 Ctrl + 滚动 --------------字体变大/缩小 Ctrl + N----- ...

  2. 使用CSS3实现一个3D相册

    CSS3系列我已经写过两篇文章,感兴趣的同学可以先看一下CSS3初体验之奇技淫巧,CSS3 3D立方体效果-transform也不过如此 第一篇主要列出了一些常用或经典的CSS3技巧和方法:第二篇是一 ...

  3. C#基础篇 - 正则表达式入门

    1.基本概念 正则表达式(Regular Expression)就是用事先定义好的一些特定字符(元字符)或普通字符.及这些字符的组合,组成一个“规则字符串”,这个“规则字符串”用来判断我们给定的字符串 ...

  4. Android混合开发之WebViewJavascriptBridge实现JS与java安全交互

    前言: 为了加快开发效率,目前公司一些功能使用H5开发,这里难免会用到Js与Java函数互相调用的问题,这个Android是提供了原生支持的,不过存在安全隐患,今天我们来学习一种安全方式来满足Js与j ...

  5. 掌握javascript中的最基础数据结构-----数组

    这是一篇<数据结构与算法javascript描述>的读书笔记.主要梳理了关于数组的知识.部分内容及源码来自原作. 书中第一章介绍了如何配置javascript运行环境:javascript ...

  6. 【腾讯Bugly干货分享】Android Linker 与 SO 加壳技术

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57e3a3bc42eb88da6d4be143 作者:王赛 1. 前言 Andr ...

  7. winform 窗体圆角设计

    网上看到的很多winform窗体圆角设计代码都比较累赘,这里分享一个少量代码就可以实现的圆角.主要运用了System.Drawing.Drawing2D. 效果图 代码如下. private void ...

  8. JavaScript基础学习-函数及作用域

    函数和作用域是JavaScript的重要组成部分,我们在使用JavaScript编写程序的过程中经常要用到这两部分内容,作为初学者,我经常有困惑,借助写此博文来巩固下之前学习的内容. (一)JavaS ...

  9. ABAP单元测试最佳实践

    本文包含了我在开发项目中经历过的实用的ABAP单元测试指导方针.我把它们安排成为问答的风格,欢迎任何人添加更多的Q&A's,以完成这个列表. 在我的项目中,只使用传统的ABAP report. ...

  10. Vim使用

    模式 ESC\Ctrl+c:退出编辑模式 ZZ\wq:命令模式下保存退出 编辑 i:进入编辑模式 I:转到行首非空字符开始编辑 s:删除当前字符进入编辑模式 a:从当前字符后开始编辑 A:从当前行末非 ...