面向切面编程(AOP),该种方式主要是为了弥补面向对象编程(OOP)的不足,通过配置切面以及关注点、通知等我们可以在程序的任意位置对我们的代码进行增强(执行一些代码),AOP是Spring的特性之一,通常我们使用AOP来实现日志的补记录以及实现一些声明式的事务等。
接下来,通过一个简单的例子来测试一下AOP如何使用:
1、pom.xml文件的依赖如下
<dependencies> <!--1.单元测试的依赖--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!--2.aop的依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!--3.cglib动态代理的依赖--> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version> </dependency> <!--4.web依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--5.小辣椒--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies>
2、application.yml(springboot)的配置文件内容如下:
其中,server.port代表端口号(tomcat的端口号)
其他内容为自定义的内容,可通过@Value注解获取到内容值
${name}为使用表达式获取当前yml文件中对应的name的值
3、定义用于返回的类(使用RestController,返回json数据),代码如下:
@Data @NoArgsConstructor @AllArgsConstructor public class Result { private boolean success; private String msg; }
4、定义自己的Service类(模拟业务场景),代码如下:
@Service public class JieService { public void todo(){ System.out.println("这是一个Service方法的调用!"); } }
@Service :把该类注入Spring容器中,若需要使用,则通过@Autowired 注解获取
5、定义一个Controller类(控制类,模拟处理用户的请求),代码如下:
@RestController public class JieController { @Autowired private JieService jieService; // 使用yml配置文件中的参数 @Value("${content}") public String content; @RequestMapping("/hello") public Result hello(){ jieService.todo(); return new Result(true,content); } }
其中,@Autowired 注解则获取到Spring容器中我们通过@Service 注解注入的对象
@RestController 注解为标记返回的数据为json格式
@Value 注解则获取到application.yml 文件中对应的参数名的值,这里@Value(${content})的写法跟在yml中去到定义的值一样
6、配置一个切面类,且注入Spring容器中,通过@Aspect 标记为切面类、@Component 注入Spring容器中,并且添加一些测试方法,代码如下:
@Component // 注册到spring容器中 @Aspect // 标志为切面类 public class ServiceAdvice { /** * 解读: * execution为固定写法 * public * com.jieku.service..*.*(..) * 第一个 * 表示所有的返回参数 * 之后代表切入点的包名,其后跟着两个点(.)表示当前包及其所有的子包 * 两个点后的* 代表所有的类 =》 综合两个点加上* ..* 表示当前包及其所有子包的所有类 * 之后的点个人理解为调用方法,点后的*表示所有的方法,之后括号中的两个点.表示任意的参数个数 * 总的解答:拦截com.jieku.service的当前包及其子包中的所有类(任意的返回参数类型)的所有方法的调用(任意参数列表) */ @Pointcut("execution(public * com.jieku.service..*.*(..))") public void good(){} @Before("good()") public void before(){ System.out.println("之前拦截到了,并且执行了!"); } @After("good()") public void after(){ System.out.println("之后也拦截到了,并且执行了!"); } /** * @Ponitcut:表示切入点,理解为找到需要增强的方法执行我们定义的增强的代码 * 通知: * @Before:前置通知,方法执行前执行该通知 * @After:后置通知,方法执行完成之后执行该通知 * @Around:环绕通知 * @AfterReturning:在返回之后执行该通知 * @AfterThrowing:在抛出异常后执行该通知 */ }
7、执行效果如下:
在页面上输入:localhost:8080/hello,执行效果如下:
8、补充:启动类以及项目结构图
启动类代码如下:
@SpringBootApplication public class JieApplication { public static void main(String[] args) { SpringApplication.run(JieApplication.class); } }
项目结构图如下:
9、后台的运行结果:
至此,简单测试成功!