AspectJ是一个基于java语言的AOP框架。Spring2.0以后新增了对AspectJ切点表达式的支持。@AspectJ是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面。主要用途:自定义开发。
切点表达式
1. execution() 用于描述方法
语法:
execution(修饰符 返回值 包.类.方法名(参数) throws 异常)
修饰符,一般省略
public 公共方法
* 任意
返回值,不能省略
void 没有返回值
String 返回字符串
* 任意
包,【省略】
com.dsx.crm 固定包
com.dsx.crm.*.service.. crm包下面任意子包,固定目录service,service目录下任意包
com.dsx.crm.. crm包下面的所有子包(包含自己所在的包)
类,【省略】
EmployeeServiceImp 指定类
*Impl 以Impl结尾
Emp* 以Emp开头
* 任意
方法名,不能省略
add 固定方法
*add 以add结尾
add* 以add开头
* 任意
(参数)
() 无参
(int) 一个整型
(int,int) 两个
(..) 参数任意
throws,可以省略。一般不写
execution(修饰符 返回值 包.类.方法名(参数) throws 异常)
案例1 :
execution(* com.dsx.crm.*.service..*.*(..))
案例2:
<aop:pointcut expression="execution(* com.dsx.crm.*do.*(..)) || execution(* com.dsx.crm.*service.*(..)) " id=" " />
|| 匹配以上两种切点任意一个都可以
了解部分:
2. within: 匹配包或子包中的方法 within(com.dsx.aop..*)
3. this:匹配实现接口的代理对象中的方法 this(com.dsx.aop.EmployeeDao)
4. target: 匹配实现接口的目标对象中的方法 target(com.dsx.aop.UserDao)
5. args: 匹配参数格式符合标准的方法 args(int,int)
6. bean(id) : 对指定的bean所有的方法 bean(UserServiceId)
AspectJ通知类型
aop联盟定义通知类型,具有特定的接口,必须实现,从而确定方法名称。
aspectJ通知类型,只定义类型名称,以及方法格式。
before:前置通知 (应用:各种校验)
在方法执行前执行,如果通知抛出异常,阻止方法运行
afterReturning:后置通知 (应用:常规数据处理)
方法正常返回后执行,如果方法中抛出异常,通知无法执行
必须在方法执行后才执行,所以可以获得方法的返回值。
around:环绕通知 (应用:十分强大,可以做任何事情)
方法执行前后分别执行,可以阻止方法的执行
必须手动执行目标方法
afterThrowing:抛出异常通知(应用:包装异常信息)
方法抛出异常后执行,如果方法没有抛出异常,无法执行
after:最终通知(应用:清理现场)
方法执行完毕后执行,无论方法中是否出现异常都会执行
导入的jar包有:
基于xml的配置
目标类
package com.dsx.spring_aspectJ;
public interface EmployeeService {
public void addEmployee();
public void updateEmployee();
public void deleteEmployee();
}
package com.dsx.spring_aspectJ;
//目标类
public class EmployeeServiceImp implements EmployeeService {
@Override
public void addEmployee() {
System.out.println("执行了添加用户的方法");
}
@Override
public void updateEmployee() {
System.out.println("执行了updateEmployee的方法");
}
@Override
public void deleteEmployee() {
System.out.println("执行了deleteEmployee的方法");
int i=1/0;
}
}
切面类
package com.dsx.spring_aspectJ;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
//切面类 应用Aspectj,含有多个通知,方法名可以是任意的
public class MyAspect {
public void myBefore(JoinPoint joinPoint) {
System.err.println("前置通知"+joinPoint.getSignature().getName());
}
public void myAfterReturning(JoinPoint joinPoint,Object object) {
//第二个参数为返回值
System.err.println("后置通知"+joinPoint.getSignature().getName());
System.out.println("后置通知"+object);
}
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知--前");
//手动执行目标方法
Object obj = joinPoint.proceed();
System.out.println("环绕通知--后");
return obj;
}
public void myAfterThrowing(JoinPoint joinPoint,Throwable e) {
System.out.println("异常通知"+e.getMessage());
}
public void myAfter(JoinPoint joinPoint) {
System.out.println("最终通知");
}
}
spring配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 业务类 -->
<bean id="employeeServiceImp" class="com.dsx.spring_aspectJ.EmployeeServiceImp" />
<!-- 切面类,通知 -->
<bean id="myAspect" class="com.dsx.spring_aspectJ.MyAspect"/>
<!-- aop编程
<aop:aspect>将切面类声明"切面",从而 获得通知(方法)
ref:切面类引用
<aop:pointcut >声明一个切入点表达式,所有的通知都可以使用
expression切入点表达式
id:名称,用于其他通知的引用
-->
<aop:config>
<aop:aspect ref="myAspect">
<aop:pointcut expression="execution(* com.dsx.spring_aspectJ.EmployeeServiceImp.*(..))" id="myPointcut"/>
<!-- <aop:before method="通知,即方法名"
pointcut="切入点表达式,此表达式只能当前通知使用"
pointcut-ref="切入点引用,可以与其它通知共享切入点"/>
通知方法格式:public void myBefore(JoinPoint joinPoint)
参数一:org.aspectj.lang.JoinPoint;用于描述连接点(目标方法),获得目标方法名等。
-->
<aop:before method="myBefore" pointcut-ref="myPointcut"/>
<!-- 后置通知,目标方法后执行,获得返回值
<aop:after-returning method="通知,即方法名"
pointcut-ref="切入点引用"
returning="object"/>
通知方法的格式:public void myAfterReturning(JoinPoint joinPoint,Object object) {
参数一:连接点描述
参数二:返回值类型Object,参数名 returning="object"配置的
<aop:after-returning method="myAfterReturning" pointcut-ref="myPointcut" returning="object"/>
-->
<!-- 环绕通知
通知方法的格式:public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable
返回值类型:Object
方法名:任意
参数:org.aspectj.lang.ProceedingJoinPoint;
抛出异常:Throwable
执行目标方法:Object obj = joinPoint.proceed();
如:
<aop:around method="myAround" pointcut-ref="myPointcut"/>
-->
<!-- 抛出异常
通知方法的格式:public void myAfterThrowing(JoinPoint joinPoint,Throwable e)
参数一:连接点描述对象
参数二:获得异常信息,类型Throwable,参数名由throwing="e"配置
如:
<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointcut" throwing="e"/>
-->
<!-- 最终通知,无论是否有异常,都会执行
通知方法的格式:public void myAfter(JoinPoint joinPoint)
如:
<aop:after method="myAfter" pointcut-ref="myPointcut"/>
-->
</aop:aspect>
</aop:config>
</beans>
测试类
package com.dsx.spring_aspectJ;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AspectJTest {
@Test
public void test1() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("com/dsx/spring_aspectJ/bean.xml");
EmployeeService employeeServiceImp = (EmployeeService) context.getBean("employeeServiceImp");
employeeServiceImp.addEmployee();
employeeServiceImp.deleteEmployee();
}
}
在对通知类型进行测试时,建议一个一个类型的去测试,更利于我们的理解。
基于注解的配置
spring的配置
切面类
package com.dsx.spring_aspectJ2;
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.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
//切面类 应用Aspectj,含有多个通知,方法名可以是任意的
@Component
@Aspect //声明为切面类
public class MyAspect {
//为了方便书写,声明一个公共的切入点
@Pointcut("execution(* com.dsx.spring_aspectJ2.EmployeeServiceImp.*(..))")
public void myPointCut() {}
// @Before(value="myPointCut()")
@Before("execution(* com.dsx.spring_aspectJ2.EmployeeServiceImp.*(..))")
public void myBefore(JoinPoint joinPoint) {
System.err.println("前置通知"+joinPoint.getSignature().getName());
}
@AfterReturning(value="myPointCut()",returning="object")
public void myAfterReturning(JoinPoint joinPoint,Object object) {
//第二个参数为返回值
System.err.println("后置通知"+joinPoint.getSignature().getName());
System.out.println("后置通知"+object);
}
@Around(value="myPointCut()")
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知--前");
//手动执行目标方法
Object obj = joinPoint.proceed();
System.out.println("环绕通知--后");
return obj;
}
@AfterThrowing(value="myPointCut()",throwing="e")
public void myAfterThrowing(JoinPoint joinPoint,Throwable e) {
System.out.println("异常通知"+e.getMessage());
}
@After(value="myPointCut()")
public void myAfter(JoinPoint joinPoint) {
System.out.println("最终通知");
}
}
AspectJ属于静态AOP代理的增强,在项目中,我们一般都采用注解的方式去实现。用来完成自定义的功能的开发。
如有不足,欢迎留言指正。望不吝赐教。。。