Spring AOP 实现了AOP联盟(Alliance)的制定的接口规范,它基于java的代理机制实现。AOP作为Spring的核心技术之一. 更多关于Spring AOP介绍 可参考:http://oss.org.cn/ossdocs/framework/spring/zh-cn/aop.html 下面给出一个例子来简单介绍Spring AOP具体实现过程
现假设用户通过login.jsp页面输入相应的用户名和密码之后,首先Spring AOP的环绕通知验证该用户名和密码是否符合要求,若符合要求,则到数据库中查找该用户,若用户存在,将该用户相关的信息写入日志。
1.BaseLoginAdvice 类实现了 前置通知接口(MethodBeforeAdvice)、环绕通知接口(MethodInterceptor)、后置通知接口(AfterReturningAdvice) 这三个接口
BaseLoginAdvice.java
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
|
package
com.laoyangx.Aop.chapter0;
import
java.lang.reflect.Method;
import
org.aopalliance.intercept.MethodInterceptor;
import
org.aopalliance.intercept.MethodInvocation;
import
org.springframework.aop.AfterReturningAdvice;
import
org.springframework.aop.MethodBeforeAdvice;
public
abstract
class
BaseLoginAdvice
implements
MethodBeforeAdvice, MethodInterceptor,
AfterReturningAdvice {
/**
* @param returnValue 目标方法返回值
* @param method 目标方法
* @param args 方法参数
* @param target 目标对象
*
*/
@Override
public
void
afterReturning(Object returnValue, Method method,
Object[] args, Object target)
throws
Throwable {
throw
new
UnsupportedOperationException(
"abstract class CBaseLoginAdvice not implement this method"
);
}
/**
* @param invocation 目标对象的方法
*/
@Override
public
Object invoke(MethodInvocation invocation)
throws
Throwable {
throw
new
UnsupportedOperationException(
"abstract class CBaseLoginAdvice not implement this method"
);
}
/**
* @param method 将要执行的目标对象方法
* @param args 方法的参数
* @param target 目标对象
*/
@Override
public
void
before(Method method, Object[] args, Object target)
throws
Throwable {
throw
new
UnsupportedOperationException(
"abstract class CBaseLoginAdvice not implement this method"
);
}
}
|
2.LoginAdviceSupport 类继承 BaseLoginAdvice 类,并重写 BaseLoginAdvice 类的三个方法
LoginAdviceSupport.java
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
|
package
com.laoyangx.Aop.chapter0;
import
java.lang.reflect.Method;
import
org.aopalliance.intercept.MethodInvocation;
public
class
LoginAdviceSupport
extends
BaseLoginAdvice {
/**
* 若在数据库中存在指定的用户,将用户登录信息写入日志文件
* @param returnValue 目标方法返回值
* @param method 目标方法
* @param args 方法参数
* @param target 目标对象
*/
@Override
public
void
afterReturning(Object returnValue, Method method,
Object[] args, Object target)
throws
Throwable {
System.out.println(
"---------- 程序正在执行 类名: com.laoyangx.Aop.chapter0.LoginAdviceSupport 方法名:afterReturning ----------------"
);
//将用户登录信息写入日志文件
}
/**
* 验证用户输入是否符合要求
* @param invocation 目标对象的方法
*/
@Override
public
Object invoke(MethodInvocation invocation)
throws
Throwable {
System.out.println(
"---------- 程序正在执行 类名: com.laoyangx.Aop.chapter0.LoginAdviceSupport 方法名:invoke ----------------"
);
String username=invocation.getArguments()[
0
].toString();
String password=invocation.getArguments()[
1
].toString();
//在这里进行相关的验证操作
//假设验证通过
return
invocation.proceed();
}
/**
* 在数据库中查找指定的用户是否存在
* @param method 将要执行的目标对象方法
* @param args 方法的参数
* @param target 目标对象
*/
@Override
public
void
before(Method method, Object[] args, Object target)
throws
Throwable {
System.out.println(
"---------- 程序正在执行 类名: com.laoyangx.Aop.chapter0.LoginAdviceSupport 方法名:before ----------------"
);
String username=(String)args[
0
];
String passowrd=(String)args[
1
];
//在这里进行数据库查找操作
}
}
|
3. IUser.java
1
2
3
4
5
6
7
8
9
10
|
package
com.laoyangx.Aop.chapter0;
public
interface
IUser {
/**
* 用户登录
* @param username 用户名
* @param password 密码
*/
public
void
Login(String username,String password);
}
|
4.UserImpl.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package
com.laoyangx.Aop.chapter0;
public
class
UserImpl
implements
IUser {
/**
* 用户登录
* @param username 用户名
* @param password 密码
*/
@Override
public
void
Login(String username, String password) {
System.out.println(
"---------- 程序正在执行 类名: com.laoyangx.Aop.chapter0.UserImpl 方法名:Login ----------------"
);
}
}
|
5. Spring 的配置文件 login.bean.xml
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="loginAdvice" class="com.laoyangx.Aop.chapter0.LoginAdviceSupport"></bean>
<bean id="userTarget" class="com.laoyangx.Aop.chapter0.UserImpl"></bean>
<bean id="user" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>com.laoyangx.Aop.chapter0.IUser</value>
</property>
<property name="interceptorNames">
<list>
<value>loginAdvice</value>
</list>
</property>
<property name="target">
<ref bean="userTarget"/>
</property>
</bean>
</beans>
6.主程序文件 ConsoleApp.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package
com.laoyangx.Aop.chapter0;
import
org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public
class
ConsoleApp {
public
static
void
main(String[] args) {
ApplicationContext ctx=
new
ClassPathXmlApplicationContext(
"com/laoyangx/Aop/chapter0/login.bean.xml"
);
IUser user=(IUser)ctx.getBean(
"user"
);
user.Login(
"username"
,
"123456"
);
}
}
|
运行程序之后,控制台上输出的结果
通过结果可以看到每个函数的执行顺序。关于 前置通知、环绕通知、后置通知 这些术语 网上都有相关的介绍