`

Spring AOP 简单入门示例

阅读更多

严重提示:仅供参考

分享一个自己写的最为简单的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中的类冲突。

  • 大小: 23.6 KB
分享到:
评论
23 楼 ronartest 2010-01-06  
汗都是,,写日志

  加入我要对访问的方法进行权限验证,,

  当用户权限不够的时候 当然不能在继续访问方法啦,这个怎么做?
22 楼 hz86655032 2009-12-28  
wikimo 写道
75468850 写道
xiaohu0901 写道
楼上想记录什么样详细的信息呢?

我是想记录service方法里面执行的“增加”、“删除”、“修改”记录的信息,最少日志应该记录了你修改了什么,修改成什么,成功了?还是失败了?


其实,我也这个东西主要希望给正在学习Spring AOP的朋友们有所启示。AOP的日志主要还是用于记录一些系统日志,方便调试分析错误,当然也可以利用AOP一些简单的参数方法拦截,进行一些操作。对于较为详细的需求如果AOP解决不了的,也可以自己写单独的应用。总而言之看需求吧,有好有坏。

我想SPRING AOP应该如楼主所说关注点在于系统级的日志,对于pointcut的详细日志记录,个人认为这是在OOP领域中可以解决的问题,log4j应该是个不错的解决方案.
21 楼 chengxianke 2009-11-17  
相当不错。。。 目前正在学习中。。 谢谢。。。
20 楼 wikimo 2009-09-26  
youngJiang 写道
楼主应该写一个不带xml的aop的例子,然后再引入xml,这样似乎更好些。

其实本人对于AOP了解的也不是很深入,主要是Spring AOP谈下自己对于面向切片或者方面的编程的一种思维方式,相对于OOP,有时间的话写个玩玩
19 楼 youngJiang 2009-09-24  
楼主应该写一个不带xml的aop的例子,然后再引入xml,这样似乎更好些。
18 楼 zs7203 2009-09-24  
写的层次很清晰 ,一看就明白了
17 楼 nowave2004 2009-09-11  
今天刚看这个,挺清晰明了的
16 楼 hongshenghome 2009-06-15  
谢谢!学习中!!!!!!!!!
15 楼 wenxiang_tune 2009-05-16  
改用自动拦截功能很是好啊,不过对Spring的精华就理解得不太深刻了,希望能有人能帮助我深刻理解一下AOP与事务处理的关系
14 楼 wikimo 2009-04-22  
uu22 写道
<aop:pointcut id="userServiceMethods" 
               expression="execution(* org.wiki.spring.service.UserServiceImpl.*(..))" /> 这个属性的expression的设置具体上不明白“*”和“(。。。))”不明白!



其实这是一个表达式。(* org.wiki.spring.service.UserServiceImpl.*(..))第一个星号代表返回值,rg.wiki.spring.service.UserServiceImpl指类名,第二个型号值UserServiceImpl类下所有方法,“..”代表方法参数。
13 楼 uu22 2009-04-22  
<aop:pointcut id="userServiceMethods" 
               expression="execution(* org.wiki.spring.service.UserServiceImpl.*(..))" /> 这个属性的expression的设置具体上不明白“*”和“(。。。))”不明白!
12 楼 weid0907 2009-04-15  
我有个巨大的疑问,希望楼主关注一下:
就是通知中的方法如果有参数,就会出错。
我目前苦于不知道怎么传递参数,而我需要的参数是一个已经实例化的引用,不能重新new或者交给spring new出来,这都不行。我尝试过用arg-names,也会出错,就是在服务器启动的时候报错,楼主可以自己测试一下,增加一个参数来试试。然后我们再讨论一下如何解决,这也是我的一个求 助,呵呵。
11 楼 happy200318 2009-04-09  
很不错哦  谢谢啦
10 楼 wikimo 2009-04-08  
应该是按你这样配置的。我明天调试下看看。。。
9 楼 orcl_zhang 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>


8 楼 wikimo 2009-04-03  
xiaohu0901 写道
从我个人理解角度看,和楼主相似。xwork中的拦截器是自动前后拦截,spring aop给我们提供一个自由的选择,可以在方法的前、后、异常或前后时进行拦截。楼主对动态切入点和静态切入点有何理解?


其实,个人对于Srping AOP的研究也是比较浅的,并没有很深入。动态静态切入点问题也没有深入去研究,据个人推断动态的切入点应该每次调用都会生成代理,而静态应该只生成一次,效率上应该静态的更高点吧,我自己这么想想的。
7 楼 wikimo 2009-04-03  
75468850 写道
xiaohu0901 写道
楼上想记录什么样详细的信息呢?

我是想记录service方法里面执行的“增加”、“删除”、“修改”记录的信息,最少日志应该记录了你修改了什么,修改成什么,成功了?还是失败了?


其实,我也这个东西主要希望给正在学习Spring AOP的朋友们有所启示。AOP的日志主要还是用于记录一些系统日志,方便调试分析错误,当然也可以利用AOP一些简单的参数方法拦截,进行一些操作。对于较为详细的需求如果AOP解决不了的,也可以自己写单独的应用。总而言之看需求吧,有好有坏。
6 楼 75468850 2009-04-03  
xiaohu0901 写道
楼上想记录什么样详细的信息呢?

我是想记录service方法里面执行的“增加”、“删除”、“修改”记录的信息,最少日志应该记录了你修改了什么,修改成什么,成功了?还是失败了?
5 楼 xiaohu0901 2009-04-03  
楼上想记录什么样详细的信息呢?
4 楼 75468850 2009-04-03  
我觉得aop做日志还是有些问题的,日志信息记录不是很完善,在service中的处理很难体现,对方法名有严格的要求。不过如果做粗粒度权限验证还是很不错的选择。不知道怎么样才能记录详细日志?

相关推荐

    SpringAOP简单入门示例..pdf

    SpringAOP简单入门示例..pdf

    spring aop简单例子

    spring aop简单例子,入门学习的好资料

    Spring4.0从入门到精通AOP日志示例

    使用spring4.0进行用户日志的记录 这里带junit的测试跟main的测试 参考了 http://blog.csdn.net/oathevil/article/details/7288867 本代码中还包括了一个java自带注解的例子写的都非常易懂对于hellospring中第一位...

    Spring从入门到精通 源码

    本书最大的特色在于每章都是由浅入深,从一个简单的示例入手,让读者快速了解本章内容,然后再详细讲解本章涉及的基本原理和知识点,最后再通过一个详细的示例宋巩固所学内容。 本书每一章的例子都是经过精挑细选,...

    spring-boot示例项目

    本项目示例基于spring boot 最新版本(2.1.9)实现,Spring Boot、Spring Cloud 学习示例,将持续更新…… 在基于Spring Boot、Spring Cloud 分布微服务开发过程中,根据实际项目环境,需要选择、集成符合项目...

    Spring从入门到精通(珍藏版)

    本书最大的特色在于每章都是由浅入深,从一个简单的示例入手,让读者快速了解本章内容,然后再详细讲解本章涉及的基本原理和知识点,最后再通过一个详细的示例宋巩固所学内容。 本书每一章的例子都是经过精挑细选,...

    spring2.0技术手册

    林信良著 spring2.0...主要包括Spring入门、Bean/消息/事件、Spring AOP、JDBC/事物支持、Spring与Hibernate的整合、Spring Web MVC框架、View层方案/Web框架整合、API封装、Spring在线书签完整项目示例等内容。

    Spring2.0技术手册

    \r\n 本书内容全面深入,主要包括Spring入门、Bean/消息/事件、Spring AOP、JDBC/事物支持、Spring与Hibernate的整合、Spring Web MVC框架、View 层方案/Web框架整合、API封装、Spring在线书签完整项目示例等内容。

    java视频教程:spring框架精讲附加实战项目练习

    通过Spring的入门程序介绍了Spring的 IoC 和 DI 的概念,介绍了Spring的基本模块。详细介绍了对象创建的细节和依赖注入的几种方式;介绍了如何使用注解完成Spring的相关功能;介绍了如何借助于Spring搭建JUnit测试...

    基于SpringBoot+Spring Cloud集成了50+个demo的项目示例.zip

    该项目包含helloworld(快速入门)、web(ssh项目快速搭建)、aop(切面编程)、data-redis(redis缓存)、quartz(集群任务实现)、shiro(权限管理)、oauth2(四种认证模式)、shign(接口参数防篡改重放)、encoder(用户...

    ssm框架整合示例

    ssm框架整合示例, 掌握SPRING + SPING MVC + MYBATIS 三大框架整合.Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java... 简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架

    Spring框架快速入门之简介

    Spring是一个开源框架,是为了解决企业应用程序开发复杂性而创建的。...这些示例还将成为本系列后面部分进行的展开式讨论的基础,在本文的后面部分,将介绍Spring框架通过SpringAOP实现AOP构造的方式。 

    spring.net中文手册在线版

    26.4.The Spring.NET AOP Cookbook 26.4.1.缓存 26.4.2.性能监视 26.4.3.重试规则 Spring.NET AOP最佳实践 第二十七章. .NET Remoting快速入门 27.1.简介 27.2.Remoting实例程序 27.3.实现 27.4.运行程序 27.5....

    Spring 2.0 技术手册 PDF

    书内容全面深入,主要包括Spring入门、Bean/消息/事件、Spring AOP、JDBC/事物支持、Spring与Hibernate的整合、Spring Web MVC框架、View层方案/Web框架整合、API封装、Spring在线书签完整项目示例等内容。

    java8集合源码分析-thinking-in-spring:小马哥极客时间Spring编程思想示例项目

    编程思想示例项目 第一章 Spring Framework 总览 核心特性 核心特性(Core) IoC 容器(IoC Container) Spring 事件(Events) 资源管理(Resources) 国际化(i18n) 校验(Validation) 数据绑定(Data Binding) 类型装换(Type...

Global site tag (gtag.js) - Google Analytics