AOP
基本术语
切面:横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
通知:切面必须要完成的工作
目标:被通知的对象
代理:向目标对象应用通知之后创建的对象
连接点:程序执行的某个特定位置
切点:AOP通过切点定位到特定的连接点
注:切点和连接点不是一一对应关系,而是一个切点匹配多个连接点
SPring AOP基于注解的方式开发
步骤:基于注解的方式
1.额外导包
Spring-aop包,Spring-aspects包,springsource.org.aoplliance包,springsource.org.aspectj.weaver包
2.配置XML
为了使Aspjectj注解起作用,自动为匹配的类生成代理对象
需要在xml文件中添加aop的命名空间
xmlns:aop="http://www.springframework.org/chema/aop"
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
3.编写切面类
把横切关注点的代码抽象到切面的类中
i.切面首先是一个IOC中的bean,即加入@Component 注解
ii.为类添加注解@Aspject表示这是一个切面类
3.1 @Order(数字)
定义切面类的优先级
数字越小,优先级越高
4.声明各种通知
为需要添加到代理对象中的方法 添加注解
**理解思路**:
try{
//前置通知
//返回通知
}
catch(Exception e)
{
//异常通知
}
//后置通知
1.前置通知:@Before:代表作用在被代理的对象方法使用之前
如果需要让被代理类的所有方法都被代理,将方法名换成 * 就可以了
*举例*: @Before("execution(public 方法类型 包名.类名.方法名(参数))")//也可以将"public 方法类型" 换成 * 代表任意修饰符和任意返回值
public void AspectMethod(JoinPoint joinPoint)
{
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("方法名是"+methodName+"参数是"+args);
}
2.后置通知:@After:代表作用在被代理的对象方法使用之后
无论过程中有没有发生异常,都会执行后置通知
因为可能会出现异常,所以在后置通知中不能访问目标方法执行的结果
3.返回通知:@AfterReturning
可以访问到方法的返回值结果
*举例*:@AfterReturning(value = "execution(public 方法类型 包名.类名.方法名(参数))" , returning = "result(返回值名:自定义的)")
public void afterReturning(JoinPoint joinPoint , Object result)
{
String methodName = joinPoint.getSignature().getName();
System.out.println("方法名是"+methodName+"参数是"+args+"结果是"+result);
}
4.异常通知:@AfterThrowing
在目标方法出现异常时会执行的代码
可以访问到异常对象,且可以自己指定在出现特定异常时在执行通知代码
*举例*:@AfterThrowing(value = "execution(public 方法类型 包名.类名.方法名(参数))" , throwing = "e(异常对象名:自定义的)")
public void afterThrowing(JoinPoint joinPoint , Exception e)
{
String methodName = joinPoint.getSignature().getName();
System.out.println("方法名是"+methodName+"参数是"+args+"出现了异常"+e);
}
5.环绕通知:@Around
环绕通知需要携带ProceedingJoinPoint类型的参数
环绕通知类似于动态代理的全过程:参数可以决定是否执行目标方法
环绕通知必须有返回值,返回值即为目标方法的返回值
*举例*:@Around("execution(public 方法类型 包名.类名.方法名(参数))")
public object aroundMethod(ProceedingJoinPoint pjd)
{
object result = null;
String methodName = pjd.getSignature().getName();
try{
//前置通知
System.out.println("前置通知"+Arrays.asList(pjd.getArgs()));
//执行目标方法
result = pjd.proceed();
//返回通知
System.out.println("返回通知"+result);
}
catch(Throwable e)
{
//异常通知
System.out.println("异常"+e);
}
//后置通知
System.out.println("后置通知");
}
切点表达式的重用
execution(public 方法类型 包名.类名.方法名(参数))
为了代码的复用性提高,避免修改的时候太复杂
使用 @Pointcut
自定义一个方法专门用来表示,方法内部什么都不需要写
举例:@Pointcut("execution(public 方法类型 包名.类名.方法名(参数))")
public void JoinPointExpression(){}
(使用样例) @Before("类名.JoinPointExpression()")
Spring AOP基于xml配置开发
步骤:
1. <!-- 配置bean -->
<bean id = "bean接口类名" class = "包名.bean对象名"></bean>
......
2.<!-- 配置切面的bean -->
<bean id = "切面类名" class = "包.类.切面对象"></bean>
......
3.<!-- 配置AOP -->
<aop:config>
<!--配置切面表达式-->
<aop:pointcut expression = "execution(public 方法类型 包名.类名.方法名(参数))" id="pointcut(自己指定的)"/>
<!--配置切面及通知-->
<aop:aspect ref = "切面类名" order = "数字">
<aop:before(前置通知) method = "前置方法名" pointcut-ref = "pointcut" />
<aop:after(后置通知) method = "后置方法名" pointcut-ref = "pointcut" />
<aop:after-throwing(异常通知) method = "异常方法名" pointcut-ref = "pointcut" throwing = "e" />
<aop:after-returning(返回通知) method = "返回方法名" pointcut-ref = "pointcut" returning = “result” />
</aop:aspect>
<!--环绕通知-->
<aop:aspect ref = "切面类名" order = "数字">
<aop:around method = "环绕方法名" pointcut-ref = "pointcut" />
</aop:aspect>
</aop:config>