目录
1.概念理解
2. 案例说明
1.概念理解
【注】一些概念来自:https://blog.csdn.net/Kaiser__/article/details/135894150
横切关注点
分散在每个各个模块中解决同一样的问题,如用户验证、日志管理、事务处理、数据缓存都属于横切关注点。这个概念不是语法层面的,而是根据附加功能的逻辑上的需要:有十个附加功能,就有十个横切关注点。
通知(增强)
增强,通俗说,就是你想要增强的功能,比如 安全,事务,日志等。每一个横切关注点上要做的事情都需要写一个方法来实现,这样的方法就叫通知方法。
前置通知:在被代理的目标方法前执行
返回通知:在被代理的目标方法成功结束后执行
异常通知:在被代理的目标方法异常结束后执行
后置通知:在被代理的目标方法最终结束后执行
环绕通知:使用try…catch…finally结构围绕整个被代理的目标方法,包括上面四种通知对应的所有位置切面
封装通知方法的类。目标
被代理的目标对象。代理
向目标对象应用通知之后创建的代理对象。连接点
通俗说,就是spring允许使用通知的地方切入点
定位连接点的方式。每个类的方法中都包含多个连接点,所以连接点是类中客观存在的事物(从逻辑上来说)。如果把连接点看作数据库中的记录,那么切入点就是查询记录的 SQL 语句。
AspectJ实施增强的类需要配置为切面,AspectJ提供了下列注解用于配置切面,注解如下:
- @Aspect 配置一个类为切面类
- @Before 配置一个方法为前置增强
- @After 配置一个方法为后置增强
- @AfterReturning 配置一个方法为返回后增强
- @AfterThrowing 配置一个方法为抛出异常后增强
- @Around 配置一个方法为环绕增强
- @DeclareParents 配置一个属性为引介增强(类级别)
切入点表达式
- execution(权限修饰符 方法返回值 方法所在类的全类名 方法名(参数列表))
- 如果我们想覆盖test类中的所有方法,那么切入点表达式如下所示:
execution(* com.its.spring.test.*(…))
解释:
第一个*代表对方法权限和返回类型不限
com.its.spring.test是该方法的全类名
第二个*代表任意方法名
(…)代表任意参数
2. 案例说明
(1)环境准备
在项目的pom.xml文件中添加相关依赖
<!--实现AOP的依赖-->
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
在配置文件中开启AOP编程
<!-- 配置AspectJ支持aop -->
<aop:aspectj-autoproxy />
(2)代码实现
1.首先定义一个业务类AopService
package com.its.service;
import com.its.mapper.AopDao;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class AopService {
@Autowired
private AopDao aopDao;
public void add(String name){
System.out.println("增加"+name);
}
public void delete(String name){
System.out.println("删除"+name);
}
}
2.再定义一个切面类ServiceAopTest,用在业务类方法执行AOP编程
package com.its.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class ServiceAopTest {
// 前置增强
@Before("execution(* com.its.service.AopService.*(..))")
public void ts02() {
System.out.println("在所有方法前,增加的内容");
}
@Before("execution(* com.its.service.AopService.add(..))")
public void ts01() {
System.out.println("在add方法前,增加的内容");
}
@Before("execution(* com.its.service..*(..))")
public void ts03() {
System.out.println("在当前service包下的所有类的所有方法前执行");
}
// 后置增强
@After("execution(* com.its.service..*(..))")
public void ts04() {
System.out.println("在当前service包下的所有类的所有方法后执行");
}
@After("execution(* com.its.service.AopService.*(..))")
public void ts05() {
System.out.println("在所有方法后,增加的内容");
}
@After("execution(* com.its.service.AopService.add(..))")
public void ts06() {
System.out.println("在add方法后,增加的内容");
}
// 返回后通知
@AfterReturning("execution(* com.its.service.AopService.*(..))")
public void returning() {
System.out.println("返回后通知");
}
//环绕通知
@Around("execution(* com.its.service..*(..))")
public Object t05(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("=====1====="); //前置
Object proceed = proceedingJoinPoint.proceed();
System.out.println("=====2====="); //后置
return proceed;
}
// 异常通知,方法发生异常时通知
@AfterThrowing("execution(* com.its.service.AopService.*(..))")
public void afterThrowing() {
System.out.println("异常通知");
}
}
注:该类需要使用 @Aspect 注解标识
3.执行测试代码
package com.its;
import com.its.service.AopService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring.xml"})
public class AopTest {
@Autowired
private AopService aopService;
@Test
public void test(){
aopService.add("李明");
}
@Test
public void test01(){
aopService.delete("李海");
}
}
4.结果如下