切点:其实切点很好理解,就是你要在调用哪个方法之前、之后、正常返回之后、异常返回之后来切入对应的代码。所以可以理解为某一个方法就是一个切入点。
1、创建POJO
/**
* @version : 1.0
* @Author :xiaolin
* @Date: 2021/10/20 0020 - 10 - 20 - 16:16
* @Description: com.xl.spring.springaop.pojo
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String name;
private Short sex;
}
2、创建对应的切点
public interface UserService {
void add(User user);
}
@Service
public class UserServiceImpl implements UserService {
@Override
public void add(User user) {
System.out.println("添加用户["+user+"]到数据库");
throw new RuntimeException("添加出错");
}
}
2,创建切面
切面:切面是一个类,它的作用是当调用到对应的切点时,往切点中切入对应的代码。
1、导入jar包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
2、创建切面类
/**
* @version : 1.0
* @Author :xiaolin
* @Date: 2021/10/20 0020 - 10 - 20 - 16:25
* @Description: com.xl.spring.springaop.aspect
*/
@Aspect //表示当前类是一个切面
public class TranAspect {
@Before("execution(* com.xl.spring.springaop.service.impl.UserServiceImpl.add(..))")
public void before() {
System.out.println("调用方法之前切入的代码---->获取连接");
}
@After("execution(* com.xl.spring.springaop.service.impl.UserServiceImpl.add(..))")
public void after() {
System.out.println("调用方法之后切入的代码---->方法执行完成");
}
@AfterReturning("execution(* com.xl.spring.springaop.service.impl.UserServiceImpl.add(..))")
public void afterReturning() {
System.out.println("方法正常返回---->结果提交");
}
@AfterThrowing("execution(* com.xl.spring.springaop.service.impl.UserServiceImpl.add(..))")
public void afterThrow() {
System.out.println("方法发生异常---->结果回滚");
}
}
上面代码中的@Aspect注解来定义对应的类是一个切面,其他四个注解的含义:
- @Before:在切点调用之前执行的方法,被称为"前置通知"
- @After:在切点调用之后执行的方法,被称为"后置通知"
- @AfterReturning:在切点正常返回之后执行的方法,被称为"返回通知",如果返回void,则返回通知为null。
- @AfterThrowing:如果切点存在异常,则在切点抛出异常后执行,被称为"异常通知"
3,连接点
连接点在AOP中的作用其实就是用来判断是否要拦截对应的方法。
比如@Before("execution(* com.xl.spring.springaop.service.impl.UserServiceImpl.add(..))")
- execution:表示执行方法的时候触发
- *:表示方法可以是任意返回类型
- com.xl.spring.springaop.service.impl.UserServiceImpl:表示对应的方法提供者的全限定名(就是切点所在的类)
- add:表示被拦截的方法名
- (..):表示任意类型的参数
4,测试运行
1、创建一个配置类
/**
* @version : 1.0
* @Author :xiaolin
* @Date: 2021/10/20 0020 - 10 - 20 - 16:46
* @Description: com.xl.spring.springaop.config
*/
@ComponentScan("com.xl.spring.springaop")
@Configuration
@EnableAspectJAutoProxy //表示spring启动AspectJ框架自动代理
public class AopConfig {
}
2、测试
public class AopTest {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(AopConfig.class);
User user = User.builder().id(1).name("宋智孝").sex((short) 2).build();
UserService userService = ac.getBean(UserService.class);
userService.add(user);
}
}
5,简化连接点操作
上面切面中的连接点可以单独抽取出来,不用每个方法都重写一遍。
@Component
@Aspect //表示当前类是一个切面
public class TranAspect {
@Pointcut("execution(* com.xl.spring.springaop.service.impl.UserServiceImpl.add(..))")
public void cut(){}
@Before("cut()")
public void before() {
System.out.println("调用方法之前切入的代码---->获取连接");
}
@After("cut()")
public void after() {
System.out.println("调用方法之后切入的代码---->方法执行完成");
}
@AfterReturning("cut()")
public void afterReturning() {
System.out.println("方法正常返回---->结果提交");
}
@AfterThrowing("cut()")
public void afterThrow() {
System.out.println("方法发生异常---->结果回滚");
}
}