AOP是一种区别于OOP的编程思想,具体概念想必大家都懂,废话不多说,直接进入正题
AOP的实现和配置有多种方式,如题,今天我们先来最简单,最高效的编写方式。
演示用的框架是spring boot:
1、导入pom依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、在启动类上添加@EnableAspectJAutoProxy注解,该注解的作用是使@Aspect注解生效;
如上,配置就是这么简单,接下来编写切面类。
3、编写切面类:有两种编写方式
1)Spring + AspectJ:基于注解,通过AspectJ execution表达式拦截方法
-- 如下,先编写一个普通的类,类里边有一个普通的登录方法(这里我们用controller类,待会直接使用http请求测试aop)
package com.happy.smartspider.controller;
import com.happy.smartspider.service.TestAop;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
@CrossOrigin
@RequestMapping("/test")
public class TestAopController {
@GetMapping("/login/{age}")
public void login(@PathVariable int age) {
System.out.println("登录成功!!!");
}
}
-- 编写切面类:此处先编写一个环绕增强
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoginPermissonAop {
@Around("execution(void com.happy.smartspider.service.impl.TestAopImpl.login(..))")
public Object around(ProceedingJoinPoint point) throws Throwable {
// 只有一个参数,直接获取
int age = (int)point.getArgs()[0];
if(age < 10) {
System.out.println("用户年龄未满10周岁,不能登录该系统...");
return null;
}else {
return point.proceed();
}
}
}
-- 类编写完毕,我们来测试一下,直接http请求:
http://localhost:8090/test/login/11
http://localhost:8090/test/login/9
看了上面的例子,你还觉得aop很难,配置很麻烦吗,是的,你没有看错,简直超级无敌简单。有些同学可能会说不简单啊,这个切点表达式怎么配,看起来好麻烦的样子,其实这个也很简单,先看一个例子:
execution(* com.happy.smartspider.service.impl.*.*(..)):
-- 1、第一个*表示任意类型返回值;
-- 2、第二个*表示com.happy.smartspider.service.impl包下的所有类;
-- 3、第三个*表示符合第二点要求的类中的任意方法;
-- 4、括号里边的'..'表示参数类型。
像示例中的写法:execution(void com.happy.smartspider.service.impl.TestAopImpl.login(int),表示的就是com.happy.smartspider.service.impl.TestAopImpl类中的参数类型为int,返回值类型为void的login()方法,对比着看,是不是感觉很简单。
接下来,再来一个超级无敌更简单的方式:有些同学不是觉得切点表达式难写么,没事,接下来的方法让你远离它:
2)Spring + AspectJ:基于注解,通过AspectJ @annotation表达式拦截方法
-- 首先,我们先定义一个注解类,这个注解是添加在需要被拦截的方法上面,这样就免去了编写繁琐的切点表达式,只需一个注解搞定,其他什么都不需要考虑:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HasPermisson {
}
-- 然后,切面类的其他定义和上面相同,只需将@Around注解中的参数改成@annotation即可:
@Around("@annotation(com.happy.smartspider.model.annotation.HasPermisson)")
-- 最后在目标类上添加定义的注解即可。
这种方式是不是非常简单方便呢,总结一下:定义注解--》定义切面--》目标类上添加注解。只需三步,就可以开开心心使用切面编程了。
说两点需要注意的地方:
1、此处定义的注解,只能在一个切面类中出现,why?如果出现在两个切面中,那就不知道具体要去执行那个切面了,导致功能无法正常使用;
2、使用第一种方法的时候,如果我们无法确定切点表达式是否正确,我们只需要确定在目标方法边上有没有如下标志(前提是开发工具是idea)
并且点击该标志能不能链接到正确的切面类中。如果都正常,那我们的工作就做完了,接下来动手试试吧!