1,选择切点

切点:其实切点很好理解,就是你要在调用哪个方法之前、之后、正常返回之后、异常返回之后来切入对应的代码。所以可以理解为某一个方法就是一个切入点。
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("方法发生异常---->结果回滚");
    }
}