^_^嗨一下
文章目录
  1. 1. 工具准备
  2. 2. 构建环境
  3. 3. 配置文件
  4. 4. 知识点总结:
    1. 4.1. 切面(Aspect)
    2. 4.2. 连接点(Joinpoint)
    3. 4.3. 通知(Advice)
    4. 4.4. 切入点(Pointcut)

如果你阅读了上一篇文章Spring的简单配置,相信你已经会搭建一个简单Spring IOC的框架了。那么说到IOC我们往往会联想到Spring AOP(面向切面编程),这次教程我们就来搭建一个简单的AOP框架,体验一下AOP的使用和好处。

为了清晰,我已经给出完整的搭建教程,本教程主要是用注解方式实现的,还有直接通过配置实现AOp的,这里就不详细讲解了,在后面直接给出源码。

工具准备

1:MyEclipse 10 + Jdk6.0 及以上

2:spring-framework-3.2.2.RELEASE-dist.zip + commons-logging-1.1.3.jar(Java日志实现) + 由于Spring3.2.2官方源代码中没有提供AOP,所以需要添加aopalliance-1.0.jar、aspectjrt.jar、aspectjweaver.jar

下载完整jar包

构建环境

1:在MyEclipse里面新建一个工程,并命名称是Spring3AOP2

2:把我提供的jar包放入项目的lib文件夹下。

配置文件

1: 编写业务类HelloServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.xhay1122.spring3.aop;
/**
* 项目名称:Spring3AOP
* 类名称:HelloServiceImpl
* 类描述: 目标对象
* 创建人:xhay
* 创建时间:2015-4-9 下午4:23:20
* 修改人:xhay
* 修改时间:2015-4-9 下午4:23:20
* 修改备注:
* @version 1.0
* 软件工程创新实验室
*/
public class HelloServiceImpl {
public String say(String _msg) {
System.out.println("HelloServiceImpl.say(msg:" + _msg + ")");
return _msg;
}
}

切面处理类TestAnnotationAspect.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package com.xhay1122.spring3.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class TestAnnotationAspect {
@Pointcut("execution(* com.xhay1122.spring3.aop.*.*(..))")
private void pointCutMethod() {
}
//声明前置通知
@Before("pointCutMethod()")
public void doBefore(JoinPoint jp) {
System.out.println("前置通知");
}
//声明后置通知
@AfterReturning(pointcut = "pointCutMethod()", returning = "result")
public void doAfterReturning(String result) {
System.out.println("后置通知");
System.out.println("---" + result + "---");
}
//声明例外通知
@AfterThrowing(pointcut = "pointCutMethod()", throwing = "e")
public void doAfterThrowing(Exception e) {
System.out.println("例外通知");
System.out.println(e.getMessage());
}
//声明最终通知
@After("pointCutMethod()")
public void doAfter(JoinPoint jp) {
System.out.println("最终通知");
}
//声明环绕通知
@Around("pointCutMethod()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("进入方法---环绕通知");
long time = System.currentTimeMillis();
Object o = pjp.proceed();
time = System.currentTimeMillis() - time;
System.out.println("执行: " + time + " ms");
System.out.println("退出方法---环绕通知");
return o;
}
}

2:在src目录下面创建一个Spring的配置文件applicationContext.xml,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?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:context="http://www.springframework.org/schema/context"
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.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
">
<aop:aspectj-autoproxy />
<!-- <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" /> -->
<bean id="aspectBean" class="com.xhay1122.spring3.aop.TestAnnotationAspect" />
<bean id="aService" class="com.xhay1122.spring3.aop.HelloServiceImpl"></bean>
</beans>

3: 编写测试代码AOPClient.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.xhay1122.spring3.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.xhay1122.spring3.aop.HelloServiceImpl;
public class AOPClient {
/**
* @Title: main
* @Description: TODO(这里用一句话描述这个方法的作用)
* @param @param args 描述
* @return void 返回类型
* 创建人:xhay
* 创建时间:2015-4-9 下午3:23:17
* 修改人:xhay
* 修改时间:2015-4-9 下午3:23:17
* 修改备注:
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
HelloServiceImpl a = (HelloServiceImpl)ctx.getBean("aService");
a.say("xhay1122.com");
}
}

到此为止,简单的spring框架就配置好了:
完整的目录结构

运行结果:通过结果我们可以看到在我们调用say方法前后,有通知的信息输出
运行结果

注解方式实现AOP源码

非注解方式实现AOP源码

知识点总结:

切面(Aspect)

官方的抽象定义为“一个关注点的模块化,这个关注点可能会横切多个对象”。“切面”在ApplicationContext中来配置。

连接点(Joinpoint)

程序执行过程中的某一行为,例如,HelloServiceImpl.say()的调用。

通知(Advice)

“切面”对于某个“连接点”所产生的动作。其中,一个“切面”可以包含多个“Advice”,例如TestAspect。Advice共有如下5种类型:

A 前置通知(Before advice):在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。xml中在里面使用元素进行声明;例如,TestAspect中的doBefore方法。注解中使用@Before声明;例如,TestAnnotationAspect中的doBefore方法。

B 后通知(After advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。xml中在里面使用元素进行声明。

C 返回后通知(After return advice):在某连接点正常完成后执行的通知,不包括抛出异常的情况。xml中在里面使用元素进行声明。注解中使用@AfterReturning声明;

D 环绕通知(Around advice):包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。xml中在里面使用元素进行声明。

E 抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。xml中在里面使用元素进行声明。

通知执行顺序:前置通知→环绕通知连接点之前→连接点执行→环绕通知连接点之后→返回通知→后通知→(如果发生异常)异常通知→后通知

切入点(Pointcut)

匹配连接点的断言,在AOP中通知和一个切入点表达式关联。示例中的所有通知所关注的连接点,都由切入点表达式execution( com.xhay1122.spring3.aop..*(..))来决定。

● 切入点表达式

execution:用于匹配方法执行的连接点;

within:用于匹配指定类型内的方法执行;

this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;注意this中使用的表达式必须是完整类名,不支持通配符;

target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;注意target中使用的表达式必须是完整类名,不支持通配符;

args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;参数类型列表中的参数必须是完整类名,通配符不支持;args属于动态切入点,这种切入点开销非常大,非特殊情况最好不要使用;

@within:用于匹配所以持有指定注解类型内的方法;注解类型也必须是完整类名;

@target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;注解类型也必须是完整类名;

@args:用于匹配当前执行的方法传入的参数持有指定注解的执行;注解类型也必须是完整类名;

@annotation:用于匹配当前执行方法持有指定注解的方法;注解类型也必须是完整类名;

bean:Spring AOP扩展的,AspectJ没有对于指示符,用于匹配特定名称的Bean对象的执行方法;

reference pointcut:表示引用其他命名切入点,只有注解风格支持,XML风格不支持。

文章目录
  1. 1. 工具准备
  2. 2. 构建环境
  3. 3. 配置文件
  4. 4. 知识点总结:
    1. 4.1. 切面(Aspect)
    2. 4.2. 连接点(Joinpoint)
    3. 4.3. 通知(Advice)
    4. 4.4. 切入点(Pointcut)