`
hanqunfeng
  • 浏览: 1542219 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Spring2.5那些事之基于AOP的方法级注解式日志配置

阅读更多

在日常开发中经常需要在代码中加入一些记录用户操作日志的log语句,比如谁在什么时间做了什么操作,等等。

把这些对于开发人员开说无关痛痒的代码写死在业务方法中实在不是一件很舒服的事情,于是AOP应运而生。

 

Spring对AOP的支持有以下4种情况:

1.基于代理的AOP

2.@Aspectj

3.纯POJO

4.注入式Aspectj切面

 

前三种都是基于方法级的,最后一个可以精确到属性及构造器。

 

关于Spring对AOP的支持的详细内容,读者可以参考《Spring in Action (第二版)中文版》第四章。

 

我这里使用的是第三种,纯POJO的方式,这种方式仅能在spring2.0及以后的版本中使用。

 

ok,言归正传,还是来说一说方法级注解的日志配置方式吧,顾名思义,就是只需要在方法上增加一个注释就可以自动打印日志,所以首先需要创建一个注解,如下:

package com.hqf.common.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserOperateLog {
	/**
	 * 用户操作名称
	 * @return 用户操作名称,默认为空串
	 */
	String value() default "";
	
	/**
	 * 用户操作类型,默认类型为0<br/>
	 * 0 - 其他操作 <br/>
	 * 1 - 查询 <br/>
	 * 2 - 新增 <br/>
	 * 3 - 修改 <br/>
	 * 4 - 删除
	 * @return 用户操作类型
	 */
	int type() default 0;
	
	/**
	 * 用户操作名称对应的key,可以通过该key值在属性文件中查找对应的value
	 * @return key
	 */
	String key() default "";
}

 

 

这里只是抛砖引玉,读者可以根据需要建立自己的注解。

 

有了注解,之后就需要在方法被调用时能解析注解,这就用到了SpringAOP的通知,我这里使用MethodBeforeAdvice,就是在方法被调用前执行。关于SpringAOP的通知的详细讨论读者可以参考《Spring in Action (第二版)中文版》第四章4.2.1

package com.hqf.common.annotation;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

public class UserOperateLogAdvisor implements MethodBeforeAdvice {

	private Logger logger;//日志句柄

	private String loggerName;//日志名称

	private Properties properties;//属性文件句柄

	
	/**                                                          
	* 描述 : <该方法用于初始化属性文件>. <br>
	*<p>                                                 
	      日志内容可以预先配置在配置文件中,在需要打印日志时从配置文件中找到对应的值。
	      这里是做扩展使用,读者可以根据实际情况进行设计                                                                                                                                                                                               
	* @param propertiesFilePath
	* @throws IOException                                                                                    			   
	*/
	public void setPropertiesFilePath(Resource propertiesFilePath)
			throws IOException {
		if (properties == null)
			properties = new Properties();
		properties.load(new FileInputStream(propertiesFilePath.getFile()));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.springframework.aop.MethodBeforeAdvice#before(java.lang.reflect.Method
	 * , java.lang.Object[], java.lang.Object)
	 */
	public void before(Method method, Object[] args, Object target)
			throws Throwable {
		String username = "未知";
		for (Object object : args) {
			//这里只提供一种获得操作人的方式,既从HttpSession中获取,但这要求方法参数中包含HttpSession
			//这里只是抛砖引玉,读者可以根据实际情况进行设计
			if (object instanceof HttpSession) {
				username = ((HttpSession) object).getAttribute("username") == null ? "未知"
						: (String) ((HttpSession) object)
								.getAttribute("username");
			}
		}
		//判断方法是否注解了UserOperateLog
		UserOperateLog anno = method.getAnnotation(UserOperateLog.class);
		if (anno == null)
			return;
		
		String defaultMessage = anno.value();
		String methodName = target.getClass().getName() + "."
				+ method.getName();
		String desc = this.handleDescription(anno.key(), StringUtils
				.hasText(defaultMessage) ? defaultMessage : methodName);
		//装配日志信息
		String logline = this.buildLogLine(username, anno.type(), desc);

		logger.info(logline);
	}

	/**
	 * 构建日志行
	 * 
	 * @param usrname
	 *            用户名称
	 * @param operateType
	 *            操作类型
	 * @param description
	 *            操作描述 
	 * @return 日志行: username - operateType - description
	 */
	protected String buildLogLine(String username, int operateType,
			String description) {
		StringBuilder sb = new StringBuilder();
		sb.append(username).append(" - ").append(operateType).append(" - ")
				.append(description);
		return sb.toString();
	}

	/**
	 * 获取日志内容描述,可以从消息配置文件中找到对应的信息
	 * 
	 * @param key
	 *            日志内容key
	 * @param defaultMessage
	 *            默认的描述信息
	 * @return 描述信息
	 */
	protected String handleDescription(String key, String defaultMessage) {
		if (properties == null)
			return defaultMessage;
		if (!StringUtils.hasText(key))
			return defaultMessage;
		String message = properties.getProperty(key);
		if (!StringUtils.hasText(message))
			return defaultMessage;
		else
			return message;
	}

	@PostConstruct
	public void init() {
		Assert.notNull(loggerName);
		logger = Logger.getLogger(loggerName);
	}

	/**
	 * @param loggerName
	 *            the loggerName to set
	 */
	public void setLoggerName(String loggerName) {
		this.loggerName = loggerName;
	}

}

 

为了使通知起作用,需要在spring配置文件加入如下内容:

	<!-- 定义用户操作日志切入点和通知器 -->
	<aop:config proxy-target-class="true">
		<aop:pointcut id="operatePoint"
			expression="@annotation(com.hqf.common.annotation.UserOperateLog)" />
		<aop:advisor pointcut-ref="operatePoint" id="logAdvisor"
			advice-ref="userOperateLogAdvisor" />
	</aop:config>
	
	<!-- 定义日志文件写入位置,需要在log4j.properties中加入名称为 useroperatorlog的日志配置-->
	<bean id="userOperateLogAdvisor" class="com.hqf.common.annotation.UserOperateLogAdvisor"
		p:loggerName="useroperatorlog" p:propertiesFilePath="classpath:messages/messages.properties"/>

 

ok,配置完成,在使用时只需要在方法上加入@UserOperateLog

例如:

@RequestMapping(value = "/demo/index2.do")
	@UserOperateLog(value="注解日志",type=1,key="annotation.log")
	public String handleIndex2(Model model,HttpSession session){
			
		return "demo/list";

	}

 

日志输出结果如下:

2010-03-04 16:01:45 useroperatorlog:68  INFO - hanqunfeng - 1 - 注解日志

 

注解里使用了key,这样就会从指定的配置文件中查找,如果查找到就替换掉默认的value值。

 

详细的代码请参考附件。

6
1
分享到:
评论
4 楼 hanqunfeng 2013-09-24  
fly_宇光十色 写道
按照你这样配置之后,启动报错啊!错误信息如下
Caused by: org.xml.sax.SAXParseException; lineNumber: 31; columnNumber: 97; 与元素类型 "bean" 相关联的属性 "p:loggerName" 的前缀 "p" 未绑定。

提示的很清楚了,你没有配置命名空间。
xmlns:p="http://www.springframework.org/schema/p"
3 楼 fly_宇光十色 2013-09-23  
按照你这样配置之后,启动报错啊!错误信息如下
Caused by: org.xml.sax.SAXParseException; lineNumber: 31; columnNumber: 97; 与元素类型 "bean" 相关联的属性 "p:loggerName" 的前缀 "p" 未绑定。
2 楼 hanqunfeng 2011-01-25  
dengquanhao 写道
引用
@RequestMapping(value = "/demo/index2.do")  
    @UserOperateLog(value="注解日志",type=1,key="annotation.log")  
    public String handleIndex2(Model model,HttpSession session){  
              
        return "demo/list";  
 
    } 

请问如上的@UserOperateLog(value="注解日志",type=1,key="annotation.log")中的value或则key,type等 
,我可否传入一个动态值呢?


貌似不可以。
1 楼 dengquanhao 2011-01-24  
引用
@RequestMapping(value = "/demo/index2.do")  
    @UserOperateLog(value="注解日志",type=1,key="annotation.log")  
    public String handleIndex2(Model model,HttpSession session){  
              
        return "demo/list";  
 
    } 

请问如上的@UserOperateLog(value="注解日志",type=1,key="annotation.log")中的value或则key,type等 
,我可否传入一个动态值呢?

相关推荐

    Spring 2.5 AOP 例子

    虽然Spring 2.5开始支持基于注解的配置,但XML配置仍然是一种常见且强大的方式。在AOP的上下文中,XML配置可以定义切面、通知(Advice)、切点(Pointcut)以及代理类型(Proxy Type)。以下是一些关键元素: 1. `...

    spring2.5的所有jar包

    2. **AOP(面向切面编程)**:Spring 2.5支持更强大的AOP功能,允许开发者定义和执行横切关注点,如日志、事务管理等,这些关注点可以独立于业务逻辑进行处理。 3. **XML配置增强**:在Spring 2.5中,XML配置文件...

    Spring2.5-中文参考手册chm

    Spring2.5版本是该框架的一个重要里程碑,它在2008年发布,带来了许多新特性和改进,提升了开发者在构建应用程序时的灵活性和效率。 **依赖注入(DI)和控制反转(IoC)** Spring的核心特性之一是依赖注入(Dependency...

    Spring2.5使用AOP需要的aspectJ

    在Spring 2.5版本中,面向切面编程(AOP)是一个强大的功能,它允许开发者定义“切面”来封装横切关注点,如日志、事务管理、权限检查等,使得代码更加模块化和可重用。AspectJ是一个成熟的AOP框架,Spring在其AOP...

    struts2+spring2.5+hibernate3基础包(包括AOP)

    Spring 2.5 版本引入了更多的注解支持,使得配置更加简洁。在SSH整合中,Spring 主要负责服务层的管理,包括bean的创建、依赖注入以及事务管理。 - **AOP(面向切面编程)**:Spring 提供了AOP支持,可以定义切面...

    spring 2.5框架图

    Spring 2.5框架是Java开发中的一个里程碑版本,它为开发者提供了丰富的功能和改进,尤其是在企业级应用开发中。这个框架的核心在于IoC(Inversion of Control)和AOP(Aspect-Oriented Programming),旨在简化Java...

    spring2.5中文文档

    3. **XML配置与注解配置的融合**:Spring 2.5引入了对Java注解的广泛支持,使得开发者可以选择使用XML配置或者注解配置,或者两者结合,更加灵活地定义bean和它们的依赖。 4. **Bean表达式语言(Bean Expression ...

    spring 2.5中文帮助文档

    通过阅读《Spring2.5-中文参考手册.chm》这份文档,开发者可以深入了解Spring 2.5的各种特性和用法,解决实际开发中遇到的问题,提升开发效率。文档不仅包含详细的API参考,还包含丰富的示例和最佳实践指导,是学习...

    Spring2.5 中文文档 chm格式

    另外,Spring2.5对Bean定义的元数据也进行了改进,支持了基于注解的配置。这使得开发者可以在类或方法级别使用注解,如`@Component`、`@Service`、`@Repository`和`@Controller`,简化XML配置文件。 在集成测试方面...

    传智播客 spring2.5源代码_lib包

    开发者可以通过XML配置文件或者基于注解的方式来定义bean。 4. **XML配置**: 在Spring 2.5中,XML仍然是主要的配置方式。开发者可以在`beans.xml`文件中定义bean及其依赖关系,以及属性的设置。例如,你可以看到如`...

    Spring2.5中文手册

    - 引入了基于注解的事务管理,通过`@Transactional`注解可以在方法级别声明事务边界。 7. **Bean的生命周期管理** - Spring管理的Bean有创建、初始化、配置、销毁等生命周期阶段,开发者可以通过实现接口或使用...

    spring2.5常用包

    2. **AOP(Aspect-Oriented Programming)**:Spring 提供了面向切面编程的支持,允许开发者定义“切面”,这些切面可以跨越多个类的多个方法,实现如日志、事务管理等通用功能。@Aspect 和 @Before、@After、@...

    Spring2.5

    通过阅读《spring2.5+学习笔记.doc》和《黎活明__spring教程.ppt》以及《黎活明_struts2教程.ppt》,你可以更深入地了解Spring 2.5与Struts2的整合,以及在实际项目中如何有效地利用这些知识。尽管Spring框架已经...

    传智播客 黎活明spring2.5 ppt

    《传智播客 黎活明spring2.5 ppt》是针对Java开发人员的一个培训资料,由知名讲师黎活明主讲,主要讲解了Spring框架2.5版本的相关知识。Spring是一个开源的Java企业级应用框架,它为开发人员提供了一个全面的编程和...

    spring2.5AOPdemo详细资料

    这个"spring2.5AOPdemo详细资料"很可能是针对Spring 2.5版本的一个AOP实战示例,帮助开发者了解并掌握AOP的概念、原理以及在实际开发中的应用。 AOP的核心概念包括切面(Aspect)、通知(Advice)、连接点(Join ...

    spring2.5注解驱动

    Spring 2.5还支持基于注解的AOP(面向切面编程)。`@Aspect`注解用于定义一个切面,`@Before`、`@After`、`@Around`、`@AfterReturning`和`@AfterThrowing`注解用于声明前置通知、后置通知、环绕通知、返回后通知和...

    spring2.5相关的jar包

    此外,Spring 2.5还增强了依赖注入(DI)功能,引入了基于注解的配置,允许在类级别和方法级别使用`@Autowired`、`@Qualifier`等注解,减少了XML配置文件的复杂性。这需要`spring-beans.jar`,`spring-context.jar`...

    struts1.2 + spring2.5 + hibernate3.2框架demo

    Struts1.2、Spring2.5和Hibernate3.2是经典的Java企业级开发框架组合,它们各自在应用程序的不同层次上发挥着重要作用。Struts1.2是一个MVC(Model-View-Controller)框架,主要负责处理用户界面与业务逻辑之间的...

    spring_2.5_aop_lib.zip

    最后,commons-logging.jar和commons-attributes-api.jar是Apache Commons的两个库,前者提供了通用的日志接口,后者则提供了处理Java注解的API,虽然在Spring AOP中不是直接使用,但它们是许多Java项目中不可或缺的...

    spring 2.5开发手册

    2. **AOP(面向切面编程)**:Spring 2.5提供了强大的AOP支持,用于实现横切关注点,如日志记录、事务管理等。它可以使用XML配置或@AspectJ注解来定义切面。 3. **Bean管理**:Spring容器管理Bean的生命周期,包括...

Global site tag (gtag.js) - Google Analytics