一、AspectJ概述

AspectJ是一个面向切面的框架,它扩展了Java语言、定义了AOP语法,能够在编译期提供代码的织入,它提供了一个专门的编译期用来生成遵守字节编码规范的Class文件。

@Aspect是AspectJ 5新增的功能,使用JDK 5.0注解技术和正规的AspectJ切点表达式语言描述切面。因此在使用@Aspect之前,需要保证所使用的JDK是5.0或更高版本,否则将无法使用注解技术。

Spring通过集成AspectJ实现了以注解的方式定义切面,大大减轻了配置文件的工作量。此外,因为Java的反射机制无法获取方法参数名,Spring还需要利用轻量级的字节码处理框架asm(已集成在Spring Core模块中)处理@AspectJ中所描述的方法参数名。

二、@Aspect(定义切面)、@Before(前置增强)、@AfterReturning(后置增强)注解配置切面

1、使用注解定义切面以实现日志切面功能,如下

package edu.cn.service;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.util.Arrays; @Aspect
public class UserServiceLogger {
private static final Logger log = LoggerFactory.getLogger(UserServiceLogger.class); @Before("execution(* edu.cn.service.UserService.*(..))")
public void before(JoinPoint jp){
log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName()
+ "方法。方法入参:" + Arrays.toString(jp.getArgs()));
} @AfterReturning(pointcut = "execution(* edu.cn.service.UserService.*(..))", returning = "returnValue")
public void afterReturning(JoinPoint jp, Object returnValue){
log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName()
+ "方法。方法返回值:" + returnValue);
} } 

@Aspect等注解在aspectjweaver依赖下。在上述代码中,使用@Aspect注解将UserServiceLogger定义为切面,并且使用@Before注解将before()方法定义为前置增强,使用@AfterReturning方法将afterReturning()方法定于为后置增强

为了能够获得当前连接点的信息,在增强方法中添加了JoinPoint类型的参数,Spring会自动注入该实例。

对于后置增强,还可以定义一个参数用于接受目标方法的返回值。需要注意的是,必须在@AfterReturning注解中通过returning属性指定该参数的名称,Spring会将目标方法的返回值赋值给指定名称的参数。

1.1、对于相同的切入点要求,可以统一定义,以便于重用和维护,如下

package edu.cn.service;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.util.Arrays; @Aspect
public class UserServiceLogger {
private static final Logger log = LoggerFactory.getLogger(UserServiceLogger.class); @Pointcut("execution(* edu.cn.service.UserService.*(..))")
public void pointcut(){} @Before("pointcut()")
public void before(JoinPoint jp){
log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName()
+ "方法。方法入参:" + Arrays.toString(jp.getArgs()));
} @AfterReturning(pointcut = "pointcut()", returning = "returnValue")
public void afterReturning(JoinPoint jp, Object returnValue){
log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName()
+ "方法。方法返回值:" + returnValue);
} }

切入点表达式可以使用@Pointcut注解来表示,而切入点签名则需要通过一个普通的方法定义来提供,如上述代码中的pointcut()方法,作为切入点签名的方法必须返回void类型。定义好切入点后,就可以使用“pointcut()”签名进行引用

2、切面定义完后,还需要在Spring配置文件中完成织入工作,如下

只需在配置文件中添加<aop:aspectj-autoproxy/>元素,就可以启用对于@AspectJ注解的支持,Spring将自动为匹配的Bean创建代理

为了注册定义好的切面,还需在Spring配置文件中声明UserServiceLogger的一个实例。如果不需要被其他Bean引用,可以不指定id属性

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <context:component-scan base-package="service,dao"/>
<bean class="edu.cn.service.UserServiceLogger"></bean>
<aop:aspectj-autoproxy/>

</beans>

三、@AfterThrowing(异常抛出增强)、@After(最终增强)、@Around(环绕增强)注解进行增强的配置

1、@AfterThrowing(异常抛出增强)

使用@AfterThrowing注解可以定义异常抛出增强。如果需要获取抛出的异常,可以为增强方法声明相关类型的参数,并通过@AfterThrowing注解的throwing属性指定该参数名称,Spring会为其注入从目标方法抛出的异常实例,如下

package edu.cn.service;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; @Aspect
public class ErrorLogger {
private static final Logger log = LoggerFactory.getLogger(ErrorLogger.class); @AfterThrowing(pointcut = "execution(* edu.cn.service.UserService.*(..))", throwing = "e")
public void afterThrowing(JoinPoint jp, RuntimeException e){
log.error(jp.getSignature().getName() + "方法方法异常:" + e);
}
}

2、@After(最终增强)

使用@After注解可以定义最终增强

package edu.cn.service;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; @Aspect
public class AfterLogger {
private static final Logger log = LoggerFactory.getLogger(AfterLogger.class); @After("execution(* edu.cn.service.UserService.*(..))")
public void afterLogger(JoinPoint jp){
log.info(jp.getSignature().getName() + "方法结束执行。");
}
}

3、@Around(环绕增强)

使用@Around注解可以定义环绕增强。通过为增强方法声明ProceedingJoinPoint类型的参数,可以获得连接点信息。通过它的proceed()方法可以调用真正的目标方法,从而实现对连接点的完全控制。

package edu.cn.service;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.util.Arrays; @Aspect
public class AroundLogger {
private static final Logger log = LoggerFactory.getLogger(AroundLogger.class); @Around("execution(* edu.cn.service.UserService.*(..))")
public Object aroundLogger(ProceedingJoinPoint jp) throws Throwable {
log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName()
+ "方法。方法入参:" + Arrays.toString(jp.getArgs()));
try {
Object result = jp.proceed();
log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName()
+ "方法。方法返回值:" + result);
} catch (Throwable e) {
log.error(jp.getSignature().getName() + "方法发生异常:" + e);
throw e;
}finally {
log.info(jp.getSignature().getName() + "方法结束执行。");
}
}
}

Spring使用注解实现AOP的更多相关文章

  1. Spring之注解实现aop(面向切面编程)

    1:Aop(aspect object programming)面向切面编程,名词解释:    1.1:功能:让关注点代码与业务逻辑代码分离    1.2:关注点        重复代码就叫做关注点  ...

  2. 阶段3 2.Spring_08.面向切面编程 AOP_9 spring基于注解的AOP配置

    复制依赖和改jar包方式 src下的都复制过来. 复制到新项目里了 bean.xml里面复制上面一行代码到下面.把aop改成context. 配置spring容器创建时要扫描的包 Service的配置 ...

  3. Spring 基于注解的AOP实现

    在本文开始之前,我要引入一张图,这张图的来源 https://blog.csdn.net/chenyao1994/article/details/79708496 ,版权归原作者所有,我借鉴了原作者的 ...

  4. Spring基于注解配置AOP

    D:\Java\IdeaProjects\JavaProj\SpringHelloWorld\src\aop.xml <?xml version="1.0" encoding ...

  5. 基于spring@aspect注解的aop实现

    第一步:编写切面类 package com.dascom.hawk.app.web.tool; import org.aspectj.lang.JoinPoint; import org.aspect ...

  6. Spring Annotation注解进行aop的学习

    使用Maven管理项目,pom文件为: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=" ...

  7. Spring的注解方式实现AOP

    Spring对AOP的实现提供了很好的支持.下面我们就使用Spring的注解来完成AOP做一个例子. 首先,为了使用Spring的AOP注解功能,必须导入如下几个包.aspectjrt.jar,asp ...

  8. 使用Spring的注解方式实现AOP

    Spring对AOP的实现提供了很好的支持.下面我们就使用Spring的注解来完成AOP做一个例子. 首先,为了使用Spring的AOP注解功能,必须导入如下几个包.aspectjrt.jar,asp ...

  9. spring学习笔记二 注解及AOP

    本节需要导入spring-aop包 注解 使用注解的目的是为了代替配置,在使用注解时,省略键时,则是为value赋值. 扫描某个包下的所有类中的注解 <?xml version="1. ...

随机推荐

  1. 2019牛客暑期多校训练营(第二场)J

    题意 给一个长度为1e9的只包含1和-1的数列,1的个数不超过1e7,计算有多少对\((l,r)\)满足\(\sum_{i=l}^r a[i]>0\) 分析 dp求出每段连续的1最右端为右端点的 ...

  2. IT公司技术博客地址

    IT公司技术博客 美团点评技术团队今日头条技术博客Tencent ISUX DesignTGideas-腾讯互动娱乐创意设计团队>AlloyTeam | 腾讯全端 AlloyTeam 团队 Bl ...

  3. mybatis oracle mysql 批量插入时的坑爹问题--需谨记

    mybatis oracle mysql 批量插入一.oracle的批量插入方式insert into db(id, zgbh, shbzh) select '1', '2', '3' from du ...

  4. SpringMVC接收请求参数和页面传参

    接收请求参数: 1,使用HttpServletRequest获取 @RequestMapping("/login.do") public String login(HttpServ ...

  5. 7 vi 编辑器

    1.vim编辑器的工作模式 命令模式,插入模式,可视化模式,扩展命令模式. 2.命令模式 2.1.光标定位 hjkl:小键盘上下左右移动 0 $:行头.行尾 gg G:第一行.最后一行 30G:进入第 ...

  6. mysql 存储过程中使用动态sql语句

    Mysql 5.0 以后,支持了动态sql语句,我们可以通过传递不同的参数得到我们想要的值 这里介绍两种在存储过程中的动态sql: set sql = (预处理的sql语句,可以是用concat拼接的 ...

  7. UI的流畅度优化

    Android中所有的界面绘制工作都是在UI线程中进行的,提高UI流畅度的最核心根本在于释放UI线程.即:不在主线程中做耗时的操作. 很多人都知道,耗时的操作要放到子线程中去做,比如访问网络,比如读写 ...

  8. CentOS6.8安装Oracle11g

    ===== 这中间还有很多细节问题该文档中并没有说明和指出: 1.如/tmp目录必须单独分出来,不然oracle在以后的使用中会逐渐变慢 2.官网说的512M内存即可,这里纠正下,如果只是测试安装那还 ...

  9. Selenium 2自动化测试实战31(跳过预期和预期失败)

    跳过预期和预期失败 在运行测试时,有时需要直接跳过某些测试用例,或者当用例符合某个条件时跳过测试,又或者直接将测试用例设置为失败.unittest提供了实现这些需求的装饰器. --unittest.s ...

  10. rocketmq的windows版客户端的启动步骤

    一.下载RocketMQ首先,我们去下载RocketMQ,RocketMQ 是一个开源的东西,可以去github上面下载,地址是:https://github.com/alibaba/RocketMQ ...