需求:以前的动态选择数据库,和如今的将某个service层的方法接入cat,都须要用到切面编程。html
参考文献:java
http://www.blogjava.net/supercrsky/articles/174368.htmlspring
http://my.oschina.net/itblog/blog/211693数据库
1、简介编程
面向切面编程(AOP)提供另一种角度来思考程序结构,经过这种方式弥补了面向对象编程(OOP)的不足。 除了类(classes)之外,AOP提供了 切面。切面对关注点进行模块化,例如横切多个类型和对象的事务管理。 (这些关注点术语一般称做 横切(crosscutting) 关注点。)缓存
Spring的一个关键的组件就是 AOP框架。 尽管如此,Spring IoC容器并不依赖于AOP,这意味着你能够自由选择是否使用AOP,AOP提供强大的中间件解决方案,这使得Spring IoC容器更加完善。框架
切面(Aspect): 一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。 在Spring AOP中,切面可使用通用类(基于模式的风格) 或者在普通类中以 @Aspect 注解(@AspectJ风格)来实现。ide
链接点(Joinpoint): 在程序执行过程当中某个特定的点,好比某方法调用的时候或者处理异常的时候。 在Spring AOP中,一个链接点 老是 表明一个方法的执行。 经过声明一个 org.aspectj.lang.JoinPoint 类型的参数可使通知(Advice)的主体部分得到链接点信息。模块化
通知(Advice): 在切面的某个特定的链接点(Joinpoint)上执行的动做。通知有各类类型,其中包括“around”、“before”和“after”等通知。 通知的类型将在后面部分进行讨论。许多AOP框架,包括Spring,都是以拦截器作通知模型,并维护一个以链接点为中心的拦截器链。spa
切入点(Pointcut): 匹配链接点(Joinpoint)的断言。通知和一个切入点表达式关联,并在知足这个切入点的链接点上运行(例如,当执行某个特定名称的方法时)。 切入点表达式如何和链接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。
引入(Introduction): (也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。 Spring容许引入新的接口(以及一个对应的实现)到任何被代理的对象。 例如,你可使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。
目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫作 被通知(advised) 对象。 既然Spring AOP是经过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。
AOP代理(AOP Proxy): AOP框架建立的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能)。 在Spring中,AOP代理能够是JDK动态代理或者CGLIB代理。 注意:Spring 2.0最新引入的基于模式(schema-based)风格和@AspectJ注解风格的切面声明,对于使用这些风格的用户来讲,代理的建立是透明的。
织入(Weaving): 把切面(aspect)链接到其它的应用程序类型或者对象上,并建立一个被通知(advised)的对象。 这些能够在编译时(例如使用AspectJ编译器),类加载时和运行时完成。 Spring和其余纯Java AOP框架同样,在运行时完成织入。
通知的类型:
前置通知(Before advice): 在某链接点(join point)以前执行的通知,但这个通知不能阻止链接点前的执行(除非它抛出一个异常)。
返回后通知(After returning advice): 在某链接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
抛出异常后通知(After throwing advice): 在方法抛出异常退出时执行的通知。
后通知(After (finally) advice): 当某链接点退出的时候执行的通知(不管是正常返回仍是异常退出)。
环绕通知(Around Advice): 包围一个链接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知能够在方法调用先后完成自定义的行为。它也会选择是否继续执行链接点或直接返回它们本身的返回值或抛出异常来结束执行。
环绕通知是最经常使用的一种通知类型。大部分基于拦截的AOP框架,例如Nanning和JBoss4,都只提供环绕通知。
切入点(pointcut)和链接点(join point)匹配的概念是AOP的关键,这使得AOP不一样于其它仅仅提供拦截功能的旧技术。 切入点使得定位通知(advice)可独立于OO层次。 例如,一个提供声明式事务管理的around通知能够被应用到一组横跨多个对象中的方法上(例如服务层的全部业务操做)。
2、编程(有两种,基于注解方式和XML配置方式,介绍基于注解方式的AOP编程)
一、配置文件中须要配置AOP
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd ">
二、
package com.abc.advice;
import java.util.Arrays;
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.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AdviceTest {
@Around("execution(* com.abc.service.*.many*(..))")
public Object process(ProceedingJoinPoint point) throws Throwable {
System.out.println("@Around:执行目标方法以前...");
//访问目标方法的参数:
Object[] args = point.getArgs();
if (args != null && args.length > 0 && args[0].getClass() == String.class) {
args[0] = "改变后的参数1";
}
//用改变后的参数执行目标方法
Object returnValue = point.proceed(args);
System.out.println("@Around:执行目标方法以后...");
System.out.println("@Around:被织入的目标对象为:" + point.getTarget());
return "原返回值:" + returnValue + ",这是返回结果的后缀";
}
@Before("execution(* com.abc.service.*.many*(..))")
public void permissionCheck(JoinPoint point) {
System.out.println("@Before:模拟权限检查...");
System.out.println("@Before:目标方法为:" +
point.getSignature().getDeclaringTypeName() +
"." + point.getSignature().getName());
System.out.println("@Before:参数为:" + Arrays.toString(point.getArgs()));
System.out.println("@Before:被织入的目标对象为:" + point.getTarget());
}
@AfterReturning(pointcut="execution(* com.abc.service.*.many*(..))",
returning="returnValue")
public void log(JoinPoint point, Object returnValue) {
System.out.println("@AfterReturning:模拟日志记录功能...");
System.out.println("@AfterReturning:目标方法为:" +
point.getSignature().getDeclaringTypeName() +
"." + point.getSignature().getName());
System.out.println("@AfterReturning:参数为:" +
Arrays.toString(point.getArgs()));
System.out.println("@AfterReturning:返回值为:" + returnValue);
System.out.println("@AfterReturning:被织入的目标对象为:" + point.getTarget());
}
@After("execution(* com.abc.service.*.many*(..))")
public void releaseResource(JoinPoint point) {
System.out.println("@After:模拟释放资源...");
System.out.println("@After:目标方法为:" +
point.getSignature().getDeclaringTypeName() +
"." + point.getSignature().getName());
System.out.println("@After:参数为:" + Arrays.toString(point.getArgs()));
System.out.println("@After:被织入的目标对象为:" + point.getTarget());
}
}
访问目标方法最简单的作法是定义加强处理方法时,将第一个参数定义为JoinPoint类型,当该加强处理方法被调用时,该JoinPoint参数就表明了织入加强处理的链接点。JoinPoint里包含了以下几个经常使用的方法:
Object[] getArgs:返回目标方法的参数
Signature getSignature:返回目标方法的签名
Object getTarget:返回被织入加强处理的目标对象
Object getThis:返回AOP框架为目标对象生成的代理对象
注意:当使用@Around处理时,咱们须要将第一个参数定义为ProceedingJoinPoint类型,该类是JoinPoint的子类。