1 入门例子
基于XML的声明式AspectJ实现AOP需要在配置文件中配置大量的代码信息,现在用注解取代配置文件了解一下。
1.1 创建目标接口和目标类
目标接口
package com.lxg.aspectj;
public interface UserDao {
public void addUser();
public void deleteUser();
}
目标实现类
package com.lxg.aspectj;
public class UserDaoImpl implements UserDao{
public void addUser() {
System.out.println("添加用户");
}
public void deleteUser() {
System.out.println("删除用户");
}
}
1.2 创建切面类
package com.lxg.aspectj.annotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MyAspect {
//定义切入点表达式
@Pointcut("execution(* com.lxg.aspectj.*.*(..))")
//使用一个返回值为void、方法体为空的方法来命名切入点
public void myPointCut(){}
//前置通知
@Before("myPointCut()")
public void myBefore(JoinPoint joinPoint){
System.out.println("前置通知:模拟执行权限检查");
System.out.println("目标类是:"+joinPoint.getTarget());
System.out.println(",被织入增强处理的方法是:"+joinPoint.getSignature().getName());
}
//后置通知
@AfterReturning(value = "myPointCut()")
public void afterReturning(JoinPoint joinPoint){
System.out.println("前置通知:模拟记录日志。。。");
System.out.println("目标类是:"+joinPoint.getTarget());
}
/**
* 环绕通知
* proceedingJoinPoint 是JoinPoint的子接口,表示可执行目标方法。
* 1.必须是Object类型的返回值
* 2.必须接收一个参数,类型为ProceedingJoinPoint
* 3.必须是throws Throwable
* @param proceedingJoinPoint
* @return
* @throws Throwable
*/
@Around("myPointCut()")
public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
//开始
System.out.println("环绕开始:执行目标方法之前,模拟开启事务");
//执行当前目标方法
Object obj = proceedingJoinPoint.proceed();
//结束
System.out.println("环绕结束:执行目标方法之后,模拟关闭事务");
return obj;
}
//异常通知
@AfterThrowing(value = "myPointCut()",throwing = "e")
public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("异常通知:出错了"+e.getMessage());
}
//最终通知
@After("myPointCut()")
public void myAfter(){
System.out.println("最终通知:模拟方法结束后释放资源...");
}
}
1.3 配置切面类和目标类
在切面类和目标类上使用@Component注解,将其标注成Spring Bean
1.5 在配置文件中开启主键扫描和AOP的自动代理
<!--开启注解扫描,指定需要扫描的包,使包下面的注解生效-->
<context:component-scan base-package="com.lxg"/>
<!--启动基于注解的声明式AspectJ支持-->
<aop:aspectj-autoproxy/>
1.6 测试
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml")
public class AopTest { @Autowired
private TargetInterface target;
@Test
public void test1(){
target.method();
}
}
运行结果:
前置通知:模拟执行权限检查
目标类是:com.lxg.aspectj.UserDaoImpl@56de5251
,被织入增强处理的方法是:addUser
环绕开始:执行目标方法之前,模拟开启事务
添加用户
最终通知:模拟方法结束后释放资源...
环绕结束:执行目标方法之后,模拟关闭事务
前置通知:模拟记录日志。。。
目标类是:com.lxg.aspectj.UserDaoImpl@56de5251
2 注解配置AOP详解
2.1 注解类型
切面类的注解
- @AspectJ
用于定义一个切面
切入点表达式的注解
- @PointCut
用于定义切入点表达式。在使用的时候需要定义一个包含名字和任意参数的方法签名来表示切入点名称。实际上,这个方法就是一个返回值为void且方法体为空的方法。
通知配置的注解
名称 | 注解 | 说明 |
---|---|---|
前置通知 | @Before | 用于配置前置通知。指定增强的方法在切入点方法之前执行 |
后置通知 | @AfterReturning | 用于配置后置通知。指定增强的方法在切入点方法之后执行 |
环绕通知 | @Around | 用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行 |
异常抛出通知 | @AfterThrowing | 用于配置异常抛出通知。指定增强的方法在出现异常时执行 |
最终通知 | @After | 用于配置最终通知。无论增强方式执行是否有异常都会执行 |
总结: 相对来说,使用注解的方式更加简单、方便,所以在实际的开发中,推荐使用注解。