本文介绍通过注解@AspectJ实现Spring AOP,这里要重点说明一下这种方式实现时所需的包,因为Aspect是第三方提供的,不包含在spring中,所以不能只导入spring-aop的包,为了安全起见我导入的包有(我是maven方式添加依赖):

步骤如下:

一、创建连接点

spring是方法级别的拦截器,所以连接点就是某个类中的某个方法,从动态代理的角度来看就是将要拦截的方法织入AOP通知。

1⃣️创建一个接口

 public interface EmployeeService {

     public void getEmployeeInfo(Employee employee);

     public void getEmployeeSex(Employee employee);
}

这个接口中提供了两个方法,后续会用来测试连接点的概念,因为只有将方法织入到AOP才会执行完整的拦截流程。

2⃣️创建接口实现类,增加注解@Component

 @Component
public class EmployeeServiceImpl implements EmployeeService { @Override
public void getEmployeeInfo(Employee employee) {
System.out.println("name:" + employee.getUsername() + ";sex:" + employee.getSex());
} @Override
public void getEmployeeSex(Employee employee) {
System.out.println("性别:"+employee.getSex());
}
}

二、创建切面

创建好了连接点之后就可以创建切面了,它就相当于是一个拦截器,在spring中只要使用@Aspect注解一个类,spring ioc容器就会将它视为一个切面处理。

 package com.hyc.aop.aspect;

 import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.DeclareParents;
import org.aspectj.lang.annotation.Pointcut; import com.hyc.pojo.Employee; /**
* 定义一个切面
*
* @Aspect 该注解表示这个类就是一个切面了
*/
@Aspect
public class EmployeeAspect { /**
* 定义一个切点,通知aop什么时候启动拦截并织入对应流程
* 注意以下几点:
* 1、方法返回类型* 和方法之间有空格
* 2、在下面的四个方法中引用这个切点时方法名要加括号
* 3、execution正则表达式中的方法就是一个连接点,将代理对象和切面相连,如果不定义这个连接点,则不会将代理对象的方法和切面相连
*/
@Pointcut("execution(* com.hyc.aop.aspect.EmployeeServiceImpl.getEmployeeInfo(..))")
public void getInfo() { } @Before("getInfo()")
public void before() {
System.out.println("before:代理方法执行之前");
} @After("getInfo()")
public void after() {
System.out.println("after:代理方法执行完毕");
} @AfterReturning("getInfo()")
public void afterReturning() {
System.out.println("afterReturning:代理方法执行完毕,执行成功");
} @AfterThrowing("getInfo()")
public void afterThrowing() {
System.out.println("afterThrowing:代理方法执行完毕,执行过程出现异常");
}
}

上面的代码中红色加粗部分所代表的意思如下:

  • @Aspect注解:告诉spring,这个类是一个切面;
  • @Pointcut注解:定义一个切点,并告诉AOP什么时候启动拦截并织入对应流程;
  • @before、@after、@afterReturning、@afterThrowing分别是四种通知,它们可以引用之前定义的切点,也可以有自己的切点;

有必要解释一下定义切点注解@Pointcut中的内容:

 @Pointcut("execution(* com.hyc.aop.aspect.EmployeeServiceImpl.getEmployeeInfo(..))") 

在上面的注解中,定义了execution的正则表达式,spring是通过这个正则表达式判断是否需要拦截你所定义的方法,即被代理对象的方法。

  • execution:代表执行方法的时候会触发;
  • *:代表方法的返回类型任意;
  • com.hyc.aop.aspect.EmployeeServiceImpl:被代理类的全限定名,注意它和前面的返回类型*之间有一个空格;
  • getEmployeeInfo:被拦截方法名称;
  • (..):方法中的参数,类型任意;

通过上面的描述,上述注解及内部正则表达式的意思就是:全限定名为com.hyc.aop.aspect.EmployeeServiceImpl的类中的getEmployeeInfo方法被当做一个切点,当程序执行这个方法的时候对它进行拦截,这样就能按照AOP通知的规则把这个方法织入流程中。

三、创建配置类,采用注解java配置

 /*
* 定义一个配置类,通过java配置的方式获取切面
*/
@Configuration
@ComponentScan(basePackages= {"com.hyc.aop.aspect","com.hyc.pojo"})
@EnableAspectJAutoProxy //自动代理,代替了动态代理的实现
public class AspectConfig {
//返回一个切面
@Bean
public EmployeeAspect getAspect() {
return new EmployeeAspect();
} }

这个配置就是之前介绍过的注解方式装配bean的配置方法,不过对AOP有效的注解是@EnableAspectJAutoProxy,从字面意思理解它是开启了切面自动代理功能,其实就是启用了AspectJ框架的自动代理,这样spring就会生成一个代理对象,进而使用AOP,其中的getAspect方法是生成了一个切面。

四、测试

完成了上面的配置之后,我就可以进行测试了,测试方法如下:

     @Test
public void testAopByConfig() {
@SuppressWarnings("resource")
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AspectConfig.class);
EmployeeService es = (EmployeeService) context.getBean(EmployeeService.class);
Employee employee = (Employee) context.getBean("employee");
es.getEmployeeInfo(employee);
employee = null;
es.getEmployeeInfo(employee);

上面的单元测试方法中红色部分:

第四行:首先是获取配置类的上下文,此时已经启动AspectJ的自动代理,并生成了一个切面;

第五行:通过上下文就能生成一个代理对象,如果被代理类有接口则采用jdk动态代理,否则就是CGLIB动态代理;

第七行:测试方法,因为employee不为空,所以可以正常返回,并执行afterReturning方法;

第八、九行:将employee设置为null,执行过程出现异常,所以会执行aferThrowing方法;

查看测试结果:

从上面的运行结果来看,完全符合刚开始的流程图:

1、首先执行before方法;

2、执行被代理对象的方法;

3、执行完被代理对象方法后,不管成功与否都会执行after方法;

4、如果被代理对象的方法正常返回,则执行afterReturning方法,如果返回异常,则执行afterTrowing方法(结果中的afterException是书写错误,其实都一个意思啦

Spring AOP(二)--注解方式的更多相关文章

  1. spring aop 使用注解方式总结

    spring aop的注解方式:和xml的配置方式略有区别,详细如下: 1.首先还是建立需要的切面类:切面类里面定义好切点配置,以及所有的需要实现的通知方法. /** * */ package com ...

  2. spring AOP自定义注解方式实现日志管理

    今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...

  3. Spring AOP的注解方式实现

    spring也支持注解方式实现AOP,相对于配置文件方式,注解配置更加的轻量级,配置.修改更加方便. 1.开启AOP的注解配置方式 <!-- 开启aop属性注解 --> <aop:a ...

  4. perf4j+spring+aop 配置 注解方式

    今天将perf4j基于spring aop方式进入了接入,接入方法还是比较简单.具体配置如下: logback.xml <!--perf4j配置--> <appender name= ...

  5. Spring AOP(注解方式)

    配置文件: xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.org ...

  6. 利用Spring AOP自定义注解解决日志和签名校验

    转载:http://www.cnblogs.com/shipengzhi/articles/2716004.html 一.需解决的问题 部分API有签名参数(signature),Passport首先 ...

  7. 跟着刚哥学习Spring框架--通过注解方式配置Bean(四)

    组件扫描:Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件. 特定组件包括: 1.@Component:基本注解,识别一个受Spring管理的组件 2.@Resposit ...

  8. (转)利用Spring AOP自定义注解解决日志和签名校验

    一.需解决的问题 部分API有签名参数(signature),Passport首先对签名进行校验,校验通过才会执行实现方法. 第一种实现方式(Origin):在需要签名校验的接口里写校验的代码,例如: ...

  9. spring AOP自定义注解 实现日志管理

    今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...

随机推荐

  1. typedef void (*funcptr)(void) typedef void (*PFV)(); typedef int32_t (*PFI)();

    看到以下代码,不明白查了一下: /** Pointer to Function returning Void (any number of parameters) */ typedef void (* ...

  2. PAT甲级——A1113 Integer Set Partition

    Given a set of N (>) positive integers, you are supposed to partition them into two disjoint sets ...

  3. <随便写>random函数

    import random random,randint(1,100)返回随机数 random.choice(list)从一个列表中随机选取一个元素返回 random.shuffle(list)将列表 ...

  4. PCA降维2

    前言 本文为模式识别系列第一篇,主要介绍主成分分析算法(Principal Component Analysis,PCA)的理论,并附上相关代码.全文主要分六个部分展开: 1)简单示例.通过简单的例子 ...

  5. QSerialPort类

    一.简介     QSerialPort类是Qt5封装的串口类,可以与串口进行通信.QSerialPortInfo是一个辅助类,提供串口的一些信息,如可用的串口名称,描述,制造商,序列号,串口16位产 ...

  6. 03.MyBatis的核心配置文件SqlMapConfig.xml

    SqlMapConfig.xml中配置的内容和顺序如下: properties(属性) settings(全局配置参数) typeAliases(类型别名) typeHandlers(类型处理器) o ...

  7. [转]C# 之泛型详解

    什么是泛型 我们在编写程序时,经常遇到两个模块的功能非常相似,只是一个是处理int数据,另一个是处理string数据,或者其他自定义的数据类型,但我们没有办法,只能分别写多个方法处理每个数据类型,因为 ...

  8. 为什么Java中的String是设计成不可变的?(Why String is immutable in java)

    There are many reasons due to the string class has been made immutable in Java. These reasons in vie ...

  9. 2016年深圳市服务业占GDP比重首次突破六成

    2016年深圳市服务业占GDP比重首次突破六成 中商产业研究院 中商情报网 2017-01-12 11:08 分享:     中商情报网讯 1月10日,深圳市财政委员会召开新闻发布会,就深圳市2016 ...

  10. 微信小程序chooseImage(从本地相册选择图片或使用相机拍照)

    一.使用API wx.chooseImage(OBJECT) var util = require('../../utils/util.js') Page({ data:{ src:"../ ...