Spring对AspectJ的支持

1.AspectJ介绍及Pointcut注解应用

(1)AspectJ

  • @AspectJ的风格类似纯java注解的普通java类
  • Spring可以使用AspectJ来做切入点解析
  • AOP的运行时仍旧是纯的Spring AOP,对AspectJ的编译器或者织入无依赖性

(2)Spring中配置@AspectJ

  • 对@AspectJ支持可以使用XML或者Java风格的配置
  • 确保AspectJ的aspectjweaver.jar库包含在应用程序(版本1.6.8或者更高版本)的classpath中

java注解方式:

@Configuration
@EnableAspectJAutoProxy
public class AppConfig{}

xml方式:

<aop:aspectj-autoproxy/>

(3)@Aspect注解的使用

  • @AspectJ切面使用@Aspect注解配置,任何拥有@Aspect的bean将被Spring自动识别并应用
  • 用@Aspect注解的类可以有方法和字段,他们也可能包括切入点(pointcut),通知(advice)和引入(introduction)声明
  • @Aspect注解是不能够通过类路径自动检测发现的,所以需要配合使用@Component注释或者在xml配置bean

   1)在xml中配置bean

<bean id="myAspect" class="org.xyz.NotVeryUsefulAspect"><!--configure properties of aspect here as nomal-->
</bean>

   2)使用@Component注释

package org.xyz;
import org.sapectj.lang.annotation.Aspect;@Aspect
public class NotVeryUsefulAspect{
}
  • 一个类中的@Aspect注解标识它为一个切面,并且将自己从自动代理中排除,否则会出现死循环

(4)pointcut

  • 一个切入点通过一个普通的方法定义来提供,并且切入点表达式使用@Pointcut注解,方法返回类型必须为void
  • 定义一个名为‘anyOldTransfer’,这个切入点将匹配任何名为“transfer”的方法的执行
@Pointcut("execution(* transfer(..))")//the pointcut expression
private void anyOldTransfer(){}//the pointcut signature
  • 切入点支持的定义方式
    • execution:匹配方法执行的连接点
    • within:限定匹配特定类型的连接点
    • this:限定匹配特定连接点的bean引用是指定类型的实例
    • target:限定匹配特定连接点的目标对象是指定类型的实例
    • args:限定匹配特定连接点的参数是指定类型的实例
    • @target:限定匹配特定连接点的类执行对象的具有给定类型的注解
    • @args:限定匹配特定连接点实际传入参数的类型具有给定类型的注解‘
    • @within:限定匹配到具有给定的注释类型的连接点
    • @annotation:限定匹配特定连接点的主体具有给定的注解

(5)组合pointcut

  • 切入点表达式可以通过&&、||、!进行组合,也可以通过名字引入切入点表达式
  • 通过组合,可以建立更加复杂的切入点表达式
@Pointcut("execution(public *(..))")
private void anyPublicOperation(){}@Pointcut("within(com.xyz.someapp.trading..)")
private void inTrading(){}@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation(){}

(6)定义良好的pointcuts

  • AspectJ是编译期的AOP
  • 检查代码并匹配连接点与切入点的代价是昂贵的
  • 一个好的切入点应该包括以下几点
    • 选择特定类型的连接点,如:execution,get,set,call,handler
    • 确定连接点范围,如:within,withincode
    • 匹配上下文信息,如:this,target,@annotation

2.Advice定义及实例

(1)Before advice

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Component
@Aspect
public class ExampleAspect{//在执行com.xyz.aop.aspectj包下以Biz结尾的类的所有方法时匹配Advice@Before("*execution(* com.xyz.aop.aspectj.biz.*Biz.*(..))")public void before(){//..
    }
}

(2)After returning advice

@Aspect
public class AfterReturningExample{@AfterReturning("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")public void doAccessCheck(){//...
    }
}
  • 有时候需要在通知体内得到返回的实际值,可以使用@AfterReturning绑定返回值的形式
@Aspect
public class AfterReturningExample{@AfterReturning(pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",returning="retVal")public void doAccessCheck(Object retVal){//...
    }
}

(3)After throwing advice

@Aspect
public class AfterThrowingExample{@AfterThrowing("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")public void doRecoveryActions(){//...
    }
}
  • 有时候需要在通知体内得到返回的实际值,可以使用@AfterReturning绑定的返回值的形式
@Aspect
public class AfterThrowingExample{@AfterThrowing(pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",throwing="ex")public void doRecoveryActions(DataAccessException ex){//...
    }
}

(4)After (finally) advice

  • 最终通知必须准备处理正常和异常两种返回情况,它通常用于释放资源
@Aspect
public class AfterFinallyExample{@After("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")public void doReleaseLock(){//...
    }
}

(5)Around advice

  • 环绕通知使用@Around注解来声明,通知方法的第一个参数必须是ProceedingJoinPoint类型
  • 在通知内部调用ProceedingJoinPoint的proceed()方法会导致执行真正的方法,传入一个Object[]对象,数组中的值将被作为参数传递给方法
@Aspect
public class AroundExample{@Around("com.xyz.myapp.SystemArchitecture.businessService()")public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable{//start stopwatchObject retVal=pjp.proceed();//stop stopwatchreturn retVal;}
}

3.Advice扩展

(1)给advice传递参数

方式一:

@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation() && args(account,..)")
public void validateAccount(Account account){//...
}

方式二:

@Pointcut("com.xyz.myapp.SystemArchitecture.dataAccessOperation() && args(account,..)")
private void accountDataAccessOperation(Account account){}@Before("accountDataAccessOperation(account)")
//Account account:这里的方法参数可以是任何类的对象
public void validateAccount(Account account){//...
}

方式三:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auditable{Auditable value();
}
@Before("com.xyz.lib.Pointcuts.anyPublicMethod()&&@annotation(auditable)")
public void audit(Auditable auditable){AuditCode code=auditable.value();//...
}

(2)Advice的参数及泛型

  • Spring AOP可以处理泛型类的声明和使用方法的参数
public interface Sample<T>{void sampleGenericMethod(T param);void sampleGenericCollectionMethod(Collection>T>param);
}

方式一:

@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
public void beforeSampleMethod(MyType param){//Advice implementation
}

方式二:

@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
public void beforeSampleMethod(Collection<MyType> param){//Advice implementation
}

(3)Advice参数名称

  • 通知和切入点注解有一个额外的“argNames”,它可以用来指定所注解的方法的参数名
@Before(value="com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)",argNames="bean,auditable")
public void audit(Object bean,Auditable auditable){AuditCode code=auditable.value();//...use code and bean
}
  • 如果第一个参数是JoinPoint,ProceedingJoinPoint,JoinPoint.StaticPart,那么可以忽略它
@Before(value="com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)",argNames="bean,auditable")
public void audit(JoinPoint jp,Object bean,Auditable auditable){AuditCode code=auditable.value();//...use code ,bean and jp
}

(4)Introductions

  • 允许一个切面声明一个通知对象实现指定接口,并且提供了一个接口实现类来代表这些对象
  • introduction使用@DeclareParents进行注解,这个注解用来定义匹配的类型拥有一个新的parent
  • 例如:给定一个接口UsageTracked,并且该接口拥有DefaultUsageTracked的实现,接下来的切面生命了所有的service接口的实现都实现了UsageTracked接口
@Aspect
public class UsageTracking{@DeclareParents(value="com.xyz.myapp.service.*+",defaultImpl=DefaultUsageTracked.class)public static UsageTracked mixin;@Before("com.xyz.myapp.SystemArchitecture.businessService() && this(usageTracked)")public void recordUsage(UsageTracked usageTracked){usageTracked.incrementUseCount();}
}

(5)切面实例化模型

  • 这是一个高级主题
  • “perthis”切面通过制定@Aspect注解perthis子句实现
  • 每个独立的service对象执行时都会创建一个切面实例
  • service对象的每个方法在第一次执行的时候创建切面实例,切面在service对象失效的同时失效
@Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())")
public class MyAspect{private int someState;@Before(com.xyz.myapp.SystemArchitecture.businessService())public void recordServiceUsage(){//...
    }
}

转载于:https://www.cnblogs.com/chanaichao/p/9267173.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/413752.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[vue-cli]在使用vue-cli开发vue项目时,自动刷新页面的原理你了解吗?

[vue-cli]在使用vue-cli开发vue项目时&#xff0c;自动刷新页面的原理你了解吗&#xff1f; 自动刷新页面并不是vue-cli的功能&#xff0c;而是webpack的hot-module-replacement-plugin插件在做这件事&#xff0c;这个插件是webpack自带的插件&#xff0c;用来做hmr的。如果需…

git 基本使用

一、本地创建git版本库 在本地随便找个空文件夹 或者 新建一个空文件夹 初始化一下 $ mkdir newgit //新建一个空目录 $ cd newgit //进入 $ git init //使用git init命令 初始化一个Git仓库二、添加文件到Git仓库&#xff0c;分两步 使用命令git add <f…

C++ ActiveX开发的问题讨论

最近在一个项目中需要开发一个ocx插件&#xff0c;在开发过程中发现了一些问题&#xff0c;所以在此记录一下。 我想讨论的主要是函数的参数问题&#xff0c;我分别使用c,JavaScript,C#对ocx插件做了测试&#xff0c;发现不同的参数类型在这几种语言中表现的差异很大。 &#x…

[vue-cli]vue-cli3插件有写过吗?怎么写一个代码生成插件?

[vue-cli]vue-cli3插件有写过吗&#xff1f;怎么写一个代码生成插件&#xff1f; MyPlugin.install function (Vue, options) { // 1. 添加全局方法或属性 Vue.myGlobalMethod function () { // 逻辑... }// 2. 添加全局资源 Vue.directive(my-directive, { bind (el, bindi…

javaScript数据类型(包括基本数据类型和非基本数据类型)

一、五种基本数据类型 1、number 数字类型 - 包括浮点数和整数&#xff0c;例如&#xff1a;1,100,3.14 2、string 字符串类型 - 包括任意数字字符组成的序列&#xff0c;例如&#xff1a;“1”&#xff0c; “one”&#xff0c; “one 2 one” 3、boolean 布尔类型 - 包括 t…

Codeforces Round #496 (Div. 3 ) E1. Median on Segments (Permutations Edition)(中位数计数)

E1. Median on Segments (Permutations Edition)time limit per test3 secondsmemory limit per test256 megabytesinputstandard inputoutputstandard outputYou are given a permutation p1,p2,…,pnp1,p2,…,pn. A permutation of length nn is a sequence such that each i…

数组转换为字符串方法

1. toString() 方法 和 toLocaleString() 方法 var arr [ "a", "b", "c"]; alert(arr.toString()); // a,b,c alert(arr.toLocaleString()); // a,b,c 返回数组的字符串表示&#xff0c;中间以逗号隔开 2. join() 方法 var a…

[vue-cli]vue-cli生成的项目可以使用es6、es7的语法吗?为什么?

[vue-cli]vue-cli生成的项目可以使用es6、es7的语法吗&#xff1f;为什么&#xff1f; vue-cli 配置了babel,可以将es6,es7....etc在webpack打包的时候转换成es5的代码&#xff0c;所以上线的时候没有问题。但是脚手架只是配置了一些默认常见的用法&#xff0c; 可以根据babel…

做小程序的流程总结(基本篇)

一、首先当我们借助小程序实现我们的网站搭建时&#xff0c;就需要使用小程序自带的一些功能&#xff1b;且需要根据该小程序获取到的一些参数存储到对应的数据库中。 openID&#xff1a;每个微信用户使用该小程序时都会产生一个openID&#xff0c;且该openID是唯一标识&#x…

js对象数组 按对象的某一属性进行去重

var array [{ id: 1, name: "张三"},{ id: 2, name: "李四"},{ id: 3, name: "张龙"},{ id: 4, name: "赵虎"},{ id: 5, name: "王朝"},{ id: 1, name: "刘金刚"},{ id: 6, name: "马汉"}, ]var obj …

[vue-cli]vue-cli怎么解决跨域的问题?

[vue-cli]vue-cli怎么解决跨域的问题&#xff1f; 在根目录下新建&#xff1a;vue.config.js注意名不能错误&#xff0c;然后里面配置 module.exports { devServer: { proxy: { //配置跨域 /api: { target: 跨域url, ws: true, changOrigin: true // pathRewrite: { // ^/api…

java - springmvc整合cxf发布webservice

1.jar包已上传百度云盘&#xff0c;在jar包目录下 2.web.xml配置 <web-app xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xmlns"http://java.sun.com/xml/ns/javaee" xsi:schemaLocation" http://java.sun.com/xml/ns/javaee http://jav…

CSS3 选择前几个元素 选择后几个元素等问题

//例如有如下代码块 <div><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p> </div>1.选择第n个p div:nth-child(n) p:nth-of-type(n)2.选择倒数第n…

[vue-cli] vue-cli中你经常的加载器有哪些?

[vue-cli] vue-cli中你经常的加载器有哪些&#xff1f; style,css,vue,postcss,url等个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

Python中将array类型不按科学计数法存在文件中的方法

直接上代码&#xff1a; from numpy import *import numpy as npDrug_array zeros((708,708),dtype int)f open(D:\mat_drug_drug.txt)lines f.readlines()Drug_row 0for line in lines: list line.strip(\n).split( ) Drug_array[Drug_row:] list[:] Drug_row…

[vue-cli] 你知道什么是脚手架吗?

[vue-cli] 你知道什么是脚手架吗&#xff1f; vue项目一般是使用webpack进行打包构建的&#xff0c;然而如果每一个项目都需要我们去配置loader和plugin的话&#xff0c;是很重复的劳动&#xff0c;并且vue项目需要使用到的最基本的webpack loader和webpack plugin是相同的。因…

Vue报错:Elements in iteration expect to have ‘v-bind:key‘ directives的解决办法

1.我们在使用v-for的时候&#xff0c;在v-for 后添加 v-bind:key"ite Vue 2.2.0的版本里&#xff0c;当在组件中使用v-for时&#xff0c;key是必须的。 1.我们在使用v-for的时候&#xff0c;在v-for 后添加 v-bind:key"item" <div v-for"todo in to…

vue报错:error Strings must use singlequote quotes 字符串必须使用单引号

例出现下面报错 这个问题说明必须使用单引号&#xff0c;在vue的项目开发中&#xff0c;如果我们在通过vue-cli脚手架构建项目的时候使用了Eslint严格模式&#xff0c;那么对于字符串类型的数据String必须要使用单引号&#xff0c;不能使用双引号&#xff0c;否则会报异常。所以…

Java数组概述和定义

1、数组概述和定义格式说明    为什么要有数组(容器)&#xff1a;       为了存储同种数据类型的多个值  数组概念&#xff1a;      数组是存储同一种数据类型多个元素的集合。也可以看成是一个容器。      数组既可以存储基本数据类型&#xff0c;也可…

工作327:uni-数据格式处理

allPrpos(obj) { // 用来保存所有的属性名称和值let list[]var props "";// 开始遍历for(var p in obj){ // 方法if(typeof(obj[p])"function"){ obj[p]();}else{ // p 为属性名称&#xff0c;obj[p]为对应属性的值if(p.indexOf("apic") ! -1){…