- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Spring AOP 切面@Around注解的用法说明由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
@Around注解可以用来在调用一个具体方法前和调用后来完成一些具体的任务.
比如我们想在执行controller中方法前打印出请求参数,并在方法执行结束后来打印出响应值,这个时候,我们就可以借助于@Around注解来实现; 。
再比如我们想在执行方法时动态修改参数值等 。
类似功能的注解还有@Before等等,用到了Spring AOP切面思想,Spring AOP常用于拦截器、事务、日志、权限验证等方面.
需要说明的是,在以下例子中,我们即可以只用@Around注解,并设置条件,见方法run1();也可以用@Pointcut和@Around联合注解,见方法pointCut2()和run2(),这2种用法是等价的。如果我们还想利用其进行参数的修改,则调用时必须用joinPoint.proceed(Object[] args)方法,将修改后的参数进行回传。如果用joinPoint.proceed()方法,则修改后的参数并不会真正被使用.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
import
org.aspectj.lang.ProceedingJoinPoint;
import
org.aspectj.lang.annotation.Around;
import
org.aspectj.lang.annotation.Aspect;
import
org.aspectj.lang.annotation.Pointcut;
import
org.aspectj.lang.reflect.MethodSignature;
import
org.slf4j.Logger;
import
org.slf4j.LoggerFactory;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.stereotype.Component;
import
javax.persistence.EntityManager;
/**
* 控制器切面
*
* @author lichuang
*/
@Component
@Aspect
public
class
ControllerAspect {
private
static
final
Logger logger = LoggerFactory.getLogger(ControllerAspect.
class
);
@Autowired
private
EntityManager entityManager;
/**
* 调用controller包下的任意类的任意方法时均会调用此方法
*/
@Around
(
"execution(* com.company.controller.*.*(..))"
)
public
Object run1(ProceedingJoinPoint joinPoint)
throws
Throwable {
//获取方法参数值数组
Object[] args = joinPoint.getArgs();
//得到其方法签名
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//获取方法参数类型数组
Class[] paramTypeArray = methodSignature.getParameterTypes();
if
(EntityManager.
class
.isAssignableFrom(paramTypeArray[paramTypeArray.length -
1
])) {
//如果方法的参数列表最后一个参数是entityManager类型,则给其赋值
args[args.length -
1
] = entityManager;
}
logger.info(
"请求参数为{}"
,args);
//动态修改其参数
//注意,如果调用joinPoint.proceed()方法,则修改的参数值不会生效,必须调用joinPoint.proceed(Object[] args)
Object result = joinPoint.proceed(args);
logger.info(
"响应结果为{}"
,result);
//如果这里不返回result,则目标对象实际返回值会被置为null
return
result;
}
@Pointcut
(
"execution(* com.company.controller.*.*(..))"
)
public
void
pointCut2() {}
@Around
(
"pointCut2()"
)
public
Object run2(ProceedingJoinPoint joinPoint)
throws
Throwable {
//获取方法参数值数组
Object[] args = joinPoint.getArgs();
//得到其方法签名
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//获取方法参数类型数组
Class[] paramTypeArray = methodSignature.getParameterTypes();
if
(EntityManager.
class
.isAssignableFrom(paramTypeArray[paramTypeArray.length -
1
])) {
//如果方法的参数列表最后一个参数是entityManager类型,则给其赋值
args[args.length -
1
] = entityManager;
}
logger.info(
"请求参数为{}"
,args);
//动态修改其参数
//注意,如果调用joinPoint.proceed()方法,则修改的参数值不会生效,必须调用joinPoint.proceed(Object[] args)
Object result = joinPoint.proceed(args);
logger.info(
"响应结果为{}"
,result);
//如果这里不返回result,则目标对象实际返回值会被置为null
return
result;
}
}
|
补充:Spring Aop实例(AOP 如此简单)@Aspect、@Around 注解方式配置 。
IoC相关的基本内容告一段落,本次介绍Spring的第二个特性,AOP,面向切面编程,术语听起来比较不容易理解,没关系,一切尽在实例中,让我们看一个简单的实例,就能明白.
项目工程目录结构和代码获取地址 。
获取地址(版本Log将会注明每一个版本对应的课程) 。
https://github.com/laiyijie/SpringLearning 。
运行具有Main函数的 App.java 。
得到如下输出 。
1
2
3
|
method start time:
1480223298250
userHello
method end time:
1480223299250
|
从App.java入手 。
App.java 。
1
2
3
4
5
6
7
8
9
10
11
|
package
me.laiyijie.demo;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
import
me.laiyijie.demo.service.HelloInterface;
public
class
App {
public
static
void
main(String[] args) {
ClassPathXmlApplicationContext context =
new
ClassPathXmlApplicationContext(
"root-context.xml"
);
HelloInterface userService = context.getBean(HelloInterface.
class
);
userService.sayHello();
context.close();
}
}
|
调用的是HelloInterface的sayHello方法 。
HelloInterface.java 。
1
2
3
4
5
6
|
package
me.laiyijie.demo.service;
public
interface
HelloInterface{
void
sayHello();
}
|
其实现类为UserServiceImpl.java 。
UserServiceImpl.java 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package
me.laiyijie.demo.service;
import
org.springframework.stereotype.Service;
@Service
public
class
UserServiceImpl
implements
HelloInterface {
public
void
sayHello() {
try
{
Thread.sleep(
1000
);
}
catch
(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(
"userHello"
);
}
}
|
诶?情况跟我们看到的代码有出入?
sayHello 应该只输出 userHello,前后两行输出从何出现?
在Main函数中找不到一点儿线索! 。
这就是AOP的一个强大特性:
无侵入性,不改变原有的代码,却能增加功能! 。
那么究竟是如何增加功能的呢?
让我们看看TimeMonitor.java 。
TimeMonitor.java 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package
me.laiyijie.demo.aop;
import
org.aspectj.lang.ProceedingJoinPoint;
import
org.aspectj.lang.annotation.Around;
import
org.aspectj.lang.annotation.Aspect;
import
org.springframework.stereotype.Service;
@Service
@Aspect
public
class
TimeMonitor {
@Around
(
"execution(* me.laiyijie.demo.service.UserServiceImpl.sayHello(..))"
)
public
void
monitorAround(ProceedingJoinPoint pjp)
throws
Throwable {
System.out.println(
"method start time:"
+ System.currentTimeMillis());
Object re = pjp.proceed();
System.out.println(
"method end time:"
+ System.currentTimeMillis());
}
}
|
终于看到了 method start time:1480223298250 和 method end time:1480223299250这两行输出是从哪儿出现的了! 。
让我们来仔细解读一下这个类 。
类有两个注释,分别是@Service和@Aspect,第一个注解是使得TimeMonitor受Spring托管并实例化。@Aspect就是使得这个类具有AOP功能(你可以这样理解)两个注解缺一不可 。
类里面只有一个方法,名字叫做monitorAroud,其实就是为了检测函数执行时间的! 。
那么关键点来了,两个输出语句是怎么插入到sayHello方法的前后的呢! 。
看这个注解:
1
|
@Around
(
"execution(* me.laiyijie.demo.service.UserServiceImpl.sayHello(..))"
)
|
@Around表示包围一个函数,也就是可以在函数执行前做一些事情,也可以在函数执行后做一些事情 。
1
|
execution(* me.laiyijie.demo.service.UserServiceImpl.sayHello(..))
|
这个比较好理解,就是使用表达式的方式指定了要对哪个函数进行包围!(除了execution以外还有很多,可以搜索AspectJ语法来学习) 。
也就是说,这个注解完整的说明了,应该在函数的什么位置插入变化,也就是所谓的切点 。
之后是函数的定义:
1
|
public
Object monitorAround(ProceedingJoinPoint pjp)
|
这里引入了ProceedingJoinPoint,在使用了@Around之后可以带入这个参数,代表的其实就是sayHello这个函数,不过做了一些封装 。
而 Object re = pjp.proceed(); 就是相当于执行了 sayHello方法! 。
剩下的代码就不用过多解释了,就是在执行这个函数的前后分别进行了系统时间的获取.
我们把这个函数体,也就是定义了要做那些事情的代码,称作增强 。
而包含切点和增强结合起来就称作切面 。
面向切面由此而来! 。
需要配置两项 。
1、pom.xml增加依赖(因为要用到AOP还需要不同的JAR包) 。
2、root-context.xml中增加切面相关配置 。
root-context.xml 。
1
2
3
4
5
6
7
8
9
10
11
12
|
<?
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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<
aop:aspectj-autoproxy
></
aop:aspectj-autoproxy
>
<
context:component-scan
base-package
=
"me.laiyijie.demo"
></
context:component-scan
>
</
beans
>
|
root-context.xml 增加了两行 。
1、xmlns:aop="http://www.springframework.org/schema/aop" 。
代表加入命名空间 。
2、<aop:aspectj-autoproxy></aop:aspectj-autoproxy> 。
使用1中引入的aop命名空间开起自动代理(自动代理具体含义后续慢慢解释,简单的理解就是AOP的实现是依靠自动代理实现的) 。
pom.xml 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<
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
>me.laiyijie</
groupId
>
<
artifactId
>demo</
artifactId
>
<
version
>0.0.1-SNAPSHOT</
version
>
<
packaging
>jar</
packaging
>
<
dependencies
>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<
dependency
>
<
groupId
>org.springframework</
groupId
>
<
artifactId
>spring-context</
artifactId
>
<
version
>4.3.2.RELEASE</
version
>
</
dependency
>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<
dependency
>
<
groupId
>org.aspectj</
groupId
>
<
artifactId
>aspectjweaver</
artifactId
>
<
version
>1.8.9</
version
>
</
dependency
>
</
dependencies
>
</
project
>
|
增加了一个依赖 。
AspectJ 一个强大的AOP框架,也就是@Aspect和@Around以及ProceedingJoinPoint这些注解和方法的提供者 。
增强:定义了应该怎么把额外的动作加入到指定函数中 。
切点:定义了你应该把增强插入到哪个函数的什么位置 。
切面:切点和增强组合起来的称呼 。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我。如有错误或未考虑完全的地方,望不吝赐教.
原文链接:https://blog.csdn.net/lichuangcsdn/article/details/87741811 。
最后此篇关于Spring AOP 切面@Around注解的用法说明的文章就讲到这里了,如果你想了解更多关于Spring AOP 切面@Around注解的用法说明的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在查看预先重写的 jQuery 代码。我无法理解以下代码。 $('body > *:not(#print-modal):not(script)').clone(); 最佳答案 此选择器匹配以下任何
所以我开始学习MySQL,我对表有点困惑,所以我想澄清一下。数据库中可以有多个表吗?例如: Database1 -Table1 -Username -Password -Table2 -Name
我在 PostgreSQL 中编写了一个函数,其代码如下: for (i = 0; i str[0][i]); values[i] = datumCopy(dat_value,
oid: 行的对象标识符(对象 ID)。这个字段只有在创建表的时候使用了 WITH OIDS ,或者是设置了default_with_oids 配置参数时出现。 这个字段的类型是 oid (和字段同
我在搜索最大连接设备数时发现了 a post大致说: 当使用 P2P_STAR 时,最大设备数量为 10,因为此 topoly 使用 Wi-Fi 热点。也就是说,如果您没有路由器。 这让我问了两个问题
我不明白为什么会这样: Printf.sprintf "%08s" "s" = Printf.sprintf "%8s" "s" - : bool = true 换句话说,我希望: Printf.sp
我正在遵循 Grails in Action 中的示例。我有一个问题,如何理解 addTo*()功能有效。 我有一个简单的域:具有以下关系的用户、帖子、标签: 用户1对M发帖 用户一对一标签 发布 M
请问为什么行 "b[0]= new Child2();"在运行时而不是在编译时失败。请不要检查语法,我只是在这里做了 class Base {} class Child1 : Base {} clas
所以我想进一步加深我对套接字的理解,但是我想首先从最低级别开始(在C语言中,而不是在汇编中大声笑) 但是,我处理的大多数站点都使用SOCK_STREAM或SOCK_DGRAM。但是我已经阅读了Beej
好吧,我对 javascript 语法了解甚少,而且我对 null 的行为感到非常困惑。关于空值有很多讨论,但我似乎无法找出问题所在!请帮我。这是脚本。 var jsonData = '';
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭5 年前。 Improve thi
问题: SeriesSum 类旨在计算以下系列的总和: 类名:SeriesSum 数据成员/实例变量: x:存储整数 n:存储术语数量 sum:用于存储系列总和的双变量 成员函数: SeriesSum
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 9 年前。 Improve this ques
今天我在 logcat 中注意到以下内容: D/OpenGLRenderer:0xa2c70600 (CardView) 上的 endAllStagingAnimators,句柄为 0xa2c9d35
如何创建值有序对的列表,例如list1 [(x, y), (x1, y1) ...].?? 学习如何创建此列表后,我需要知道如何将 x 值提供给列表中的用户输入并搜索 x 的下一个值并显示有序对 (x
我在存储过程中有以下逻辑。 这里完成了什么? 如果color为null,替换为'' IF ISNULL(@color, '') <> '' BEGIN END 最佳答案 它等同于: IF (@colo
我知道.Net中的接口(interface)定义了接口(interface)和继承它的类之间的契约。刚刚完成了一个大量使用数据访问层接口(interface)的项目,这让我开始思考。 . .有什么大不
如何防止基类方法被子类覆盖 最佳答案 您不需要做任何特别的事情:默认情况下方法是不可覆盖的。相反,如果您希望该方法可重写,则必须将 virtual 关键字添加到其声明中。 但是请注意,即使方法不可重写
我已阅读以下有关工厂模式的文章 here 请仅引用Class Registration - avoiding reflection这一部分。 这个版本在没有反射的情况下实现了工厂和具体产品之间的减少耦
我正在学习 Java 类(class),但无法完全理解下一课的内容。 目的:本课的目的是通过创建一个模拟 for-each 循环如何工作的替代方案来解释 for-each 循环的工作方式。 在上一课中
我是一名优秀的程序员,十分优秀!