AOP全称是Aspect Oriented Programing,通常译为面向切面编程。利用AOP可以对面向对象编程做很好补充。
项目中遇到的实际运用到的切面编程是某系统日志模块,在原有的某些怎删改查功能已经完成的情况,需要添加对这些功能的操作日志监控共功能,这时候在原来的代码上再去一个一个添加操作记录的功能,显然会很繁琐,接下来就根据实际的功能记录下Spring AOP的运用
@Order(10)
@Aspect
@Component
public class AuditAspect {
public AuditAspect() {
// TODO Auto-generated constructor stub
}
@Pointcut("execution(public String cn.tiankuan.gcf.controller.*.add*(..))")
public void addPointcut() {
}
@Pointcut("execution(public String cn.xx.gcf.controller.*.update*(..))")
public void updatePointcut() {
}
@Pointcut("execution(public String cn.xx.gcf.controller.*.delete*(..))")
public void deletePointcut() {
}
@Pointcut("execution(public String cn.xx.gcf.controller.*.*Pwd(..))")
public void pwdPointcut() {
}
@Pointcut("execution(public void cn.xx.gcf.controller.*.*login(..))")
public void testPointcut(){
}
@After("addPointcut() || updatePointcut() || deletePointcut() || pwdPointcut() || testPointcut()")
public void addAadvice(JoinPoint joinPoint) {
System.out.println("============ 切面 测试 方法执行"+joinPoint.getSignature().getName()+"-"
+joinPoint.getSignature().getDeclaringTypeName()+"-"
+joinPoint.getSignature().getModifiers()+"-"
+joinPoint.getSignature().getDeclaringType()+"-");
System.out.println();
Object[] paramValues = joinPoint.getArgs();
String[] paramNames = ((CodeSignature) joinPoint.getSignature()).getParameterNames();
for(int i=0;i<paramNames.length;i++){
System.out.println(paramNames[i]+","+paramValues[i]);
}
}
@Before("testPointcut()")
public void aspectTest(JoinPoint joinPoint){
System.out.println("============ 切面 前测试 方法执行"+joinPoint.getSignature().getName());
}
}
关于aop的一些基础概念如下,转载于:http://blog.csdn.net/u013782203/article/details/51799427点击打开链接
- 通知、增强处理(Advice) 就是你想要的功能,也就是上说的安全、事物、日子等。你给先定义好,然后再想用的地方用一下。包含Aspect的一段处理代码
- 连接点(JoinPoint) 这个就更好解释了,就是spring允许你是通知(Advice)的地方,那可就真多了,基本每个方法的钱、后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点。其他如AspectJ还可以让你在构造器或属性注入时都行,不过那不是咱们关注的,只要记住,和方法有关的前前后后都是连接点。
- 切入点(Pointcut) 上面说的连接点的基础上,来定义切入点,你的一个类里,有15个方法,那就有十几个连接点了对吧,但是你并不想在所有方法附件都使用通知(使用叫织入,下面再说),你只是想让其中几个,在调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切入点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法。
- 切面(Aspect) 切面是通知和切入点的结合。现在发现了吧,没连接点什么事,链接点就是为了让你好理解切点搞出来的,明白这个概念就行了。通知说明了干什么和什么时候干(什么时候通过方法名中的befor,after,around等就能知道),二切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义。
- 引入(introduction) 允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗
- 目标(target) 引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被咋们织入切面。二自己专注于业务本身的逻辑。
- 代理(proxy) 怎么实现整套AOP机制的,都是通过代理,这个一会儿给细说。
- 织入(weaving) 把切面应用到目标对象来创建新的代理对象的过程。有三种方式,spring采用的是运行时
基础的注解:
@Aspect//声明切面,标记类
@Pointcut("execution(* *.perform(..))") //定义切点,标记方法
@Before("performance()") //切点之前执行
@AfterReturning("performance()") //切点之后执行
@AfterThrowing("performance()") //切点抛出异常后执行
Spring AOP 的注解配置并不复杂:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
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/task
http://www.springframework.org/schema/task/spring-task-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
springde xml配置文件中加入aop相关的命名空间
<!-- 切面配置 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
开启aop的注解配置,配置就基本完成了
下面整理一下基础的几个切面的使用方法:
@Aspect
@Component
public class AspectAction {
@Pointcut("execution(public String myMaven.action.*.*(..))")
public void testPointcut(){ //myMaven.action
}
@Pointcut("execution(public String myMaven.action.*.*(..))")
public void testPointcut01(){
}
@Before("testPointcut()")
public void aspectTest01(JoinPoint joinPoint){
System.out.println("============before 切面 方法执行");
Object[] paramValues = joinPoint.getArgs();
String[] paramNames = ((CodeSignature) joinPoint.getSignature()).getParameterNames();
for(int i=0;i<paramNames.length;i++){
System.out.println(paramNames[i]+","+paramValues[i]);
}
}
@AfterReturning(returning="rvt", pointcut="testPointcut01()")
public void aspectTest02(JoinPoint joinPoint,Object rvt){
System.out.println("============after 切面 方法执行");
System.out.println("返回值:"+ rvt);
}
}
上面两个切面分别是方法执行前和方法有返回后织入:
方法执行请主要涉及到的是要获取切点方法的参数,joinPoint.getSignature()强转为CodeSignature类后,才可以拿到方法的参数名数组,通过循环可以拿到所有的参数
方法返回后的问题就是要获取该方法的返回值,例子如上,返回值就在第二个参数object rvt中。
@Pointcut("execution(public String myMaven.action.AspectTestAction.login(..))")
public void testPointcut02(){
}
切入点excution表达式的语法
1、execution(): 表达式主体。
2、第一个*号:表示返回类型, *号表示所有的类型。
3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
4、第二个*号:表示类名,*号表示所有的类。
5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数
具体的使用例子 http://sishuok.com/forum/posts/list/281.html 点击打开链接