Spring(11):使用@AspectJ 注解实现AOP日志打印与示例

2017/12/31

AspectJ,一个面向切面的框架。@AspectJ 是AspectJ版本5的新增功能,所以确保JDK是5.0以上版本,负责无法使用注解技术。

(1)Spring通过集成AspectJ实现了以注解定义切面,大大减少了配置文件的工作量。

(2)java的反射机制无法获取方法参数名,Spring还利用了字节码处理框架asm处理@AspectJ描述的方法参数名


下面通过一个实例演示:

【0】文件结构和jar包


图1



图2


【1】新建一个包(com\smbms\AopLog)新建两个增强类(UserserviceLogger、UserserviceLogger2):

UserserviceLogger.java:

package com.smbms.AopLog;

import java.util.Arrays;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class UserserviceLogger {
	private static final Logger log = Logger.getLogger(UserserviceLogger.class);
	//前置增强方法
	@Before("execution(* com.smbms.pojo..*.*(..))")
	public void before (JoinPoint jp) throws Throwable{
		log.info("***UserserviceLogger*********before:调用了"+jp.getTarget()+" 的"+jp.getSignature().getName()
				+" 方法。方法入参:"+Arrays.toString(jp.getArgs()));
		try{
			log.info("调用了 "+jp.getTarget()+" 的 "+jp.getSignature().getName()
			+" 方法。");
		}catch(Throwable e){
			log.error(jp.getSignature().getName()+" 方法发生异常: "+e);
			throw e;
		}finally{
			log.info(jp.getSignature().getName()+"方法执行结束");
		}
	}
	
	@AfterReturning(pointcut = "execution(* com.smbms.pojo..*.*(..))",
			        returning = "result")
	//后置增强方法
	public void after (JoinPoint jp,Object result) throws Throwable{
		log.info("****UserserviceLogger**********after:调用了 "+jp.getTarget()+" 的"+jp.getSignature().getName()
				+" 方法。方法入参:"+Arrays.toString(jp.getArgs())+result);
		try{
			log.info("调用了 "+jp.getTarget()+" 的 "+jp.getSignature().getName()
			+" 方法");
		}catch(Throwable e){
			log.error(jp.getSignature().getName()+" 方法发生异常: "+e);
			throw e;
		}finally{
			log.info(jp.getSignature().getName()+"方法执行结束");
		}
	}
}

解释:

1、@Aspect 将某个类定义为切面,使用@Before 将before() 方法定义为前置增强,使用@AfterReturning 将after()方法定义为后置增强。

2、为了获取当前连接点的信息,添加JoinPoint类型参数,Spring会自动注入该实例。

3、对于后置增强,还可以定义一个参数,用于接收目标方法的返回值,但要在@AfterReturning的returning属性指定参数名,Spring会自动将目标方法返回值赋值给指定名称参数



UserserviceLogger2.java:

package com.smbms.AopLog;

import java.util.Arrays;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class UserserviceLogger2 {
	private static final Logger log = Logger.getLogger(UserserviceLogger.class);
	
	@Pointcut("execution(* com.smbms.pojo..*.*(..))")
	public void pointcut(){}
	
	//前置增强方法
	@Before("pointcut()")
	public void before (JoinPoint jp) throws Throwable{
		log.info("***UserserviceLogger2*********before:调用了"+jp.getTarget()+" 的"+jp.getSignature().getName()
				+" 方法。方法入参:"+Arrays.toString(jp.getArgs()));
		try{
			log.info("调用了 "+jp.getTarget()+" 的 "+jp.getSignature().getName()
			+" 方法。");
		}catch(Throwable e){
			log.error(jp.getSignature().getName()+" 方法发生异常: "+e);
			throw e;
		}finally{
			log.info(jp.getSignature().getName()+"方法执行结束");
		}
	}
	
	@AfterReturning(pointcut = "pointcut()",returning = "result")
	//后置增强方法
	public void after (JoinPoint jp,Object result) throws Throwable{
		log.info("***UserserviceLogger2***********after:调用了 "+jp.getTarget()+" 的"+jp.getSignature().getName()
				+" 方法。方法入参:"+Arrays.toString(jp.getArgs())+result);
		try{
			log.info("调用了 "+jp.getTarget()+" 的 "+jp.getSignature().getName()
			+" 方法");
		}catch(Throwable e){
			log.error(jp.getSignature().getName()+" 方法发生异常: "+e);
			throw e;
		}finally{
			log.info(jp.getSignature().getName()+"方法执行结束");
		}
	}
}


解释:

1、@Before和@AfterReturning注解分别指定各自切入点为 com.smbms.pojo.. 包下面的所有类所有方法,对于所有相同的切入点,其实可以统一定义,以便于维护重用。

2、如上所示,@Pointcut 定义切入点表达式,切入点签名通过一个普通方法表示。



【2】使用了注解,配置文件就会变得简单了,在 applicationContext-mybatis.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:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-2.5.xsd">
	
	
	<!-- 数据源配置 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 
	     destroy-method="close">
	<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
	<property name="url">
		<value><![CDATA[jdbc:mysql://127.0.0.1:3306/test?
				useUnicode=true&characterEncoding=utf-8]]></value>
	</property>
	<property name="username" value="root"></property>
	<property name="password" value=""></property>    
    </bean>
    
    <!-- SqlSessionFactoryBean 配置 -->
    <bean id="sqlSessionFactory"
    		class="org.mybatis.spring.SqlSessionFactoryBean">
	<!-- 引用数据源组件 -->
		<property name="dataSource" ref="dataSource"></property>
	<!-- 引用Mybatis配置文件的配置 -->
		<property name="configLocation" 
		        value="classpath:mybatis-config.xml"></property>
	<!-- 配置SQL映射文件信息 ,逐个列出SQL映射文件麻烦,所以使用 mapperLocations 属性扫描加载SQL映射文件-->
	    <property name="mapperLocations">
	    	<list>
	    		<value>classpath:com/smbms/pojo/**/*.xml</value>
	    	</list>
	    </property>
    </bean>
    
    <!-- 配置SQLSessionTemplate -->
   	<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
   		<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
   	</bean>
   	<!-- 配置DAO组件并进入SQLSessionTemplate实例 -->
   	<bean id="userMapper" class="com.smbms.pojo.UserMapperImpl">
   		<constructor-arg name="sqlSession" ref="sqlSessionTemplate"></constructor-arg>
   	</bean>
	
   	<!-- 配置业务Bean并注入DAO实例 -->
   	<bean id="userService" class="com.smbms.pojo.UserServiceImpl">
   		<property name="userMapper" ref="userMapper"></property>
   	</bean>

    <context:component-scan base-package="com.smbms"></context:component-scan>
   	<!-- 因为bean不被引用,所以不加id -->
   	<bean class="com.smbms.AopLog.UserserviceLogger"></bean>   	
    <bean class="com.smbms.AopLog.UserserviceLogger2"></bean>
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
     
</beans>

【3】其他的bean和接口和实现类省略,重在aop的使用。


【4】输出结果:

INFO  12-31 12:11:22,713 ***UserserviceLogger*********before:璋冪敤浜哻om.smbms.pojo.UserServiceImpl@35841320 鐨刦indUsersWithConditions 鏂规硶銆傛柟娉曞叆鍙傦細[com.smbms.pojo.User@3cce5371]  (UserserviceLogger.java:17) 
INFO  12-31 12:11:22,713 璋冪敤浜? com.smbms.pojo.UserServiceImpl@35841320 鐨? findUsersWithConditions 鏂规硶銆?  (UserserviceLogger.java:20) 
INFO  12-31 12:11:22,714 findUsersWithConditions鏂规硶鎵ц缁撴潫  (UserserviceLogger.java:26) 
DEBUG 12-31 12:11:22,714 Returning cached instance of singleton bean 'com.smbms.AopLog.UserserviceLogger2#0'  (AbstractBeanFactory.java:247) 
INFO  12-31 12:11:22,715 ***UserserviceLogger2*********before:璋冪敤浜哻om.smbms.pojo.UserServiceImpl@35841320 鐨刦indUsersWithConditions 鏂规硶銆傛柟娉曞叆鍙傦細[com.smbms.pojo.User@3cce5371]  (UserserviceLogger2.java:22) 
INFO  12-31 12:11:22,715 璋冪敤浜? com.smbms.pojo.UserServiceImpl@35841320 鐨? findUsersWithConditions 鏂规硶銆?  (UserserviceLogger2.java:25) 
INFO  12-31 12:11:22,715 findUsersWithConditions鏂规硶鎵ц缁撴潫  (UserserviceLogger2.java:31) 
INFO  12-31 12:11:22,716 ***UserserviceLogger*********before:璋冪敤浜哻om.smbms.pojo.UserMapperImpl@19932c16 鐨刧etUserList 鏂规硶銆傛柟娉曞叆鍙傦細[com.smbms.pojo.User@3cce5371]  (UserserviceLogger.java:17) 
INFO  12-31 12:11:22,716 璋冪敤浜? com.smbms.pojo.UserMapperImpl@19932c16 鐨? getUserList 鏂规硶銆?  (UserserviceLogger.java:20) 
INFO  12-31 12:11:22,717 getUserList鏂规硶鎵ц缁撴潫  (UserserviceLogger.java:26) 
INFO  12-31 12:11:22,717 ***UserserviceLogger2*********before:璋冪敤浜哻om.smbms.pojo.UserMapperImpl@19932c16 鐨刧etUserList 鏂规硶銆傛柟娉曞叆鍙傦細[com.smbms.pojo.User@3cce5371]  (UserserviceLogger2.java:22) 
INFO  12-31 12:11:22,717 璋冪敤浜? com.smbms.pojo.UserMapperImpl@19932c16 鐨? getUserList 鏂规硶銆?  (UserserviceLogger2.java:25) 
INFO  12-31 12:11:22,718 getUserList鏂规硶鎵ц缁撴潫  (UserserviceLogger2.java:31) 
DEBUG 12-31 12:11:22,723 Creating a new SqlSession  (JakartaCommonsLoggingImpl.java:54) 
DEBUG 12-31 12:11:22,769 SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@69c81773] was not registered for synchronization because synchronization is not active  (JakartaCommonsLoggingImpl.java:54) 
DEBUG 12-31 12:11:22,821 Fetching JDBC Connection from DataSource  (DataSourceUtils.java:110) 
DEBUG 12-31 12:11:25,399 JDBC Connection [jdbc:mysql://127.0.0.1:3306/test?
				useUnicode=true&characterEncoding=utf-8, UserName=root@localhost, MySQL Connector Java] will not be managed by Spring  (JakartaCommonsLoggingImpl.java:54) 
DEBUG 12-31 12:11:25,407 ==>  Preparing: select u.* ,r.roleName from smbms_user u ,smbms_role r where u.userName like CONCAT('%',?,'%') and u.userRole = ? and u.userRole = r.id   (JakartaCommonsLoggingImpl.java:54) 
DEBUG 12-31 12:11:25,479 ==> Parameters: mmb(String), 110(Integer)  (JakartaCommonsLoggingImpl.java:54) 
DEBUG 12-31 12:11:26,042 <==    Columns: id, userCode, userName, userPassword, gender, birthday, phone, address, userRole, createBy, createDate, modifyBy, modifyDate, roleName  (JakartaCommonsLoggingImpl.java:59) 
DEBUG 12-31 12:11:26,045 <==        Row: 1, test01, mmb02, 9876543210, 2, 1991-12-29, 0000, maoming, 110, 1, 2017-12-17 10:50:04.0, null, null, guan_li_yuan  (JakartaCommonsLoggingImpl.java:59) 
DEBUG 12-31 12:11:26,061 <==        Row: 2, test01, mmb02, scua, 2, 1991-12-29, 0000, maoming, 110, 1, 2017-12-17 10:56:48.0, null, null, guan_li_yuan  (JakartaCommonsLoggingImpl.java:59) 
DEBUG 12-31 12:11:26,063 <==        Row: 3, test01, mmb02, scua, 2, 1991-12-29, 0000, maoming, 110, 1, 2017-12-17 10:58:46.0, null, null, guan_li_yuan  (JakartaCommonsLoggingImpl.java:59) 
DEBUG 12-31 12:11:26,064 <==        Row: 4, test01, mmb02, scua, 2, 1991-12-29, 0000, maoming, 110, 1, 2017-12-17 11:01:42.0, null, null, guan_li_yuan  (JakartaCommonsLoggingImpl.java:59) 
DEBUG 12-31 12:11:26,065 <==        Row: 5, test01, mmb02, scua, 2, 1991-12-29, 0000, maoming, 110, 1, 2017-12-17 11:03:05.0, null, null, guan_li_yuan  (JakartaCommonsLoggingImpl.java:59) 
DEBUG 12-31 12:11:26,066 <==      Total: 5  (JakartaCommonsLoggingImpl.java:54) 
DEBUG 12-31 12:11:26,081 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@69c81773]  (JakartaCommonsLoggingImpl.java:54) 
DEBUG 12-31 12:11:26,081 Returning JDBC Connection to DataSource  (DataSourceUtils.java:327) 
INFO  12-31 12:11:26,082 ***UserserviceLogger2***********after:璋冪敤浜? com.smbms.pojo.UserMapperImpl@19932c16 鐨刧etUserList 鏂规硶銆傛柟娉曞叆鍙傦細[com.smbms.pojo.User@3cce5371][com.smbms.pojo.User@51a9ad5e, com.smbms.pojo.User@5f20155b, com.smbms.pojo.User@72ade7e3, com.smbms.pojo.User@239105a8, com.smbms.pojo.User@3fce8fd9]  (UserserviceLogger2.java:38) 
INFO  12-31 12:11:26,082 璋冪敤浜? com.smbms.pojo.UserMapperImpl@19932c16 鐨? getUserList 鏂规硶  (UserserviceLogger2.java:41) 
INFO  12-31 12:11:26,083 getUserList鏂规硶鎵ц缁撴潫  (UserserviceLogger2.java:47) 
INFO  12-31 12:11:26,083 ****UserserviceLogger**********after:璋冪敤浜? com.smbms.pojo.UserMapperImpl@19932c16 鐨刧etUserList 鏂规硶銆傛柟娉曞叆鍙傦細[com.smbms.pojo.User@3cce5371][com.smbms.pojo.User@51a9ad5e, com.smbms.pojo.User@5f20155b, com.smbms.pojo.User@72ade7e3, com.smbms.pojo.User@239105a8, com.smbms.pojo.User@3fce8fd9]  (UserserviceLogger.java:34) 
INFO  12-31 12:11:26,083 璋冪敤浜? com.smbms.pojo.UserMapperImpl@19932c16 鐨? getUserList 鏂规硶  (UserserviceLogger.java:37) 
INFO  12-31 12:11:26,083 getUserList鏂规硶鎵ц缁撴潫  (UserserviceLogger.java:43) 
INFO  12-31 12:11:26,084 ***UserserviceLogger2***********after:璋冪敤浜? com.smbms.pojo.UserServiceImpl@35841320 鐨刦indUsersWithConditions 鏂规硶銆傛柟娉曞叆鍙傦細[com.smbms.pojo.User@3cce5371][com.smbms.pojo.User@51a9ad5e, com.smbms.pojo.User@5f20155b, com.smbms.pojo.User@72ade7e3, com.smbms.pojo.User@239105a8, com.smbms.pojo.User@3fce8fd9]  (UserserviceLogger2.java:38) 
INFO  12-31 12:11:26,084 璋冪敤浜? com.smbms.pojo.UserServiceImpl@35841320 鐨? findUsersWithConditions 鏂规硶  (UserserviceLogger2.java:41) 
INFO  12-31 12:11:26,084 findUsersWithConditions鏂规硶鎵ц缁撴潫  (UserserviceLogger2.java:47) 
INFO  12-31 12:11:26,084 ****UserserviceLogger**********after:璋冪敤浜? com.smbms.pojo.UserServiceImpl@35841320 鐨刦indUsersWithConditions 鏂规硶銆傛柟娉曞叆鍙傦細[com.smbms.pojo.User@3cce5371][com.smbms.pojo.User@51a9ad5e, com.smbms.pojo.User@5f20155b, com.smbms.pojo.User@72ade7e3, com.smbms.pojo.User@239105a8, com.smbms.pojo.User@3fce8fd9]  (UserserviceLogger.java:34) 
INFO  12-31 12:11:26,084 璋冪敤浜? com.smbms.pojo.UserServiceImpl@35841320 鐨? findUsersWithConditions 鏂规硶  (UserserviceLogger.java:37) 
INFO  12-31 12:11:26,084 findUsersWithConditions鏂规硶鎵ц缁撴潫  (UserserviceLogger.java:43) 
testGetUserList userCode:test01userName: mmb02userRole: 110userRoleName: guan_li_yuanuserAddress: null
testGetUserList userCode:test01userName: mmb02userRole: 110userRoleName: guan_li_yuanuserAddress: null
testGetUserList userCode:test01userName: mmb02userRole: 110userRoleName: guan_li_yuanuserAddress: null
testGetUserList userCode:test01userName: mmb02userRole: 110userRoleName: guan_li_yuanuserAddress: null
testGetUserList userCode:test01userName: mmb02userRole: 110userRoleName: guan_li_yuanuserAddress: null

继续,下面是定义异常抛出增强:Spring(12):使用注解(@AfterThrowing/@After/@Around)实现AOP异常增强与实例


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值