第四课:springboot实现aop对方法进行拦截使用

简介

关于spring的aop相信只要是java开发的可能没有用过但是出去面试的时间也一定会被问到过.但是在一整个项目中aop怎么用的可能有些人还真的就不是特别的清楚;可能因为项目比较复杂;很难吧部分aop功能的代码给摘出来;或者项目中就没有真的使用过.
项目demo下载

项目的结构

在这里插入图片描述

代码内容

1.pom文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.khy.boot</groupId>
  <artifactId>boot-aspect</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
   <parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.4.RELEASE</version>
	</parent>
  
   <properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<!--含有多个main 需要指定某一个启动class-->
		<start-class>com.khy.MainApplication</start-class>
	</properties>
	
	 <dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency> 
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.6</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.4</version>
		</dependency>
		<dependency>
			<groupId>commons-collections</groupId>
			<artifactId>commons-collections</artifactId>
		</dependency>
		<!--额外的配置内容 -->
		<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
		</dependency>			
  </dependencies>
  
	<build>
	    <plugins>
	        <plugin>
	            <groupId>org.springframework.boot</groupId>
	            <artifactId>spring-boot-maven-plugin</artifactId>
	        </plugin>
	    </plugins>
	</build>
</project>

其实pom文件里面本身基于springboot的 所以只需要添加额外的jar文件内容.

2.AspectController

里面是关于调用的方法的内容信息主要包含两部的接口内容
一个是http://localhost:8080/aspect/say?detail=aaa 这个是测试通过拦截切点是某个包路径下面的类中的所有的方法.

http://localhost:8080/aspect/sleep?time=100 这个主要是测试拦截切点是某个自定义注解的(因为也第一个aop的切点面 )

@RestController
@RequestMapping("/aspect")
public class AspectController {
	private static final Logger khy = LoggerFactory.getLogger("KHY");
	 
	@Autowired
	private UserService userService;
	/**
	 * http://localhost:8080/aspect/say?detail=测试小康康
	 * @param something
	 * @return
	 */
	@RequestMapping("/say")
	public String say(String detail){
		khy.debug("say 方法执行请求参数 detail={}",detail);
		String ret = userService.say(detail);
		khy.debug("say 方法执行响应内容 ret={}",ret);
		return "执行成功";
	}
	
	/**
	 * http://localhost:8080/aspect/sleep?time=100
	 * @param something
	 * @return
	 */
	@RequestMapping("/sleep")
	public String sleep(Long time){
		khy.debug("sleep 方法执行请求参数 time={}",time);
		userService.sleep(time);
		return "执行成功";
	}
	
}

3.UserServiceImpl

里面是对应实现的方法内容;
主要包含say(String detail) 和sleep(Long time) 两个方法
sleep(Long time) 方法上面是含有自定义注解的

@Service
public class UserServiceImpl implements UserService {

	@Override
	public String say(String detail) {
		try {
			Thread.sleep(1000L);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return detail+"已执行";
	}

	@AspectTest(description="自定义的注解内容")
	@Override
	public void sleep(Long time) {
		 System.out.println("执行sleep方法time="+time);
	}

4. AopAspect切面的相关配置内容

/**
 * aop 切面的相关配置内容;
 * @author kanghanyu
 * 
 * 		例如定义切入点表达式  execution (* com.sample.service.impl..*.*(..))
 *         execution()是最常用的切点函数,其语法如下所示:
 *         整个表达式可以分为五个部分:
 *         1、execution(): 表达式主体。 
 *         2、第一个*号:表示返回类型,*号表示所有的类型。
 *         3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
 *         4、第二个*号:表示类名,*号表示所有的类。
 *         5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。
 *
 */
@Component
@Aspect
@Order(1)//多个切面的时间一个执行的顺序 数值越小越早执行
public class AopAspect {
	
	private static final Logger logger = LoggerFactory.getLogger("KHY");

	  /**切面点 service包路径下面的所有的类中的所有的方法内容*/
    private final String POINT_CUT = "execution(* com.khy.service..*(..))";
    
    @Pointcut(POINT_CUT)
    private void pointcut(){}
    
    /**
     *   环绕通知: 
     *   环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,
     *   执行完毕是否需要替换返回值。 
     *   环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型 
     *   和 MethodInterceptor 里面实现invoke 方法的功能类似的;
     * @param proceedingJoinPoint
     * @return
     */
    @Around(value = POINT_CUT)  
    public Object doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint){  
    	String method = "";
    	Object ret = null;
        try {  
        	Signature signature = proceedingJoinPoint.getSignature();
        	method = signature.getDeclaringTypeName()+"."+signature.getName();
        	Object[] args = proceedingJoinPoint.getArgs();
        	logger.debug("环绕通知的目标方法名" + method);  
            //记录被调用的接口开始时间
            LogTimeUtils.start("Invoking method: " + method);
            ret = proceedingJoinPoint.proceed();  
            logger.debug("环绕通知的响应结果内容" +JSONObject.toJSONString(ret));  
        } catch (Throwable throwable) {  
            throwable.printStackTrace();  
        }finally {
			long elapseTime = LogTimeUtils.end();
			StringBuilder builder = new StringBuilder();
			builder.append(method).append("执行了");
			builder.append(elapseTime).append("ms");
			logger.debug("当前方法"+builder.toString());
		}
		return ret;
    }
}

5.基于切点是自定义注解的

/**
 * aop 切面的相关配置内容基于自定义注解的内容;
 * @author khy
 * @createTime 2019年10月12日下午4:53:08
 */
@Component
@Aspect
@Order(2)//多个切面的时间一个执行的顺序 数值越小越早执行
public class AnnotationAspect {
	
	private static final Logger logger = LoggerFactory.getLogger("KHY");

	  /**切面点是基于自定义注解的内容;*/
    private final String POINT_CUT = "@annotation(com.khy.config.AspectTest)";
    
    @Around(value = POINT_CUT)
    public Object doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint){  
    	String method = "";
    	Object ret = null;
        try {  
        	//获取通过注解内容的添加的内容;
        	String description = getDescription(proceedingJoinPoint);
        	logger.debug("通过自定义注解的aop拦截到的方法上面自定义注解的内容值是{" + description + "}");  
        	Signature signature = proceedingJoinPoint.getSignature();
        	method = signature.getDeclaringTypeName()+"."+signature.getName();
        	logger.debug("通过自定义注解的aop环绕通知的目标方法名" + method);  
            ret = proceedingJoinPoint.proceed();  
            logger.info("通过自定义注解的aop环绕通知的响应结果内容" +JSONObject.toJSONString(ret)); 
        } catch (Throwable throwable) {  
            throwable.printStackTrace();  
        }finally {
		}
		return ret;
    }  
    
    
    private String getDescription(ProceedingJoinPoint joinPoint)  throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String description = "";
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    description = method.getAnnotation(AspectTest.class).description();
                    break;
                }
            }
        }
        return description;
    }
}

执行的内容描述

private final String POINT_CUT = “execution(* com.khy.service…*(…))”;
拦截的是con.khy.service 包下面的类中的所有的方法内容

当我们调用 http://localhost:8080/aspect/say?detail=测试小康康
然后会走UserServiceImpl.say(String detail) 方法会被我们的 AopAspect里面的会被环绕通知给拦截;别的还有前置/后置/异常等通知内容都是大同小异,项目中常用的一般是around.所以别的拦截暂不提.有兴趣可以查一下贴到我的代码里面来
然后再环绕通知中

在这里插入图片描述

然后再目标方法执行之前计时开始;在 finally 代码块中计算结束计算总的耗时时长

AnnotationAspect 是自定义的注解
当请求http://localhost:8080/aspect/sleep?time=100 的实现调用
sleep方法内容,因为方法上面含有@AspectTest 注解内容;
然后同时也会被上面的AopAspect给拦截;所以执行当前方法会被 以上两个 aspect给拦截
其实后期可以根据service方法上的 @Transactional 的注解中的事务类型动态的选择数据源

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在SpringBoot实现AOP,需要进行以下步骤: 1. 导入AOP相关的包,可以在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ``` [1] 2. 编写一个Controller类,例如UserController。 3. 使用@Aspect注解实现一个切面类,对UserController中的所有方法进行切入。切面类需要使用@Component注解将其声明为一个Bean实例,这样Spring IOC容器才会为与切面匹配的Bean创建代理。 ```java @Component @Aspect public class MyAspect { // 切入点定义和通知方法实现 // ... } ``` [2 [3] 通过以上步骤,就可以在SpringBoot项目中实现AOP。切面类中的切入点定义和通知方法实现可以根据具体需求进行编写,用于在方法执行前、后或异常时执行特定的行为。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [SpringBoot环境下实现AOP](https://blog.csdn.net/m0_37754981/article/details/89024041)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [Spring boot实现aop](https://blog.csdn.net/qq_43599835/article/details/90721857)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值