- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Spring AOP使用接口方式实现由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
Spring 提供了很多的实现AOP的方式:Spring 接口方式,schema配置方式和注解. 。
本文重点介绍Spring使用接口方式实现AOP. 研究使用接口方式实现AOP, 以了解为目的. 更好地理解spring使用动态代理实现AOP. 通常我们使用的更多的是使用注解的方式实现AOP 。
下面来看看如何实现接口方式的AOP 。
要在项目中使用Spring AOP 则需要在项目中导入除了spring jar包之外, 还需要引入aspectjrt.jar,aspectjweaver.jar,aopalliance.jar ,spring-aop-3.2.0.M2.jar和cglib.jar 。
使用Spring aop接口方式实现aop, 可以通过自定义通知来供Spring AOP识别. 常见的自己定义通知有:前置通知, 后置通知, 返回通知, 异常通知, 环绕通知. 对应实现的接口是
实现步骤如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package
com.lxl.www.aop.interfaceAop;
/**
* 使用接口方式实现AOP, 默认通过JDK的动态代理来实现. 非接口方式, 使用的是cglib实现动态代理
*
* 业务接口类-- 计算器接口类
*
* 定义三个业务逻辑方法
*/
public
interface
IBaseCalculate {
int
add(
int
numA,
int
numB);
int
sub(
int
numA,
int
numB);
int
div(
int
numA,
int
numB);
int
multi(
int
numA,
int
numB);
int
mod(
int
numA,
int
numB);
}
|
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
|
package
com.lxl.www.aop.interfaceAop;
//业务类,也是目标对象
import
com.lxl.www.aop.Calculate;
import
org.springframework.aop.framework.AopContext;
import
org.springframework.stereotype.Service;
/**
* 业务实现类 -- 基础计算器
*/
@Service
public
class
BaseCalculate
implements
IBaseCalculate {
@Override
public
int
add(
int
numA,
int
numB) {
System.out.println(
"执行目标方法: add"
);
return
numA + numB;
}
@Override
public
int
sub(
int
numA,
int
numB) {
System.out.println(
"执行目标方法: sub"
);
return
numA - numB;
}
@Override
public
int
multi(
int
numA,
int
numB) {
System.out.println(
"执行目标方法: multi"
);
return
numA * numB;
}
@Override
public
int
div(
int
numA,
int
numB) {
System.out.println(
"执行目标方法: div"
);
return
numA / numB;
}
@Override
public
int
mod(
int
numA,
int
numB) {
System.out.println(
"执行目标方法: mod"
);
int
retVal = ((Calculate) AopContext.currentProxy()).add(numA, numB);
return
retVal % numA;
}
}
|
前置通知 。
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
|
package
com.lxl.www.aop.interfaceAop;
import
org.springframework.aop.MethodBeforeAdvice;
import
org.springframework.stereotype.Component;
import
java.lang.reflect.Method;
/**
* 定义前置通知
*/
@Component
public
class
BaseBeforeAdvice
implements
MethodBeforeAdvice {
/**
*
* @param method 切入的方法
* @param args 切入方法的参数
* @param target 目标对象
* @throws Throwable
*/
@Override
public
void
before(Method method, Object[] args, Object target)
throws
Throwable {
System.out.println(
"===========进入beforeAdvice()============"
);
System.out.println(
"目标对象:"
+ target);
System.out.println(
"方法名: "
+method);
System.out.println(
"即将进入切入点方法"
);
}
}
|
后置通知 。
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
|
package
com.lxl.www.aop.interfaceAop;
import
org.aspectj.lang.annotation.AfterReturning;
import
org.springframework.aop.AfterAdvice;
import
org.springframework.aop.AfterReturningAdvice;
import
org.springframework.stereotype.Component;
import
java.lang.reflect.Method;
public
class
BaseAfterReturnAdvice
implements
AfterReturningAdvice {
/**
*
* @param returnValue 切入点执行完方法的返回值,但不能修改
* @param method 切入点方法
* @param args 切入点方法的参数数组
* @param target 目标对象
* @throws Throwable
*/
@Override
public
void
afterReturning(Object returnValue, Method method, Object[] args, Object target)
throws
Throwable {
System.out.println(
"==========进入afterReturning()=========== \n"
);
System.out.println(
"切入点方法执行完成"
);
System.out.println(
"后置通知--目标对象:"
+ target);
System.out.println(
"后置通知--方法名: "
+method);
System.out.println(
"后置通知--方法入参: "
+ args.toString());
System.out.println(
"后置通知--方法返回值: "
+ returnValue);
}
}
|
异常通知 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package
com.lxl.www.aop.interfaceAop;
import
org.springframework.aop.ThrowsAdvice;
import
org.springframework.stereotype.Component;
import
java.lang.reflect.Method;
@Component
public
class
BaseAfterThrowsAdvice
implements
ThrowsAdvice {
/**
* @param method 可选:切入的方法
* @param args 可选:切入的方法的参数
* @param target 可选:目标对象
* @param throwable 必填 : 异常子类,出现这个异常类的子类,则会进入这个通知。
*/
public
void
afterThrowing(Method method, Object[] args, Object target, Throwable throwable) {
System.out.println(
"出错啦"
);
}
}
|
环绕通知 。
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
|
package
com.lxl.www.aop.interfaceAop;
import
org.aopalliance.intercept.MethodInterceptor;
import
org.aopalliance.intercept.MethodInvocation;
import
org.springframework.stereotype.Component;
import
java.lang.reflect.Method;
/**
* 环绕通知
*/
@Component
public
class
BaseAroundAdvice
implements
MethodInterceptor {
/**
* invocation :连接点
*/
@Override
public
Object invoke(MethodInvocation invocation)
throws
Throwable {
System.out.println(
"===========around环绕通知方法 开始==========="
);
// 调用目标方法之前执行的动作
System.out.println(
"环绕通知--调用方法之前: 执行"
);
// 调用方法的参数
Object[] args = invocation.getArguments();
// 调用的方法
Method method = invocation.getMethod();
// 获取目标对象
Object target = invocation.getThis();
System.out.println(
"输入参数:"
+ args[
0
] +
";"
+ method +
";"
+ target);
// 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行
Object returnValue = invocation.proceed();
System.out.println(
"环绕通知--调用方法之后: 执行"
);
System.out.println(
"输出参数:"
+ args[
0
] +
";"
+ method +
";"
+ target +
";"
+ returnValue);
System.out.println(
"===========around环绕通知方法 结束==========="
);
return
returnValue;
}
}
|
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
|
package
com.lxl.www.aop.interfaceAop;
/**
* 切点
*
* 继承NameMatchMethodPointcut类,来用方法名匹配
*/
import
org.springframework.aop.support.NameMatchMethodPointcut;
import
org.springframework.stereotype.Component;
import
java.lang.reflect.Method;
@Component
public
class
Pointcut
extends
NameMatchMethodPointcut {
private
static
final
long
serialVersionUID = 3990456017285944475L;
@SuppressWarnings
(
"rawtypes"
)
@Override
public
boolean
matches(Method method, Class targetClass) {
// 设置单个方法匹配
this
.setMappedName(
"add"
);
// 设置多个方法匹配
String[] methods = {
"add"
,
"div"
};
//也可以用“ * ” 来做匹配符号
// this.setMappedName("get*");
this
.setMappedNames(methods);
return
super
.matches(method, targetClass);
}
}
|
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
|
<?
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:p
=
"http://www.springframework.org/schema/p"
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
>
<!-- ==============================aop配置================================ -->
<!-- 声明一个业务类 -->
<
bean
id
=
"baseCalculate"
class
=
"com.lxl.www.aop.interfaceAop.BaseCalculate"
/>
<!-- 声明通知类 -->
<
bean
id
=
"baseBefore"
class
=
"com.lxl.www.aop.interfaceAop.BaseBeforeAdvice"
/>
<
bean
id
=
"baseAfterReturn"
class
=
"com.lxl.www.aop.interfaceAop.BaseAfterReturnAdvice"
/>
<
bean
id
=
"baseAfterThrows"
class
=
"com.lxl.www.aop.interfaceAop.BaseAfterThrowsAdvice"
/>
<
bean
id
=
"baseAround"
class
=
"com.lxl.www.aop.interfaceAop.BaseAroundAdvice"
/>
<!-- 指定切点匹配类 -->
<
bean
id
=
"pointcut"
class
=
"com.lxl.www.aop.interfaceAop.Pointcut"
/>
<!-- 包装通知,指定切点 -->
<
bean
id
=
"matchBeforeAdvisor"
class
=
"org.springframework.aop.support.DefaultPointcutAdvisor"
>
<
property
name
=
"pointcut"
>
<
ref
bean
=
"pointcut"
/>
</
property
>
<
property
name
=
"advice"
>
<
ref
bean
=
"baseBefore"
/>
</
property
>
</
bean
>
<!-- 使用ProxyFactoryBean 产生代理对象 -->
<
bean
id
=
"businessProxy"
class
=
"org.springframework.aop.framework.ProxyFactoryBean"
>
<!-- 代理对象所实现的接口 ,如果有接口可以这样设置 -->
<
property
name
=
"proxyInterfaces"
>
<
value
>com.lxl.www.aop.interfaceAop.IBaseCalculate</
value
>
</
property
>
<!-- 设置目标对象 -->
<
property
name
=
"target"
>
<
ref
bean
=
"baseCalculate"
/>
</
property
>
<!-- 代理对象所使用的拦截器 -->
<
property
name
=
"interceptorNames"
>
<
list
>
<
value
>matchBeforeAdvisor</
value
>
<
value
>baseAfterReturn</
value
>
<
value
>baseAround</
value
>
</
list
>
</
property
>
</
bean
>
</
beans
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package
com.lxl.www.aop.interfaceAop;
import
org.springframework.context.ApplicationContext;
import
org.springframework.context.annotation.AnnotationConfigApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public
class
InterfaceMainClass{
public
static
void
main(String[] args) {
ApplicationContext context =
new
ClassPathXmlApplicationContext(
"aop/aop.xml"
);
BaseCalculate calculate = (BaseCalculate) context.getBean(
"baseCalculate"
);
calculate.add(
1
,
3
);
}
}
|
各种类型通知的执行顺序: 前置方法会在切入点方法之前执行,后置会在切入点方法执行之后执行,环绕则会在切入点方法执行前执行同事方法结束也会执行对应的部分。主要是调用proceed()方法来执行切入点方法。来作为环绕通知前后方法的分水岭 在xml 配置 businessProxy这个bean的时候,ProxyFactoryBean类中指定了,proxyInterfaces参数。这里把他配置了IBaseCalculate接口。因为在项目开发过程中,往往业务类都会有对应的接口,以方便利用IOC解耦。但Spring AOP却也能支持没有接口的代理。这就是为什么需要导入cglib.jar包了。看过spring的源码,知道在目标切入对象如果有实现接口,spring会默认使用jdk动态代理来实现代理类。如果没有接口,则会通过cglib来实现代理类.
这个业务类现在有 前置通知,后置通知,环绕三个通知同时作用,可能以及更多的通知进行作用。那么这些通知的执行顺序是怎么样的?就这个例子而言,同时实现了三个通知。在例 子xml中,则显示执行before通知,然后执行around的前处理,执行切点方法,再执行return处理。最后执行around的后处理。经过测 试,知道spring 处理顺序是按照xml配置顺序依次处理通知,以队列的方式存放前通知,以压栈的方式存放后通知。所以是前通知依次执行,后通知到切入点执行完之后,从栈里 在后进先出的形式把后通知执行.
在实现过程中发现通知执行对应目标对象的整个类中的方法,如何精确到某个方法,则需要定义一个切点匹配的方式:spring提供了方法名匹配或正则方式来匹配。然后通过DefaultPointcutAdvisor来包装通知,指定切点.
使用接口方式配置起来,可见代码还是非常的厚重的,定义一个切面就要定义一个切面类,然而切面类中,就一个通知方法,着实没有必要。所以Spring提供了,依赖aspectj的schema配置和基于aspectj 注解方式。这两种方式非常简单方便使用,也是项目中普遍的使用方式.
到此这篇关于Spring AOP使用接口方式实现的文章就介绍到这了,更多相关Spring AOP 接口实现内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://juejin.cn/post/6999786128018505764 。
最后此篇关于Spring AOP使用接口方式实现的文章就讲到这里了,如果你想了解更多关于Spring AOP使用接口方式实现的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试在我的代码库中为我正在编写的游戏服务器更多地使用接口(interface),并了解高级概念以及何时应该使用接口(interface)(我认为)。在我的例子中,我使用它们将我的包相互分离,并使
我有一个名为 Widget 的接口(interface),它在我的整个项目中都在使用。但是,它也用作名为 Widget 的组件的 Prop 。 处理此问题的最佳方法是什么?我应该更改我的 Widget
有一个接口(interface)可以是多个接口(interface)之一 interface a {x:string} interface b {y:string} interface c {z:st
我遇到了一种情况,我需要调用第三方服务来获取一些信息。这些服务对于不同的客户可能会有所不同。我的界面中有一个身份验证功能,如下所示。 interface IServiceProvider { bool
在我的例子中,“RequestHandlerProxy”是一个结构,其字段为接口(interface)“IAdapter”,接口(interface)有可能被调用的方法,该方法的输入为结构“Reque
我有一个接口(interface)Interface1,它已由类A实现,并且设置了一些私有(private)变量值,并且我将类A的对象发送到下一个接受输入作为Interface2的类。那么我怎样才能将
假设我有这样的类和接口(interface)结构: interface IService {} interface IEmailService : IService { Task SendAs
有人知道我在哪里可以找到 XML-RPC 接口(interface)的定义(在 OpenERP 7 中)?我想知道创建或获取对象需要哪些参数和对象属性。每个元素的 XML 示例也将非常有帮助。 最佳答
最近,我一直在阅读有关接口(interface)是抽象的错误概念的文章。一篇这样的帖子是http://blog.ploeh.dk/2010/12/02/InterfacesAreNotAbstract
如果我有一个由第三方实现的现有 IInterface 后代,并且我想添加辅助例程,Delphi 是否提供了任何简单的方法来实现此目的,而无需手动重定向每个接口(interface)方法?也就是说,给定
我正在尝试将 Article 数组分配给我的 Mongoose 文档,但 Typescript 似乎不喜欢这样,我不知道为什么它显示此警告/错误,表明它不可分配. 我的 Mongoose 模式和接口(
我有两个接口(interface): public interface IController { void doSomething(IEntity thing); } public inte
是否可以创建一个扩展 Serializable 接口(interface)的接口(interface)? 如果是,那么扩展接口(interface)的行为是否会像 Serilizable 接口(int
我试图在两个存储之间创建一个中间层,它从存储 A 中获取数据,将其转换为相应类型的存储 B,然后存储它。由于我需要转换大约 50-100 种类型,我希望使用 map[string]func 并根据 s
我正在处理一个要求,其中我收到一个 JSON 对象,其中包含一个日期值作为字符串。我的任务是将 Date 对象存储在数据库中。 这种东西: {"start_date": "2019-05-29", "
我们的方法的目标是为我们现有的 DAO 和模型类引入接口(interface)。模型类由各种类型的资源 ID 标识,资源 ID 不仅仅是随机数,还带有语义和行为。因此,我们必须用对象而不是原始类型来表
Collection 接口(interface)有多个方法。 List 接口(interface)扩展了 Collection 接口(interface)。它声明与 Collection 接口(int
我有一个 Java 服务器应用程序,它使用 Jackson 使用反射 API 对 DTO 进行一般序列化。例如对于这个 DTO 接口(interface): package com.acme.libr
如果我在 Kotlin 中有一个接口(interface): interface KotlinInterface { val id: String } 我可以这样实现: class MyCla
我知道Java中所有访问修饰符之间的区别。然而,有人问了我一个非常有趣的问题,我很难找到答案:Java 中的 private 接口(interface)和 public 接口(interface)有什
我是一名优秀的程序员,十分优秀!