`
jinyanhui2008
  • 浏览: 312934 次
  • 性别: Icon_minigender_1
  • 来自: 青岛
社区版块
存档分类
最新评论

关于spring aop的一些思考

阅读更多

最近在考虑数据流压缩的问题,因为不想去更改程序了,所以选择使用springaop来实现这些处理。

经过查阅相关资料,类型包括“around”、“before”和“after”。

 

  • 前置通知(Before advice): 在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。

  • 返回后通知(After returning advice): 在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。

  • 抛出异常后通知(After throwing advice): 在方法抛出异常退出时执行的通知。

  • 后通知(After (finally) advice): 当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。 

    我在测试里面,在系统中最常用到的类型应该是Beforeadvice, AfterThrowingadvice了。

    我在系统中使用AfterThrowingadvice来作为异常事务处理。使用Beforeadvice+After (finally) advice或者around作为日志记录服务来使用。

    因为我对上面的一些里面并不是太懂只写一写我在系统中真正用到的一些功能,如日志服务、异常事务处理、全程监控函数执行情况并可一个对返回值传入值进行修改删除等操作。

    首先说的是日志服务,我在日志服务里面使用的是before,因为我只需要记录谁什么时间调用了什么函数,置于函数调用是否成功并不关心,如果需要验证是否成功的话我觉得可能需要结合Beforeadvice+After (finally) advice来实现吧。

    代码示例:

    package com.wfy.system.service.impl;
    
    import java.lang.reflect.Method;
    import java.sql.DriverManager;
    import java.util.List;
    import java.util.Map;
    import org.aspectj.lang.JoinPoint;
    import org.springframework.aop.AfterAdvice;
    import org.springframework.aop.AfterReturningAdvice;
    import org.springframework.aop.BeforeAdvice;
    import com.sybase.jdbcx.SybDriver;
    import org.aopalliance.aop.Advice;
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    
    public class SystemLogServiceImpl implements ISystemLogService {
    
    	public void before(JoinPoint point){
    System.err.println(point.getSignature().getDeclaringTypeName() +" 类中的 " + point.getSignature().getName() + " 方法在 "+ TimeUtil.dateTime5() +" 被调用了");
    		Object [] objs = point.getArgs();
    		if(point.getSignature().getDeclaringTypeName().indexOf("FyErpDataFransmissionWebServiceImpl")>=0){
    			if(point.getSignature().getName().equals("clientCheck")){
    				LogUtil.writeLog("验证登录系统信息,设备号:"+ objs[0]);
    			}
    			if(point.getSignature().getName().equals("deleteLog")){
    				LogUtil.writeLog("删除服务器日志信息,机器号:"+ objs[0] +" 表名:"+ objs[1] +" 小于:"+ objs[2] +"的所有数据");
    			}
    			if(point.getSignature().getName().equals("downloadData")){
    				LogUtil.writeLog("下载数据,机器号:"+ objs[0] +" 表名:"+ objs[1] +" 下载数量:"+ objs[2] +"的所有数据");
    			}
    			if(point.getSignature().getName().equals("downloadKey")){
    				LogUtil.writeLog("下载主键信息,机器号:"+ objs[0] +" 表名:"+ objs[1] +"的所有数据");
    			}
    			if(point.getSignature().getName().equals("downloadRecords")){
    				LogUtil.writeLog("下载总更新数量信息,机器号:"+ objs[0] +" 表名:"+ objs[1] +"的所有数据");
    			}	
    			if(point.getSignature().getName().equals("downloadTable")){
    				LogUtil.writeLog("下载更新表头信息");
    			}
    			if(point.getSignature().getName().equals("uploadTable")){
    				LogUtil.writeLog("更新服务器端数据,表名:"+ objs[0] +"的所有更新数据");
    			}	
    			if(point.getSignature().getName().equals("writeLog")){
    				LogUtil.writeLog("记录客户端异常,"+objs[0]);
    			}			
    		}
    	 }
    }

    配置文件部分:

    	<!-- 日志管理程序 -->
    	<aop:config>
    		<aop:pointcut id="SystemLogPointcut" expression="execution(* *..*Service.*(..))" />
    		<aop:aspect id="beforeExample" ref="ISystemLogSession">
    			<aop:before pointcut-ref="SystemLogPointcut" method="before" />
    		</aop:aspect>
    	<bean id="ISystemLogSession" class="com.wfy.system.service.impl.SystemLogServiceImpl"></bean>
    	<!-- 日志管理程序 -->

    基本上这就是我的简单日志服务了,我根据不同的方法名来翻译不同的操作信息,但是并不考虑是否操作成功。

     

    然后就是异常事务处理了

    java代码:

     

    package com.wfy.exceptionAdvisor;
    
    import org.springframework.aop.ThrowsAdvice;
    import org.springframework.dao.DataAccessException;
    import org.springframework.dao.DataIntegrityViolationException;
    import org.springframework.jdbc.BadSqlGrammarException;
    
    import com.microsoft.sqlserver.jdbc.SQLServerException;
    import com.wfy.util.LogUtil;
    
    import java.io.IOException;
    import java.lang.reflect.Method;
    import java.sql.SQLException;
    
    public class ExceptionAdvisor implements ThrowsAdvice {
        public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable {
            //System.out.println("*************************************************************************************************************");
            //System.out.println("Error happened in class: " + target.getClass().getName());
            //System.out.println("Error happened in method: " + method.getName());
            for (int i = 0; i < args.length; i++) {
                //System.out.println("arg[" + i + "]: " + args[i]);		//如果取消这是可以详细打印错误信息。
            }
            //System.out.println("Exception class: " + ex.getClass().getName());
            //System.out.println("ex.getMessage():"+ex.getMessage());
            ex.printStackTrace();
            //System.out.println("*************************************************************************************************************");
    		
            
            if(target.getClass().getName().indexOf("FyErpDataFransmissionWebServiceImpl")>=0){//对错误信息进行日志输出,也就是前面我提到的日志,这里记录的是错误日志。
    			if(method.getName().equals("clientCheck")){
    				LogUtil.writeLog("验证登录系统信息,设备号:"+ args[0] +"   "+ex.getMessage());
    			}
    			if(method.getName().equals("deleteLog")){
    				LogUtil.writeLog("删除服务器日志信息,机器号:"+ args[0] +" 表名:"+ args[1] +" 小于:"+ args[2] +"的所有数据   "+ex.getMessage());
    			}
    			if(method.getName().equals("downloadData")){
    				LogUtil.writeLog("下载数据,机器号:"+ args[0] +" 表名:"+ args[1] +" 下载数量:"+ args[2] +"的所有数据   "+ex.getMessage());
    			}
    			if(method.getName().equals("downloadKey")){
    				LogUtil.writeLog("下载主键信息,机器号:"+ args[0] +" 表名:"+ args[1] +"的所有数据   "+ex.getMessage());
    			}
    			if(method.getName().equals("downloadRecords")){
    				LogUtil.writeLog("下载总更新数量信息,机器号:"+ args[0] +" 表名:"+ args[1] +"的所有数据   "+ex.getMessage());
    			}	
    			if(method.getName().equals("downloadTable")){
    				LogUtil.writeLog("下载更新表头信息   "+ex.getMessage());
    			}
    			if(method.getName().equals("uploadTable")){
    				LogUtil.writeLog("更新服务器端数据,表名:"+ args[0] +"的所有更新数据   "+ex.getMessage());
    			}	
    			if(method.getName().equals("writeLog")){
    				LogUtil.writeLog("记录客户端异常,"+args[0]+"   "+ex.getMessage());
    			}			
    		}
            if(ex.getClass().equals(BusinessException.class)){//如果是这个异常的话说明是人为抛出的错误信息,不进行转换直接抛出。
            	ex.printStackTrace();
    			throw ex;
            }else if(ex.getClass().equals(DataIntegrityViolationException.class)){
            	throw new BusinessException("保存的字符串异常!");
            }else if(ex.getClass().equals(DataAccessException.class)){
    			throw new BusinessException("数据库操作失败!");
    		}else if(ex.getClass().toString().equals(NullPointerException.class.toString())) {
    			throw new BusinessException("调用了未经初始化的对象或者是不存在的对象!");
    		}else if(ex.getClass().equals(IOException.class)) {
    			throw new BusinessException("IO异常!");
    		}else if(ex.getClass().equals(ClassNotFoundException.class)) {
    			throw new BusinessException("指定的类不存在!");
    		}else if(ex.getClass().equals(ArithmeticException.class)) {
    			throw new BusinessException("数学运算异常!");
    		}else if(ex.getClass().equals(ArrayIndexOutOfBoundsException.class)) {
    			throw new BusinessException("数组下标越界!");
    		}else if(ex.getClass().equals(IllegalArgumentException.class)) {
    			throw new BusinessException("方法的参数错误!");
    		}else if(ex.getClass().equals(ClassCastException.class)) {
    			throw new BusinessException("类型强制转换错误!");
    		}else if(ex.getClass().equals(SecurityException .class)) {
    			throw new BusinessException("违背安全原则异常!");
    		}else if(ex.getClass().equals(SQLException.class)) {
    			throw new BusinessException("操作数据库异常!");
    		}else if(ex.getClass().equals(NoSuchMethodError.class)) {
    			throw new BusinessException("方法末找到异常!");
    		}else if(ex.getClass().equals(InternalError.class)) {
    			throw new BusinessException("Java虚拟机发生了内部错误");
    		}else if(ex.getClass().equals(BadSqlGrammarException.class)){
    			throw new BusinessException(ex.getMessage());
    		}else if(ex.getClass().equals(SQLServerException.class)){
    			throw new BusinessException(ex.getMessage());
    		}else{
    			throw new BusinessException("程序内部错误,操作失败!"+ex.getMessage());
    		}
        }
    }
    

     

     

    package com.wfy.exceptionAdvisor;
    public class BusinessException extends RuntimeException {
    	private static final long serialVersionUID = 3152616724785436891L;
    
        public BusinessException(String frdMessage) {
            super(createFriendlyErrMsg(frdMessage));
        }
    
        public BusinessException(Throwable throwable) {
            super(throwable);
        }
        public BusinessException(Throwable throwable, String frdMessage) {
            super(throwable);
        }
    
        private static String createFriendlyErrMsg(String msgBody){
    		String prefixStr = "抱歉,";
    		String suffixStr = " 请稍后再试或与管理员联系!";
    	
    		StringBuffer friendlyErrMsg = new StringBuffer("");
    	
    		friendlyErrMsg.append(prefixStr);
    	
    		friendlyErrMsg.append(msgBody);
    	
    		friendlyErrMsg.append(suffixStr);
    	
    		return friendlyErrMsg.toString();
    	}
    }
    

    xml代码:

     

    <!-- 异常处理aop -->
    	<bean id="exceptionHandler" class="com.wfy.exceptionAdvisor.ExceptionAdvisor"></bean>
    	<bean id="BeanNameAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    		<property name="beanNames">
    			<list>
    				<value>*Service</value>
    				<!-- <value>*Session</value> -->
    			</list>
    		</property>
    		<property name="interceptorNames">
    			<value>exceptionHandler</value>
    		</property>
    	</bean>
    	<!-- 异常处理aop -->	
     

    然后还有一个就是一个比较牛B的东西了,MethodInterceptor,他能让你从函数调用开始到函数调用结束对数据进行全程的监控,甚至可以修改传入函数的参数以及返回值。

    java代码:

     

    package com.wfy.system.service.impl;
    
    import java.lang.reflect.Method;
    import java.sql.DriverManager;
    import java.util.List;
    import java.util.Map;
    import org.aspectj.lang.JoinPoint;
    import org.springframework.aop.AfterAdvice;
    import org.springframework.aop.AfterReturningAdvice;
    import org.springframework.aop.BeforeAdvice;
    
    import com.wfy.exceptionAdvisor.BusinessException;
    import com.wfy.system.service.IDynamicDataSession;
    import com.wfy.system.service.ISystemLogSession;
    import com.wfy.util.JRockey2;
    import com.wfy.util.JSecurity;
    import com.wfy.util.LogUtil;
    import com.wfy.util.TimeUtil;
    import com.sybase.jdbcx.SybDriver;
    import org.aopalliance.aop.Advice;
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    
    public class SystemLogSessionImpl implements MethodInterceptor{
    	@Override
    	public Object invoke(MethodInvocation method) throws Throwable {
    		Object result = null;
    		result = method.proceed();
    		result = result.toString()+"我改过了";
    		return result;
    	}	 
    }
    

  •   xml代码:

     

    	<bean id="ISystemLogSession" class="com.wfy.system.service.impl.SystemLogSessionImpl">
    	</bean>
    	
    	<!-- 异常处理aop -->
    	<bean id="exceptionHandler" class="com.wfy.exceptionAdvisor.ExceptionAdvisor"></bean>
    	<bean id="BeanNameAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    		<property name="beanNames">
    			<list>
    				<value>*Service</value>
    				<!-- <value>*Session</value> -->
    			</list>
    		</property>
    		<property name="interceptorNames">
    			<value>ISystemLogSession</value>
    		</property>
    	</bean>
     

     

     

    这样配置完了就能对每一个Method进行处理了,从函数调用直到函数调用结束返回结果全程进行监控。

    甚至日志处理、异常处理等等操作都可以在此基础上来完成,哈哈确实很强悍。

     

    总结来说,spring aop非常值的深入研究。使用aop可以对传入参数进行安全验证、权限控制等等一系列操作。

     

     

    1
    0
    分享到:
    评论

    相关推荐

      spring aop 拦截器简单实现

      非常简单的aop例子,可以从该离子出发隐身出很多其他的问题的思考。

      合集Java流行框架分析:Spring源码、SpringBoot源码、SpringAOP源码

      对于框架底层的学习,需要反复、认真思考,并做到温故而知新,这样才能将底层原理吸收得更早。 学习一个框架的源码,不仅在实际使用时如果出现问题,可以快速定位出问题,找到问题原因并解决,同时还可以学习到...

      Spring技术内幕:深入解析Spring架构与设计原理(第2部分)

       如果你正在思考下面这些问题,也许《Spring技术内幕:深入解析Spring架构与设计原理》就是你想要的!  掌握Spring的架构原理与设计思想真的能让开发者如虎添翼吗?  IoC容器如何掌控以POJO为基础的Bean对象?它...

      SPRING3技术内幕

       如果你正在思考下面这些问题,也许《Spring技术内幕:深入解析Spring架构与设计原理》就是你想要的!  掌握Spring的架构原理与设计思想真的能让开发者如虎添翼吗?  IoC容器如何掌控以POJO为基础的Bean对象?...

      JavaSourceCodeLearning:Java流行框架源码分析:Spring源码,SpringBoot源码,SpringAOP源码,SpringSecurity源码,SpringSecurity OAuth2源码,JDK源码,Netty

      :check_mark_button: SpringAOP源码 :check_mark_button: SpringSecurity原始码 :check_mark_button: SpringSecurity OAuth2原始码 :check_mark_button: JDK原始码 :check_mark_button: Dubbo原始码 Netty原始...

      Chapter 6_ 使用Spring进行面向切面编程(AOP)

      面向切面编程(AOP)提供另外一种角度来思考程序结构,通过这种方式弥补了面向对象编程(OOP)的不足。 除了类(classes)以外,AOP提供了 切面。切面对关注点进行模块化,例如横切多个类型和对象的事务管理。

      Spring技术内幕:深入解析Spring架构与设计原理

       如果你正在思考下面这些问题,也许《Spring技术内幕:深入解析Spring架构与设计原理》就是你想要的!  掌握Spring的架构原理与设计思想真的能让开发者如虎添翼吗?  IoC容器如何掌控以POJO为基础的Bean对象?...

      Spring技术内幕:深入解析Spring架构与设计原理(第1部分)

       如果你正在思考下面这些问题,也许《Spring技术内幕:深入解析Spring架构与设计原理》就是你想要的!  掌握Spring的架构原理与设计思想真的能让开发者如虎添翼吗?  IoC容器如何掌控以POJO为基础的Bean对象?它...

      Spring技术内幕:深入解析Spring架构与设计原理(第一部分)

       如果你正在思考下面这些问题,也许《Spring技术内幕:深入解析Spring架构与设计原理》就是你想要的!  掌握Spring的架构原理与设计思想真的能让开发者如虎添翼吗?  IoC容器如何掌控以POJO为基础的Bean对象?它...

      SPRING3技术内幕.z01

       如果你正在思考下面这些问题,也许《Spring技术内幕:深入解析Spring架构与设计原理》就是你想要的!  掌握Spring的架构原理与设计思想真的能让开发者如虎添翼吗?  IoC容器如何掌控以POJO为基础的Bean对象?...

      Spring.net框架

      本部分代码仅仅提供一种功能演示,如果实际应用仍需进一步完善(建议使用一些成型的Ioc框架,例如Spring.net或Castle等)。经过改造后 的系统,组件间依赖关系如下图: 可以看出这次实现了真正的“针对接口编程”...

      Spring技术内幕

      , 如果你也在思考下面的问题,本书也许就是你想要的:, 掌握Spring的架构原理与设计思想真的能让开发者如虎添翼吗?, IoC容器如何掌控以POJO为基础的Bean对象?它的轻量级开发设计思想是如何实现的?, Spring产品级...

      第24次课-1 Spring与Hibernate的整合

      HibernateDaoSupport提供了基于AOP事务的自动处理,程序员完全可以不用理会事务的开始与提交,它会自动完成SessionFactory的注入和事务的注入。 24.3 Spring对Hibernate的简化 24.3.5 HibernateDaoSupport ...

      贫血模式下的SSH处理日志管理以及对权限管理的思考

      在众多情况下,日志的管理是通过拦截器来完成的,不过通过STRUTS2的拦截器编码比较繁琐,在此通过spring的aop来处理,在贫血模式下将代码量降到最低,同时配置文件均可共用,从此,不用为日志管理浪费任何时间。

      基于ssm的旅游后台管理系统.zip

      使用AdminLTE 前端框架,实现基本的CRUD功能,使用spring-security进行用户登录权限控制,利用spring aop记录访问日志 毕业设计是高等教育阶段学生在完成学业前所进行的一项重要学术任务,旨在检验学生通过学习所...

      SpringBoot-Demo-master.zip

      其与设计模式完成的任务差不多,是提供另一种角度来思考程序的结构,来弥补面向对象编程的不足,这个可能是面试中经常提到的问题,同时它也是Spring框架中一个重大的特性,对于我们开发中最常见的可能就是日志记录,...

      第一讲-大型互联网项目架构设计实践及架构优化思路.pdf

      1、如何构建一个高可用,高并发的项目架构(架构方向思考: 项目架构问题) 2、压测方案(发现系统问题,进行修复,调试)-- 分析当前系统性能瓶颈,解读一些 压测报告 3、服务器(tomcat 服务器,undertow 服务调优...

    Global site tag (gtag.js) - Google Analytics