锁定老帖子 主题:Spring AOP 简单入门示例
该帖已经被评为新手帖
|
|
---|---|
作者 | 正文 |
发表时间:2009-03-22
最后修改:2009-04-09
严重提示:仅供参考 分享一个自己写的最为简单的Spring AOP的应用,其实,本人也是学习Spring不久,只是把一些个人的理解分享下,供参考。可能很多人刚开始不太理解到底啥是AOP,其实它也是相对OOP来说的,类似OOP其实也是一种编程思想吧。本人暂且把Spring 中的AOP理解成一种方法的拦截器(可能有所片面,主要是方便理解)。 个人通俗理解,就好比你去自动取款机取钱,边上装了个摄像头在监视着。你取你的钱,不用管那摄像头干嘛,只是对于摄像头来说,已经把你取钱的这一过程记录了下来。你取钱的这一过程我们可以从OOP角度分析,而对于摄像头来说,就是从AOP角度去分析了。反映到我下面要讲的示例就是系统日志的记录。
我要讲的示例大致是这样的,从OOP角度分析,就是说现在有一个User对象,然后你要调用业务逻辑实现去保存(或者其他行为)这个User对象,或者说是做持久化操作,把User对象相关信息写进数据库。那么从AOP角度来看,就是在你进行保存对象这一行为发生的时候进行日志记录。就是说,你在进行业务操作的时候,不需要去关心系统背后到底做了啥,Spring AOP它已经帮你搞定了。
(图一、个人对于OOP与AOP在本人示例中的理解)
上图说表示的东西是个人的理解理解,纵向为主业务逻辑这里表现为对User对象的持久化操作,横向为AOP实现,这里表现为系统日志记录。
以下是代码具体实现:(采用Spring2.5,Myeclipse6.5) (一)、从AOP角度分析: package org.wiki.spring.aspect; import org.aspectj.lang.JoinPoint; /** * 定义切面类,将系统中的横切性关注点模块化 * * @author Wiki.M * */ public class Aspect { /** * 定义advice,即切面类中方法具体实现, 这里主要是用于记录日志,只做简单处理。 * * @param joinPoint,可以取得被拦截方法的一些信息 */ public void logging(JoinPoint joinPoint) { //得到被拦截方法参数,并打印 Object[] args = joinPoint.getArgs(); for (int i = 0; i < args.length; i++) { System.out.println("method arg" + i + " -- " + args[i]); } //得到被拦截方法签名 System.out.println(joinPoint.getSignature().getName()); //记录系统日志具体实现 System.out.println("----logging-----"); } } (二)从DAO,数据持久化角度分析: package org.wiki.spring.dao; import org.wiki.spring.domain.User; /** * 定义IUserDAO接口,目的是为了灵活实现UserDAO不同的操作。 * @author Wiki.M * */ public interface IUserDAO { public void addUser(User user); public void deleteUser(int id); public void updateUser(int id); } //================================================== package org.wiki.spring.dao; import org.wiki.spring.domain.User; /** * IUserDAO接口的具体实现,这里只做简单处理 * @author Wiki.M * */ public class UserDAOImpl implements IUserDAO { @Override public void addUser(User user) { System.out.println("----addUser----"); } @Override public void deleteUser(int id) { System.out.println("----deleteUser----"); } @Override public void updateUser(int id) { System.out.println("----updateUser----"); } } (三)域模型分析 package org.wiki.spring.domain; /** * 领域模型User * @author Wiki.M * */ public class User { private int id; private String name; private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } } (四)、从业务层分析: package org.wiki.spring.service; import org.wiki.spring.domain.User; /** * 定义User业务逻辑相关的一个接口, * 目的是为了在客户端自由调用接口实现 * @author Wiki.M * */ public interface IUserService { public void saveUser(User user); public void deleteUser(int id); public void updateUser(int id); } //========================================= package org.wiki.spring.service; import org.wiki.spring.dao.IUserDAO; import org.wiki.spring.domain.User; /** * 业务逻辑接口IUserService的具体实现 * @author Wiki.M * */ public class UserServiceImpl implements IUserService { private IUserDAO userDAO; public void setUserDAO(IUserDAO userDAO) { this.userDAO = userDAO; } @Override public void deleteUser(int id) { userDAO.deleteUser(id); } @Override public void saveUser(User user) { userDAO.addUser(user); } @Override public void updateUser(int id) { userDAO.updateUser(id); } } (五)从客户端调用分析: package org.wiki.spring.client; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.wiki.spring.domain.User; import org.wiki.spring.service.IUserService; public class Client { /** * 客户端调用,用于测试 * @param args */ public static void main(String[] args){ BeanFactory factory = new ClassPathXmlApplicationContext("*.xml"); //得到UserService具体实现,用于操作业务逻辑 IUserService userService = (IUserService)factory.getBean("userServiceImpl"); User user = new User(); user.setId(1); user.setName("Wiki"); user.setPassword("123"); //测试1,记录日志 userService.saveUser(user); //测试2,记录日志 userService.deleteUser(1); } }
Spring配置文件: <?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.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"> <!-- 配置UserDAOImpl --> <bean id="userDAO" class="org.wiki.spring.dao.UserDAOImpl"/> <!-- 配置UserServiceImpl --> <bean id="userServiceImpl" class="org.wiki.spring.service.UserServiceImpl"> <!-- 注入userDAO,实际为UserDAOImpl,即对数据持久化的具体实现 --> <property name="userDAO" ref="userDAO" /> </bean> <!-- 配置aspect切面类 --> <bean id="userAspect" class="org.wiki.spring.aspect.Aspect" /> <!-- 配置AOP --> <aop:config> <!-- 配置aspect切面类 --> <aop:aspect ref="userAspect"> <!-- 配置pointcut,即切入点,对哪些类的哪些方法起到AOP的作用 --> <aop:pointcut id="userServiceMethods" expression="execution(* org.wiki.spring.service.UserServiceImpl.*(..))" /> <!-- 配置advice,即Aspect类中的logging()方法,这里采用在业务方法执行前进行拦截 --> <aop:before method="logging" pointcut-ref="userServiceMethods" /> </aop:aspect> </aop:config> </beans>
可能用到的Jar包: commons-logging.jar, log4j.jar, spring.jar, aspectjrt.jar, aspectjweaver.jar
另附本人测试代码。
注:如使用Annotation方式最好请修改Aspect这个类的类名,命名的时候疏忽了,可能会更aspectjrt.jar中的类冲突。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-03-22
谢谢楼主的分享!受益了
|
|
返回顶楼 | |
发表时间:2009-03-22
其实,可能有些理解也有所片面,希望能有所帮助……
|
|
返回顶楼 | |
发表时间:2009-04-03
从我个人理解角度看,和楼主相似。xwork中的拦截器是自动前后拦截,spring aop给我们提供一个自由的选择,可以在方法的前、后、异常或前后时进行拦截。楼主对动态切入点和静态切入点有何理解?
|
|
返回顶楼 | |
发表时间:2009-04-03
最后修改:2009-04-03
我觉得aop做日志还是有些问题的,日志信息记录不是很完善,在service中的处理很难体现,对方法名有严格的要求。不过如果做粗粒度权限验证还是很不错的选择。不知道怎么样才能记录详细日志?
|
|
返回顶楼 | |
发表时间:2009-04-03
楼上想记录什么样详细的信息呢?
|
|
返回顶楼 | |
发表时间:2009-04-03
xiaohu0901 写道 楼上想记录什么样详细的信息呢?
我是想记录service方法里面执行的“增加”、“删除”、“修改”记录的信息,最少日志应该记录了你修改了什么,修改成什么,成功了?还是失败了? |
|
返回顶楼 | |
发表时间:2009-04-03
75468850 写道 xiaohu0901 写道 楼上想记录什么样详细的信息呢?
我是想记录service方法里面执行的“增加”、“删除”、“修改”记录的信息,最少日志应该记录了你修改了什么,修改成什么,成功了?还是失败了? 其实,我也这个东西主要希望给正在学习Spring AOP的朋友们有所启示。AOP的日志主要还是用于记录一些系统日志,方便调试分析错误,当然也可以利用AOP一些简单的参数方法拦截,进行一些操作。对于较为详细的需求如果AOP解决不了的,也可以自己写单独的应用。总而言之看需求吧,有好有坏。 |
|
返回顶楼 | |
发表时间:2009-04-03
xiaohu0901 写道 从我个人理解角度看,和楼主相似。xwork中的拦截器是自动前后拦截,spring aop给我们提供一个自由的选择,可以在方法的前、后、异常或前后时进行拦截。楼主对动态切入点和静态切入点有何理解?
其实,个人对于Srping AOP的研究也是比较浅的,并没有很深入。动态静态切入点问题也没有深入去研究,据个人推断动态的切入点应该每次调用都会生成代理,而静态应该只生成一次,效率上应该静态的更高点吧,我自己这么想想的。 |
|
返回顶楼 | |
发表时间:2009-04-08
最后修改:2009-04-08
楼主,问你个问题,我把你的代码改成用aspect注解来实现aop怎么实现不了
代码修补部分如下: package org.wiki.spring.aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @org.aspectj.lang.annotation.Aspect public class Aspect { @Pointcut("execution(* s*(..))") private void allMehtod(){} @Before("allMehtod()") public void logging(JoinPoint joinPoint) { //得到被拦截方法参数,并打印 Object[] args = joinPoint.getArgs(); for (int i = 0; i < args.length; i++) { System.out.println("method arg" + i + " -- " + args[i]); } //得到被拦截方法签名 System.out.println(joinPoint.getSignature().getName()); //记录系统日志具体实现 System.out.println("----logging-----"); } } <?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.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"> <aop:aspectj-autoproxy /> <bean id="userDAO" class="org.wiki.spring.dao.UserDAOImpl"/> <bean id="userServiceImpl" class="org.wiki.spring.service.UserServiceImpl"> <property name="userDAO" ref="userDAO" /> </bean> <!-- <bean id="userAspect" class="org.wiki.spring.aspect.Aspect" /> <aop:config> <aop:aspect ref="userAspect"> <aop:pointcut id="userServiceMethods" expression="execution(* org.wiki.spring.service.UserServiceImpl.*(..))" /> <aop:before method="logging" pointcut-ref="userServiceMethods" /> </aop:aspect> </aop:config> --> </beans> |
|
返回顶楼 | |