spring AOP 例子

先看 advice 类

package com.supben.advice;

import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;

/**
 * 实现spring advice 接口
 * 
 * @author shencl
 * 
 */
public class TestAdvice implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {

	private static final Logger log = LoggerFactory.getLogger(TestAdvice.class);

	/**
	 * before 通知
	 */
	public void before(Method method, Object[] args, Object target) throws Throwable {
		log.info(target.getClass().getSimpleName() + "类的" + method.getName() + "方法,执行TestAdvice的before通知");
// 通知要做的业务
		if (method.getName().startsWith("get")) {
			log.info("只有方法名是以get开始的方法,才会执行到这句话....");
		}
	}

	/**
	 * after 通知
	 */
	public void afterReturning(Object arg0, Method method, Object[] arg2, Object target) throws Throwable {
		log.info(target.getClass().getSimpleName() + "类的" + method.getName() + "方法,执行TestAdvice的after通知");
	}

	/**
	 * 异常通知
	 */
	public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable {
		log.info(target.getClass().getSimpleName() + "类的" + method.getName() + "方法,执行TestAdvice的throwing通知");
	}

}




配置文件
<?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" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans   
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   
    http://www.springframework.org/schema/context   
    http://www.springframework.org/schema/context/spring-context-2.5.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

	<context:annotation-config />
	<!-- 扫描com.supben 下所有的包-->
	<context:component-scan base-package="com.supben" />

	<bean id="testAdvice" class="com.supben.advice.TestAdvice" />
	<aop:config>
	   <aop:advisor pointcut="execution(* *..service.*Service.*(..))"
			advice-ref="testAdvice" />
	</aop:config>

</beans>


service接口
package com.supben.service;

public interface FirstService {

	public void get();

	public void exception();
}

service实现类
package com.supben.service.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.supben.service.FirstService;

@Service("firstService")
public class FirstServiceImpl implements FirstService {
	private static final Logger log = LoggerFactory.getLogger(FirstServiceImpl.class);

	public void get() {
		log.info("方法执行ing.....");
	}

	public void exception() {
		throw new RuntimeException("测试异常");
	}
}


测试类
package com.supben.test;

import junit.framework.TestCase;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.supben.service.FirstService;
import com.supben.spring.SpringContextUtil;

public class ServiceTest extends TestCase {
	/**
	 * 装载spring 配置文件
	 */
	static {
		new ClassPathXmlApplicationContext("application.xml");
	}

	@Test
	public void testGet() {
		FirstService service = SpringContextUtil.getBean("firstService");
		service.get();
	}

	@Test
	public void testGet2() {
		FirstService service = SpringContextUtil.getBean("firstService");
		service.exception();
	}
}



测试结果:

2012-05-09 15:10:10,028 INFO [com.supben.advice.TestAdvice] - FirstServiceImpl类的get方法,执行TestAdvice的before通知
2012-05-09 15:10:10,030 INFO [com.supben.advice.TestAdvice] - 只有方法名是以get开始的方法,才会执行到这句话....
2012-05-09 15:10:10,032 INFO [com.supben.service.impl.FirstServiceImpl] - 方法执行ing.....
2012-05-09 15:10:10,032 INFO [com.supben.advice.TestAdvice] - FirstServiceImpl类的get方法,执行TestAdvice的after通知



2012-05-09 15:10:10,035 INFO [com.supben.advice.TestAdvice] - FirstServiceImpl类的exception方法,执行TestAdvice的before通知
2012-05-09 15:10:10,035 INFO [com.supben.advice.TestAdvice] - FirstServiceImpl类的exception方法,执行TestAdvice的throwing通知

结果分析:
get方法满足执行之前会 执行 before通知,执行完成后会执行after通知。

exception方法执行之前会执行before 通知,因为方法名不是以get开头,所以不会执行before通知的业务逻辑。然后出现异常了会执行throwing通知,因为出异常了,方法没有执行完毕,所以不会触发after通知。


概念:

切面(aspect): 翻译成外貌更合适:整个程序相当于一个密封的圆柱体,即一个外貌,现在要面向这个东西编程,在不改变原来类(FirstServiceImpl)的情况下,改变里边的代码。通知(advice):TestAdvice里边的before,after,throwing方法都是通知。 常见的有前置通知,后置通知,异常通知。
切点(cut-point):定义通知应该应用在哪些地方,本例是FirstServiceImpl中的get方法和exception方法,一般用正则表达式定义。
切点表达式:配置文件中的execution(* *..service.*Service.*(..)) 是一个切点表达式,表示的是一个一个的方法.比如本例中的表达式,意思是 包目录的最后一级是service,类/接口名 后缀为Service的 class文件里的,方法名为任意名称,参数个数不限的 方法。 * 表示任意,(..)表示方法参数个数不限。
目标对象(traget):FirstService就是目标对象。

此外还有两个重要的概念
引入(Introduction):允许为已存在类添加新方法和属性。
代理(Proxy):将通知应用到目标对象后创建的对象。
本文章不讨论。

你可能感兴趣的:(spring aop)