AspectJ简介
- AspectJ是一个基于Java语言的AOP框架
- Spring2.0以后新增了对AspectJ切点表达式支持
- @AspectJ是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
- 新版本Spring框架,建议使用AspectJ方式来开发AOP
- 使用AspectJ需要导入Spring AOP和AspectJ相关jar包
- 除spring四个核心包之外还需要
- spring-aop
- aopalliance
- spring-aspects
- aspectjweaver
使用AspectJ实现AOP的两种方式
- 注解方式
- XML方式
注解方式的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: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">
<!-- bean definitions here -->
</beans>
@AspectJ提供不同的通知类型
- @Before前置通知,相当于BeforeAdvice
- @AfterReturning后置通知,相当于AfterReturningAdvice
- @Around环绕通知,相当于MethodInterceptor
- @AfterThrowing异常抛出通知,相当于ThrowAdvice
- @After最终final通知,不管是否异常,该通知都会执行
- @DeclareParents引介通知,相当于IntroductionInterceptor
在通知中通过value属性定义切点
通过execution函数,可以定义切点的方法切入
语法
execution(<访问修饰符>?<返回值类型><方法名>(<参数>)<异常>)
例子
- 匹配所有类public方法 execution(public * *(..))
- 匹配指定包下所有类方法 execution(* com.dao.*(..)) ==不包含子包==
- execution(* com.dao..*(..)) ==包、子包下所有类==
- 匹配指定类所有方法 execution(* com.service.UserService.*(..))
- 匹配实现特定接口所有类方法 execution(* com.dao.GenericDAO==+.*(..)) ==+代表子类==
- 匹配所有save开头的方法 execution(* save*(..))
例子
xml
<?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: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">
<!--开启AspectJ的注解开发,自动代理-->
<aop:aspectj-autoproxy />
<!--目标类-->
<bean id="userDao" class="com.UserDao" />
<!--定义切面-->
<bean class="com.MyAspect" />
</beans>
目标类
package com;
public class UserDao {
public void save(){
System.out.println("保存");
}
public void delete(){
System.out.println("删除");
}
public void find(){
System.out.println("查找");
}
public void findAll(){
System.out.println("查找所有");
}
}
切面类
package com;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspect {
@Before(value = "execution(* com.UserDao.*(..))")
public void before(){
System.out.println("前置通知!!!!");
}
}
@Before前置通知
可以在方法中传入JoinPoint对象,用来获取切点信息
@Before(value = "execution(* com.UserDao.*(..))")
public void before(JoinPoint joinPoint){
System.out.println("前置通知!!!!"+joinPoint);
}
@AfterReturing后置通知
通过returning属性,可以定义方法返回值returning,作为参数
@AfterReturning(value = "execution(* com.UserDao.find(..))" , returning = "result")
public void afterReturning(Object result){
System.out.println("后置通知!!!!" + result);
}
@Around环绕通知
around方法的返回值就是目标代理方法执行返回值,参数ProceedingJoinPoint可以调用拦截目标方法执行,==如果不调用ProceedingJoinPoint的proceed方法,那么目标方法就被拦截了==
@Around(value = "execution(* com.UserDao.delete(..))")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前");
Object object = proceedingJoinPoint.proceed();
System.out.println("环绕后");
return object;
}
@AfterThrowing异常抛出通知
通过设置throwing属性,可以设置发生异常对象参数
@AfterThrowing(value = "execution(* com.UserDao.findAll(..))",throwing = "e")
public void afterThrowing(Throwable e){
System.out.println("异常抛出通知"+ e.getMessage());
}
@After最终通知
无论是否出现异常,最终通知总是会被执行的
@After(value = "execution(* com.UserDao.findAll(..))")
public void after(){
System.out.println("最终通知");
}
通过@Pointcut为切点命名
- 在每个通知内定义切点,会造成工作量大,不易维护,对于重复的切点,可以使用@Pointcut进行定义
- 切点方法:private void 无参数方法,方法名为切点名
- 当通知多个切点时,可以使用||进行连接
==这里要注意aspectjweaver的版本==
@Before(value = "pointCutDelete() || pointCutSave()")
public void before(JoinPoint joinPoint){
System.out.println("前置通知!!!!"+joinPoint);
}
//定义切点
@Pointcut(value = "execution(* com.UserDao.save(..))")
private void pointCutSave(){}
@Pointcut(value = "execution(* com.UserDao.delete(..))")
private void pointCutDelete(){}
XML方式开发AOP
<!--aop的相关配置-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pointcut1" expression="execution(* com.UserDao.find(..))" />
<!--配置AOP切面-->
<aop:aspect ref="myAspect">
<!--配置前置通知-->
<aop:before method="before" pointcut-ref="pointcut1" />
</aop:aspect>
</aop:config>
<!--后置通知以及返回值-->
<aop:after-returning method="before" pointcut-ref="pointcut1" returning="result"/>
网友评论