Spring AOP 详解
首先介绍一下aop的有关概念。关于aop的相关概念,帮助文档给了我们详细的说明,但是个人感觉,文档中的说明太过高深,不适合我等技术小白学习。本人根据自己的学习给出自己的理解,不恰当的地方还请大神指点。
直接给出例子
首先,一个实体对象Person
[code]
<strong>public</strong><strong>class</strong> Person {
<strong>private</strong> String id;
<strong>private</strong> String name;
<strong>public</strong> Person() {
}
<strong>public</strong> Person(String id, String name) {
<strong>super</strong>();
<strong>this</strong>.id = id;
<strong>this</strong>.name = name;
}
<strong>public</strong> String getId() {
<strong>return </strong>id;
}
<strong>public</strong><strong>void</strong> setId(String id) {
<strong>this</strong>.id = id;
}
<strong>public</strong> String getName() {
<strong>return </strong>name;
}
<strong>public</strong><strong>void</strong> setName(String name) {
<strong>this</strong>.name = name;
}
}
[/code]
定义PersonDaoImpl模拟实现数据库操作的类
[code]
<strong>public</strong><strong>class</strong> PersonDaoImpl {
<strong>public</strong><strong>void</strong> add() {
System.<em>out</em>.println("add person");
}
<strong>public</strong><strong>void</strong> update() {
System.<em>out</em>.println("update person");
}
<strong>public</strong><strong>void</strong> delete() {
System.<em>out</em>.println("delete person");
}
<strong>public</strong> List listAll() {
Person p1 = <strong>new</strong> Person("1001", "person1");
Person p2 = <strong>new</strong> Person("1002", "person2");
List<Person> list = <strong>new</strong> ArrayList<Person>();
list.add(p1);
list.add(p2);
<strong>return</strong> list;
}
<strong>public</strong> Person find() {
Person p1 = <strong>new</strong> Person("1001", "person1");
<strong> return</strong> p1;
}
}
[/code]
定义Transaction类,模拟数据库操作中的事务管理
[code]
<strong>public</strong><strong>class</strong> Transaction {
<strong>public</strong><strong>void</strong> beginTransaction() {
System.<em>out</em>.println("beginTransaction");
}
/**对应后置通知
* @param joinPoint
* 通过joinPoint可以得到目标类和目标方法的一些信息
* @param val
* 目标方法的返回值
* 和<aop:after-returning returning="val"/>中returning的值保质一致
*/
<strong>public</strong><strong>void</strong> commit(JoinPoint joinPoint, Object val) {
System.<em>out</em>.println("commit");
List<Person> list = (List<Person>) val;
<strong>for</strong> (Person p : list) {
System.<em>out</em>.println(p.getName());
}
}
<strong>public</strong><strong>void</strong> finalMethod() {
System.<em>out</em>.println("最终通知");
}
//对应环绕通知
<strong>public</strong><strong>void</strong> arroundMethod(ProceedingJoinPoint joinPoint) {
<strong>try</strong> {
joinPoint.proceed(); // 让目标类的目标方法执行
} <strong>catch</strong> (Throwable e) {
// <strong>TODO</strong> Auto-generated catch block
e.printStackTrace();
}
}
<strong>public</strong><strong>void</strong> throwMehod(Throwable except) {
System.<em>out</em>.println(except.getMessage());
}
}
[/code]
最后,给出客户端AopTest测试类
[code]
<strong>public</strong><strong>class</strong> AopTest {
@Test
<strong>public</strong><strong>void</strong> test(){
ApplicationContext context = <strong>new</strong> ClassPathXmlApplicationContext("cn/ytu/aop/xml/applicationContext.xml");
PersonDaoImpl dao = (PersonDaoImpl) context.getBean("personDao");
dao.listAll();
}
}
[/code]
配置文件applicationContext.xml
[code]
<?xml version=<em>"1.0"</em> encoding=<em>"UTF-8"</em>?>
<beans xmlns=<em>"http://www.springframework.org/schema/beans"</em>
xmlns:xsi=<em>"http://www.w3.org/2001/XMLSchema-instance"</em>
xmlns:aop=<em>"http://www.springframework.org/schema/aop"</em>
xsi:schemaLocation=<em>"http://www.springframework.org/schema/beans</em>
<em> http://www.springframework.org/schema/beans/spring-beans-2.5.xsd</em>
<em> http://www.springframework.org/schema/aop </em>
<em> http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"</em>>
<!–
1、目标类
2、切面
3、进行aop的配置
–>
<!– 目标类 –>
<bean id=<em>"personDao"</em> class=<em>"cn.ytu.aop.xml.PersonDaoImpl"</em>></bean>
<!– 切面声明 –>
<bean id=<em>"transaction"</em> class=<em>"cn.ytu.aop.xml.Transaction"</em>></bean>
<!– aop配置 –>
<aop:config>
<!– 配置切入点 execution(* cn.itcast.spring0401.aop.xml.PersonDaoImpl.*(..))–>
<aop:pointcut expression=<em>"execution(* cn.ytu.aop.xml.PersonDaoImpl.*(..))"</em> id=<em>"perform"</em>/>
<!– 配置切面 –>
<aop:aspect ref=<em>"transaction"</em>>
<!– 前置通知 –>
<aop:before method=<em>"beginTransaction"</em> pointcut-ref=<em>"perform"</em>/>
<!– 后置通知 –>
<aop:after-returning method=<em>"commit"</em> pointcut-ref=<em>"perform"</em> returning=<em>"val"</em>/>
<!– 最终通知 –>
<aop:after pointcut-ref=<em>"perform"</em> method=<em>"finalMethod"</em> />
<!– 环绕通知 –>
<aop:around method=<em>"arroundMethod"</em> pointcut-ref=<em>"perform"</em> />
<!– 异常通知 –>
<aop:after-throwing method=<em>"throwMehod"</em> pointcut-ref=<em>"perform"</em> throwing=<em>"except"</em>/>
</aop:aspect>
</aop:config>
</beans>
[/code]
首先,通过这个例子来说明aop中相关概念
(1).切面(Aspect):在本例中“切面”就是Transaction类的行为。
(2).连接点(Joinpoint):程序执行过程中的某一行为,具体说就是在客户端调用的目标对象或者代理对象中的方法。对应本例中的dao.listAll();
(3).通知(Advice):简单说,通知就是切面中的方法.对应本例中的Transaction类中的一系列方法。
(4).切入点(Pointcut):定义“事件”发生的条件。
(5).目标对象(Target Object) :被一个或者多个切面所通知的对象。对应本例中的PersonDaoImpl
下面,详细介绍如何通过xml配置aop
- 首先导入aop相关的jar文件
Aspectjweaver.jar与aspectjrt.jar
- 加入与aop相关的xsd
xmlns:aop=”http://www.springframework.org/schema/aop”
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
- 引入目标类,切面
<!– 目标类 –>
<bean id=“personDao” class=“cn.ytu.aop.xml.PersonDaoImpl”></bean>
<!– 切面声明 –>
<bean id=“transaction” class=“cn.ytu.aop.xml.Transaction”></bean>
- 进行aop的配置
<aop:config>
<!–
配置aop的切入点
id 是切入点的标识
expression 为切入点的表达式
切入点的表达式的模板
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
参数详解
modifiers-pattern 修饰符可选 public private protected
ret-type-pattern 返回类型必选 * 代表任意类型
declaring-type-pattern 方法的声明类型可选
name-patterm 方法名称类型 必选
set* 以set开头的所有的方法名称
param-pattern 参数匹配 必选
(..) 任意多个参数,每个参数任意多个类型
(*,String) 两个参数第一个是任意类型,第二个是String
throws-pattern 异常的匹配模式可选
<aop:pointcut expression=”execution(* cn.ytu.aop.xml.PersonDaoImpl.*(..))” id=”perform”/>
<!–
配置切面
ref 指向声明切面的类
–>
<aop:aspect ref=”transaction”>
<!–
前置通知
pointcut-ref 引用一个切入点
–>
<aop:before method=”beginTransaction” pointcut-ref=”perform”/>
<!–
后置通知
returning 目标方法的返回值
如果目标方法中有可能存在异常,异常确实发生了,这个时候,后置通知将不再执行
–>
<aop:after-returning method=”commit” pointcut-ref=”perform” returning=”val”/>
<!–
最终通知
不能得到目标方法的返回值
无论目标方法是否有异常,最终通知都将执行
资源的关闭、连接的释放写在最终通知里
–>
<aop:after pointcut-ref=”perform” method=”finalMethod”/>
<!–
环绕通知
ProceedingJoinPoint的proceed方法就是目标对象的目标方法
环绕通知可以控制目标对象目标方法执行
–>
<!–
<aop:around method=”aroundMethod” pointcut-ref=”perform”/>
–>
<!–
异常通知
在异常通知中获取目标方法抛出的异常
–>
<aop:after-throwing method=”throwingMethod” pointcut-ref=”perform” throwing=”except”/>
</aop:aspect>
</aop:config>