Spring AOP 的简单例子

       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

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

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

package com.laoyangx.Aop.chapter0;

public interface IUser {
	/**
	 * 用户登录
	 * @param username 用户名
	 * @param password 密码
	 */
  public void Login(String username,String password);
}

4.UserImpl.java

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

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");

	}

}

运行程序之后,控制台上输出的结果

通过结果可以看到每个函数的执行顺序。关于 前置通知、环绕通知、后置通知 这些术语 网上都有相关的介绍

posted @ 2011-10-15 19:04  来自非洲大草原的食人虎  阅读(17924)  评论(1编辑  收藏  举报