在现在的开发中使用这种方案比较多.
在spring2.0以后它支持jdk1.5注解,而整合aspectj后可以使用aspectj语法,可以简化开发。
Aspect:切面 =切点+通知(多个切点与多个通知的组合)
AspectJ 它是一个第三方框架,spring从2.0后可以使用aspectJ框架的部分语法.
AspectJ框架它定义的通知类型有6种
- 前置通知Before 相当于BeforeAdvice
- 后置通知AfterReturning 相当于AfterReturningAdvice
- 环绕通知 Around 相当于MethodInterceptor
- 抛出通知AfterThrowing 相当于ThrowAdvice
- 引介通知DeclareParents 相当于IntroductionInterceptor
- 最终通知After 不管是否异常,该通知都会执行
相比spring 的传统AOP Advice多了一个最终通知
基于xml配置方案
第一步:创建目标(target)
接口
package com.itcast.aspectj;
public interface IUserService {
public void add();
public void update();
public void del();
public void search();
}
实现类
package com.itcast.aspectj;
public class IUserServiceImpl implements IUserService {
@Override
public void add() {
System.out.println(0/0);
System.out.println("aspectj IUserService add");
}
@Override
public void update() {
System.out.println("aspectj IUserService update");
}
@Override
public void del() {
System.out.println(0/0);
System.out.println("aspectj IUserService del");
}
@Override
public void search() {
System.out.println("aspectj IUserService search");
}
}
第二步:创建通知(增强 advice)
注意:在aspectj中它的增强可以不实现任何接口,只需要定义出增强功能(方法)
package com.itcast.aspectj;
import org.aspectj.lang.ProceedingJoinPoint;
//advice通知
public class IUserServiceHapper {
public void before(){
System.out.println("前置通知。。。");
}
public void before1(){
System.out.println("前置通知1。。。");
}
public void afterReturning(){
System.out.println("后置通知。。。");
}
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕前。。。");
Object value = point.proceed();//执行目标行为
System.out.println("环绕后。。。");
return value;
}
public void afterThorwing(){
System.out.println("异常通知");
}
public void after(){
System.out.println("最终通知。。。");
}
}
第三步:在spring的xml 配置文件中来配置
aop:config下的aop:aspect是aspectJ框架用来声明切面的。
<?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.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--目标target-->
<bean id="userService" class="com.itcast.aspectj.IUserServiceImpl"></bean>
<!--通知Advice-->
<bean id="userServiceAdvice" class="com.itcast.aspectj.IUserServiceHapper"></bean>
<!--通过AOP的标签来完成我们的配置-->
<aop:config> <!--它帮我们完成自动代理功能-->
<!--抽取切点-->
<aop:pointcut id="addpointcut" expression="execution(* *.add(..)) "></aop:pointcut>
<aop:pointcut id="delpointcut" expression="execution(* *.del(..)) "></aop:pointcut>
<aop:aspect ref="userServiceAdvice">
<!--前置通知-->
<aop:before method="before" pointcut-ref="addpointcut"/>
<aop:before method="before1" pointcut-ref="addpointcut"/>
<!--后置通知-->
<aop:after-returning method="afterReturning" pointcut-ref="addpointcut"/>
<!--环绕通知-->
<aop:around method="around" pointcut-ref="addpointcut"/>
<!--最终通知-->
<aop:after method="after" pointcut-ref="addpointcut"/>
<!--异常通知-->
<aop:after-throwing method="afterThorwing" pointcut-ref="delpointcut"/>
</aop:aspect>
</aop:config>
</beans>
通知类型:
也可把切点抽取出来做成公共的,各通知可进行引用,可设置多个< aop:pointcut>
修改如下:
<aop:config> <!--它帮我们完成自动代理功能-->
<aop:pointcut id="addpointcut" expression="execution(* *.add(..)) "></aop:pointcut>
<aop:pointcut id="delpointcut" expression="execution(* *.del(..)) "></aop:pointcut>
<aop:aspect ref="userServiceAdvice">
<aop:before method="before" pointcut-ref="addpointcut"/>
<aop:before method="before1" pointcut-ref="addpointcut"/>
<aop:after-returning method="afterReturning" pointcut-ref="addpointcut"/>
<aop:around method="around" pointcut-ref="addpointcut"/>
<aop:after method="after" pointcut-ref="addpointcut"/>
<aop:after-throwing method="afterThorwing" pointcut-ref="delpointcut"/>
</aop:aspect>
</aop:config>
关于通知上的参数
- 在前置通知上可以添加JoinPoint参数
通过它可以获取目标相关的信息
public void before(JoinPoint jp){
System.out.println("拦截的目标类:"+jp.getSignature().getDeclaringTypeName());
System.out.println("拦截的方法名称:"+jp.getSignature().getName());
System.out.println("前置通知");
}
使用前置通知可以完成日志记录,权限控制
- 在后置通知上添加的参数
public void afterReturning(JoinPoint jp,Object val){
System.out.println("返回val。。。");
System.out.println("后置通知。。。");
}
第二个参数val它可以获取目标方法的返回值
注意:需要在配置文件中配置
<!--后置通知-->
<aop:after-returning method="afterReturning" pointcut-ref="addpointcut" returning="val"/>
- 环绕通知上的参数
public Object around(ProceedingJoinPoint pjp) throws Throwable {
//它是我们开发中应用最多的,可以完成日志操作,权限操作,性能监控,事务管理
System.out.println("环绕前。。。");
Object value = pjp.proceed();//执行目标行为
System.out.println("环绕后。。。");
return value;
}
它是我们开发中应用最多的,可以完成日志操作,权限操作,性能监控,事务管理
4.抛出异常通知上的参数
public void afterThorwing(JoinPoint jp,Throwable throwable){
//第二个参数Throwable它是用于接收抛出的异常,注意:需要在配置文件中声明
System.out.println("异常通知");
}
第二个参数Throwable它是用于接收抛出的异常
注意:需要在配置文件中声明
<!--异常通知-->
<aop:after-throwing method="afterThorwing" pointcut-ref="delpointcut" throwing="throwable"/>
- 最终通知上的参数
public void after(JoinPoint joinPoint){
//可以使用最终通知完成资源释放
System.out.println("最终通知。。。");
}
可以使用最终通知完成资源释放