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"); } }
运行程序之后,控制台上输出的结果
通过结果可以看到每个函数的执行顺序。关于 前置通知、环绕通知、后置通知 这些术语 网上都有相关的介绍