一、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. luoguP2863 [USACO06JAN]牛的舞会The Cow Prom

    P2863 [USACO06JAN]牛的舞会The Cow Prom 123通过 221提交 题目提供者 洛谷OnlineJudge 标签 USACO 2006 云端 难度 普及+/提高 时空限制 1 ...

  2. easyUI datagrid中checkbox选中事件以及行点击事件,翻页之后还可以选中

    DataGrid其中与选择,勾选相关 DataGrid属性:singleSelect boolean 如果为true,则只允许选择一行. false ctrlSelect boolean 在启用多行选 ...

  3. Selenium 的页面加载以及几种等待的问题

    1. PageLoadStrategy : 当调用driver.get("https://xxxx.xxx.xxx")来访问某页面时,get方法通常会阻塞浏览器直到页面完全加载后才 ...

  4. c++ 派生类的构造函数 与 基类构造函数的关系

    <面向对象程序设计基础(第二版>李师贤等,第254页:C++语言的基本规则是:创建一个派生类的对象时,如果基类带有构造函数,则先调用基类的构造函数,然后才调用派生类的构造函数. <T ...

  5. 在mac上如何用safari调试ios手机的移动端页面

    第一步:打开iphone手机的开发者模式,流程是:[设置]->[Safari]->[高级]->开启[Web检查器] ,如图1.图2 图1 图2第二步:打开Mac上Safari的开发者 ...

  6. Python编程中NotImplementedError的使用

    Python编程中raise可以实现报出错误的功能,而报错的条件可以由程序员自己去定制.在面向对象编程中,可以先预留一个方法接口不实现,在其子类中实现.如果要求其子类一定要实现,不实现的时候会导致问题 ...

  7. tp5中很牛皮的一句sql语句,三个条件(两个不确定条件,一个硬性条件)

    $result = Db::table('xxxxxx')   // 表名 ->alias('g') ->join('xxxxx_2 u','g.user_id = u.id') -> ...

  8. 微信小程序之数据缓存和数据获取

    在一个微信小程序中 避免不了的就是在多个页面获取数据,而且还会在不同的页面获取相同的数据,写起来就是一大坨,看着就不愉快 那么今天说一下 这个方法 wx.setStorage(OBJECT) 这个方法 ...

  9. SQL Server分页的存储过程写法以及性能比较

    ------创建数据库data_Test ----- create database data_Test GO use data_Test GO create table tb_TestTable - ...

  10. LC 272. Closest Binary Search Tree Value II 【lock,hard】

    Given a non-empty binary search tree and a target value, find k values in the BST that are closest t ...