一、AOP的术语
上篇博客介绍了AOP的由来,及使用aop的便利,在深入了解aop之前,我们当然得先了解一下其众多的概念性术语:
1、主术语
-
切面(Aspect)
一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。在Spring AOP中,切面可以使用基于模式或者基于@Aspect注解的方式来实现。
-
连接点(Joinpoint)
在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。
-
通知(Advice)
在切面的某个特定的连接点上执行的动作。其中包括了“around”、“before”和“after”等不同类型的通知(通知的类型将在后面部分进行讨论)。许多AOP框架(包括Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。
-
切入点(Pointcut)
匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。
-
引入(Introduction)
用来给一个类型声明额外的方法或属性(也被称为连接类型声明(inter-type declaration))。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用引入来使一个bean实现IsModified接口,以便简化缓存机制。
-
目标对象(Target Object)
被一个或者多个切面所通知的对象。也被称做被通知(advised)对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。
-
AOP代理(AOP Proxy)
AOP框架创建的对象,用来实现切面契约(例如通知方法执行等等)。在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
-
织入(Weaving)
把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
2、通知类型:
-
前置通知(Before advice)
在某连接点之前执行的通知,但这个通知不能阻止连接点之前的执行流程(除非它抛出一个异常)。
-
后置通知(After returning advice)
在某连接点正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
-
异常通知(After throwing advice)
在方法抛出异常退出时执行的通知。
-
最终通知(After (finally) advice)
当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
-
环绕通知(Around Advice)
包围一个连接点的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它自己的返回值或抛出异常来结束执行。
环绕通知是最常用的通知类型。和AspectJ一样,Spring提供所有类型的通知,推荐使用尽可能简单的通知类型来实现需要的功能。例如,如果你只是需要一个方法的返回值来更新缓存,最好使用后置通知而不是环绕通知,尽管环绕通知也能完成同样的事情。用最合适的通知类型可以使得编程模型变得简单,并且能够避免很多潜在的错误。比如,你不需要在JoinPoint
上调用用于环绕通知的proceed()
方法,就不会有调用的问题。
下面那Javaz中AOP举例:
二、代码演示
1、业务对象——要切入的目标
业务类跟有没有AOP没有多大关系,业务类是不知道AOP的存在的。
- <span style="font-size:18px;"><span style="font-family:SimSun;font-size:18px;">package com.jushi.aop;
-
- import java.util.HashMap;
- import java.util.Map;
-
- public class IUserImpl implements IUser {
-
- public static Map map = null;
- public static void init(){
- String[] list = {"Lucy", "Tom", "小明", "Smith", "Hello"};
- Map tmp = new HashMap();
- for(int i=0; i<list.length; i++){
- tmp.put(list[i], list[i]+"00");
- }
- map = tmp;
- }
- public void addUser(String username) {
- init();
- map.put(username, username+"11");
- System.out.println("--------------【addUser】: "+username+" --------------");
- System.out.println("【The new List:"+map+"】");
- }
-
- public void findAll() {
- init();
- System.out.println("---------------【findAll】: "+map+" ------------------");
- }
-
- public String findUser(String username) {
- init();
- String password = "没查到该用户";
- if(map.containsKey(username)){
- password = map.get(username).toString();
- }
- System.out.println("-----------------【findUser】-----------------");
- System.out.println("-----------------Username:"+username+"-----------------");
- System.out.println("-----------------【Result】:"+password+"------------------");
- return password;
-
- }
-
- }
- </span></span>
2、定义切面类:定义了切入服务,通知类型,切入点。
- <span style="font-size:18px;">public class CheckUser {
-
-
-
- @Pointcut("execution(* com.jushi.aop.*.find*(..))")
- public void checkUser(){
- System.out.println("**************The System is Searching Information For You****************");
- }
-
-
- @Pointcut("execution(* com.jushi.aop.*.add*(..))")
- public void checkAdd(){
- System.out.println("**************<< Add User >> Checking.....***************");
- }
-
- @Before("checkUser()")
- public void beforeCheck(){
- System.out.println(">>>>>>>> 准备搜查用户..........");
- }
-
- @After("checkUser()")
- public void afterCheck(){
- System.out.println(">>>>>>>> 搜查用户完毕..........");
- }
-
-
- @Before("checkAdd()")
- public void beforeAdd(){
- System.out.println(">>>>>>>> 增加用户--检查ing..........");
- }
-
-
- @After("checkAdd()")
- public void afterAdd(){
- System.out.println(">>>>>>>> 增加用户--检查完毕!未发现异常!..........");
- }
- }</span>
3、现在我们需要配置Spring的配置文件,告诉程序扫描AOP的注解。
- <span style="font-size:18px;">@Aspect
- <?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-2.5.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
-
- //声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面
- <aop:aspectj-autoproxy/>
- // 业务类
- <bean id="user" class="com.jushi.aop.IUserImpl"/>
- //切面类
- <bean id="check" class="com.jushi.aop.CheckUser"/>
- </beans></span>
至此,spring aop 的一个简单Demo 就实现了。