SpringBoot面向切面编程(AOP)的示例

AOP面向切面编程也是Spring框架中一大特性,今天我们来简单体会一下。
本次实验是在SpringBoot框架下进行的。

首先介绍一下大体思路:

一、自定义一个注解Action
二、编写连接点,即要进行切面操作的方法。在需要进行切面操作的方法上加上Action注解来标识。
三、编写切面,在切面中我们需要定义切点(拦截注解为Action的方法),定义在切点的前后所进行的切面操作
四、编写配置类,开启AspectJ支持
五、进行测试

先还要在pom.xml中【导入依赖】:

	<!-- spring-aop -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-aop</artifactId>
		<version>5.1.9.RELEASE</version>
	</dependency>
	<!-- aspectj支持 -->
	<dependency>
		<groupId>org.aspectj</groupId>
		<artifactId>aspectjrt</artifactId>
		<version>1.9.4</version>
	</dependency>
	<dependency>
		<groupId>org.aspectj</groupId>
		<artifactId>aspectjweaver</artifactId>
		<version>1.9.4</version>
	</dependency>

一、自定义注解Action

spring现在支持用注解来标识需要进行切面操作的方法,所以用注解是更方便的。如何使用,我们来看。
自定义一个注解Annotation,命名为Action,命名是随意的。

package com.example.demo.aop;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//@Target的ElementType.METHOD指明了这个注解Action是一个只能定义在方法上的注解
@Target(ElementType.METHOD)
//指明该注解的生命周期
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Action {
	//定义注解的属性,注:这里不是接口里的方法,表明是一个String类型的name属性
	String name();
}

注解和接口有点相似,其实是不一样的,里面name是这个注解的属性,而在接口中我们称之为方法声明。

大家不需要纠结为什么注解Action中要定义一个属性name,这个是无所谓的,不定义也可以。
我们只用明白,这个注解只是定义的一个标记,日后凡是带有这个注解的方法就是要进行切面操作的。

二、编写Service的方法

在这里插入图片描述

package com.example.demo.service;


import org.springframework.stereotype.Service;

import com.example.demo.aop.Action;

@Service
public class TestAopService {
	@Action(name = "注解式的action")
	public void print() {
		System.out.println("正在进行TestAopService的业务操作print。。。");
	}
	
	//这个方法就不拦截了
	public void show() {
		System.out.println("正在进行TestAopService的业务操作show。。。");
	}
}

print方法是我们需要进行切面操作的,所以我给它加上一个注解@Action
而show方法我们不拦截它,那我们就不带注解

三、编写切面

Action接口和切面的类都在aop包下:
在这里插入图片描述
编写切面是关键的一步

package com.example.demo.aop;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import javassist.bytecode.SignatureAttribute.MethodSignature;

//声明这是一个切面类,并将其放到Spring容器中,成为一个Bean
@Aspect
@Component
public class LogAspect {
	
	//需要建立一个切点,切点是没有方法体的
	@Pointcut("@annotation(com.example.demo.aop.Action)")
	public void annotationPointcut() {};
	
	//然后围绕切点,定义一些操作
	@Before("annotationPointcut()")
	//参数JoinPoint用来接受连接点方法的各种信息,这里连接点是TestAopService类中的print方法
	public void before(JoinPoint joinPoint) {
		//用连接点获得方法签名然后获得方法名
		String name = joinPoint.getSignature().getName();
		System.out.println("连接点" + name + "准备启用了:");
	}
}

解释一下:
用@Pointcut注解我们定义了一个切点,里面的参数是拦截规则。
说通俗点,就是凡是带有Action注解的方法,都算我们的切点! 这应该很好理解了
切点方法是不需要写方法体的,因为切点只是一个标记点,写方法体没有意义。

然后下面@Before注解标识的方法:就是在切点方法执行前,先做的一个方法。
说通俗点,凡是带Action注解的方法执行之前,都要先执行一下我定义的before方法!

因为带Action注解的都是切点,而before注解是在切点前做的操作!到这儿应该就很清楚了。
还有一个@After注解是一回事。

最后,我们的切面它也是一个Bean,所以我们需要将其注明为Componnent

四、编写配置类

在这里插入图片描述
SpringBoot中可以有多个配置类,我们在com.example.demo.configuration包下加入一个配置类AopConfig:

package com.example.demo.configuration;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan("com.example.demo.aop")
@EnableAspectJAutoProxy//开启AspectJ
public class AopConfig {
	
}

它就一个作用:开启开启Spring对AspectJ支持

@ComponentScan(“com.example.demo.aop”)这句话是为了扫描aop包下的logAspect切面,但实际上在SpringBoot中这句话不要也可以,因为SpringBoot程序启动的时候,就已经会自动扫描主包以下的所有子包了,将所有的Bean都会注册进容器,所以这里写这个扫描有点多此一举了。

五、测试

新建一个Junit测试

package com.example.demo;

import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.example.demo.service.TestAopService;

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestAop {
	@Autowired
	TestAopService testAopService;
	@Test
	public void testAop() {
		testAopService.print();
		System.out.println("接着调用show方法:");
		testAopService.show();
	}
}

运行结果:
在这里插入图片描述
我们发现,“连接点print准备启用了”这个输出正是before方法中的输出,随后就执行了切点:print方法,证明我们的切面操作实现成功。
再看看后面的show方法,show方法运行之后,只有自己的业务操作,并没有before方法的输出,这是因为show方法不满足切点的条件,它并没有带Action注解,所以它不会执行切点的before方法。

【总结】:
AOP中涉及很多抽象的概念,比如:切点、连接点、切面等等。我不建议一开始就去研究这些抽象的词汇。说白了,面向切面编程是什么?就是在某一类方法(切点)前面或后面(@before, @after)加上一些特定的操作(before方法, after方法)。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot 提供了很好的支持来实现面向切面编程面向切面编程AOP)是一种编程范式,它允许将横跨多个业务逻辑的功能(例如日志记录、事务管理等)从应用程序的核心业务逻辑中分离出来,以提高代码的可重用性、模块化和可维护性。 在 Spring Boot 中,你可以使用 Spring AOP 来实现面向切面编程。Spring AOP 基于代理模式,通过在目标对象上动态生成一个代理对象来实现切面功能。Spring AOP 提供了很多注解来定义切面、切入点、通知等。 下面是一个简单的面向切面编程示例,它演示了如何在 Spring Boot 中使用 AOP 记录方法的执行时间: 1. 定义一个切面类,使用 @Aspect 注解标记,定义一个切入点,使用 @Pointcut 注解标记: ``` @Aspect @Component public class LogAspect { @Pointcut("execution(* com.example.demo.service.*.*(..))") public void servicePointcut() { } @Around("servicePointcut()") public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); Object proceed = joinPoint.proceed(); System.out.println(joinPoint.getSignature().getName() + " executed in " + (System.currentTimeMillis() - startTime) + "ms"); return proceed; } } ``` 2. 在应用程序的启动类上添加 @EnableAspectJAutoProxy 注解来启用 AOP: ``` @SpringBootApplication @EnableAspectJAutoProxy public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 这样,在调用 com.example.demo.service 包下的任何方法时,LogAspect 类中定义的 logExecutionTime 方法都会被调用,记录方法的执行时间。 以上是一个简单的面向切面编程示例。在实际应用中,你可以使用 AOP 来实现很多功能,例如事务管理、安全控制等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值