@aspectj 作为通过 java 5 注释注释的普通的 java 类,它指的是声明 aspects 的一种风格。通过在你的基于架构的 xml 配置文件中包含以下元素,@aspectj 支持是可用的。
<aop:aspectj-autoproxy/>
你还需要在你的应用程序的 classpath 中使用以下 aspectj 库文件。这些库文件在一个 aspectj 装置的 ‘lib’ 目录中是可用的,如果没有,你可以在 internet 中下载它们。
aspectjrt.jar
aspectjweaver.jar
aspectj.jar
aspects 类和其他任何正常的 bean 一样,除了它们将会用 @aspectj 注释之外,它和其他类一样可能有方法和字段,如下所示:
package org.xyz;
import org.aspectj.lang.annotation.aspect;
@aspect
public class aspectmodule {
}
它们将在 xml 中按照如下进行配置,就和其他任何 bean 一样:
<bean id="myaspect" class="org.xyz.aspectmodule">
<!-- configure properties of aspect here as normal -->
</bean>
一个切入点有助于确定使用不同建议执行的感兴趣的连接点(即方法)。在处理基于配置的 xml 架构时,切入点的声明有两个部分:
一个切入点表达式决定了我们感兴趣的哪个方法会真正被执行。
下面的示例中定义了一个名为 ‘businessservice’ 的切入点,该切入点将与 com.xyz.myapp.service 包下的类中可用的每一个方法相匹配:
import org.aspectj.lang.annotation.pointcut;
@pointcut("execution(* com.xyz.myapp.service.*.*(..))") // expression
private void businessservice() {} // signature
下面的示例中定义了一个名为 ‘getname’ 的切入点,该切入点将与 com.tutorialspoint 包下的 student 类中的 getname() 方法相匹配:
import org.aspectj.lang.annotation.pointcut;
@pointcut("execution(* com.tutorialspoint.student.getname(..))")
private void getname() {}
你可以使用 @{advice-name} 注释声明五个建议中的任意一个,如下所示。这假设你已经定义了一个切入点标签方法 businessservice():
@before("businessservice()")
public void dobeforetask(){
...
}
@after("businessservice()")
public void doaftertask(){
...
}
@afterreturning(pointcut = "businessservice()", returning="retval")
public void doafterreturnningtask(object retval){
// you can intercept retval here.
...
}
@afterthrowing(pointcut = "businessservice()", throwing="ex")
public void doafterthrowingtask(exception ex){
// you can intercept thrown exception here.
...
}
@around("businessservice()")
public void doaroundtask(){
...
}
你可以为任意一个建议定义你的切入点内联。下面是在建议之前定义内联切入点的一个示例:
@before("execution(* com.xyz.myapp.service.*.*(..))")
public dobeforetask(){
...
}
为了理解上面提到的关于基于 aop 的 @aspectj 的概念,让我们编写一个示例,可以实现几个建议。为了在我们的示例中使用几个建议,让我们使 eclipse ide 处于工作状态,然后按照如下步骤创建一个 spring 应用程序:
步骤 | 描述 |
---|---|
1 | 创建一个名为 springexample 的项目,并且在所创建项目的 src 文件夹下创建一个名为 com.tutorialspoint 的包。 |
2 | 使用 add external jars 选项添加所需的 spring 库文件,就如在 spring hello world example 章节中解释的那样。 |
3 | 在项目中添加 spring aop 指定的库文件 aspectjrt.jar, aspectjweaver.jar 和 aspectj.jar。 |
4 | 在 com.tutorialspoint 包下创建 java 类 logging, student 和 mainapp。 |
5 | 在 src 文件夹下创建 beans 配置文件 beans.xml。 |
6 | 最后一步是创建所有 java 文件和 bean 配置文件的内容,并且按如下解释的那样运行应用程序。 |
这里是 logging.java 文件的内容。这实际上是 aspect 模块的一个示例,它定义了在各个点调用的方法。
package com.tutorialspoint;
import org.aspectj.lang.annotation.aspect;
import org.aspectj.lang.annotation.pointcut;
import org.aspectj.lang.annotation.before;
import org.aspectj.lang.annotation.after;
import org.aspectj.lang.annotation.afterthrowing;
import org.aspectj.lang.annotation.afterreturning;
import org.aspectj.lang.annotation.around;
@aspect
public class logging {
/** following is the definition for a pointcut to select
* all the methods available. so advice will be called
* for all the methods.
*/
@pointcut("execution(* com.tutorialspoint.*.*(..))")
private void selectall(){}
/**
* this is the method which i would like to execute
* before a selected method execution.
*/
@before("selectall()")
public void beforeadvice(){
system.out.println("going to setup student profile.");
}
/**
* this is the method which i would like to execute
* after a selected method execution.
*/
@after("selectall()")
public void afteradvice(){
system.out.println("student profile has been setup.");
}
/**
* this is the method which i would like to execute
* when any method returns.
*/
@afterreturning(pointcut = "selectall()", returning="retval")
public void afterreturningadvice(object retval){
system.out.println("returning:" + retval.tostring() );
}
/**
* this is the method which i would like to execute
* if there is an exception raised by any method.
*/
@afterthrowing(pointcut = "selectall()", throwing = "ex")
public void afterthrowingadvice(illegalargumentexception ex){
system.out.println("there has been an exception: " + ex.tostring());
}
}
下面是 student.java 文件的内容:
package com.tutorialspoint;
public class student {
private integer age;
private string name;
public void setage(integer age) {
this.age = age;
}
public integer getage() {
system.out.println("age : " + age );
return age;
}
public void setname(string name) {
this.name = name;
}
public string getname() {
system.out.println("name : " + name );
return name;
}
public void printthrowexception(){
system.out.println("exception raised");
throw new illegalargumentexception();
}
}
下面是 mainapp.java 文件的内容:
package com.tutorialspoint;
import org.springframework.context.applicationcontext;
import org.springframework.context.support.classpathxmlapplicationcontext;
public class mainapp {
public static void main(string[] args) {
applicationcontext context =
new classpathxmlapplicationcontext("beans.xml");
student student = (student) context.getbean("student");
student.getname();
student.getage();
student.printthrowexception();
}
}
下面是配置文件 beans.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"
xsi:schemalocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<aop:aspectj-autoproxy/>
<!-- definition for student bean -->
<bean id="student" class="com.tutorialspoint.student">
<property name="name" value="zara" />
<property name="age" value="11"/>
</bean>
<!-- definition for logging aspect -->
<bean id="logging" class="com.tutorialspoint.logging"/>
</beans>
一旦你已经完成的创建了源文件和 bean 配置文件,让我们运行一下应用程序。如果你的应用程序一切都正常的话,这将会输出以下消息:
going to setup student profile.
name : zara
student profile has been setup.
returning:zara
going to setup student profile.
age : 11
student profile has been setup.
returning:11
going to setup student profile.
exception raised
student profile has been setup.
there has been an exception: java.lang.illegalargumentexception
.....
other exception content