`
jinyanhui2008
  • 浏览: 319544 次
  • 性别: 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
    分享到:
    评论

    相关推荐

      Java框架技术 Spring 学习案例 Spring AOP案例和Spring事务处理案例

      同时,这些案例也鼓励你思考如何利用Spring框架解决实际业务场景中的问题,提升你的编程技能和解决问题的能力。 总的来说,Spring框架的AOP和事务处理是Java开发中的重要工具,它们为开发者提供了强大的功能,以更...

      spring2-aop.pdf

      SpringAOP的配置方法可以灵活地定义切点和通知,以及如何将它们应用到目标对象上。 SpringAOP还支持使用ProxyFactoryBean来创建代理对象,以实现AOP的功能。ProxyFactoryBean是Spring中的一个工厂bean,它可以用来...

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

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

      引出对Spring底层实现再思考

      Spring框架是Java开发中不可或缺的一部分,它以其强大的依赖注入(DI)和面向切面编程(AOP)功能闻名。在深入探讨Spring的底层实现时,我们需要理解几个关键概念和技术。 首先,Spring的核心在于IoC(Inversion of...

      SPRING3技术内幕

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

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

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

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

       如果你正在思考下面这些问题,也许《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原始...

      Spring应用开发代码

      Spring框架是Java开发中广泛应用的一个开源框架,以其强大的依赖注入(Dependency Injection,简称DI)和面向切面编程(Aspect-...记得在实践中不断思考,将理论知识与实践相结合,这样才能真正掌握Spring的魅力所在。

      spring4源码

      Spring4的一些改进为Spring 5的反应式编程打下了基础。 8. **性能优化**:Spring4 通过减少内存消耗和提高并发性能,提升了整体运行效率。例如,Bean的实例化过程更加高效,对容器的初始化进行了优化。 9. **错误...

      学习Spring 的例子JpetStore

      《Spring框架学习:以JpetStore为例》 Spring框架是Java企业级应用开发中的核心...在学习过程中,我们不仅要理解代码的结构和逻辑,还要思考这些设计背后的原理和最佳实践,以便在自己的项目中发挥Spring的最大价值。

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

      2. **AOP(Aspect Oriented Programming)面向切面编程**:Spring提供了AOP支持,允许开发者定义横切关注点,如日志、事务管理等,提高了代码的复用性和可维护性。 3. **Bean的生命周期管理**:书中详细解释了...

      spring4.2.4源码

      Spring框架是中国Java开发领域中最广泛使用的轻量级框架之一,其4.2.4版本是一个稳定且成熟的版本,包含了对IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)的重要实现。...

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

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

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

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

      spring-配套代码

      首先,Spring 是一个开源的、基于 IoC(Inversion of Control,控制反转)和 AOP(Aspect-Oriented Programming,面向切面编程)的轻量级框架。IoC 使得应用程序的组件之间依赖关系由容器来管理,而不是由组件自己...

      模拟spring和工具jar包

      5. **AOP**:虽然标题和描述没有明确提到,但如果是对Spring的全面模拟,面向切面编程可能也有所涉及。AOP允许我们在不修改代码的情况下添加新的行为,比如日志记录、事务管理等。 6. **工具jar包**:这个可能包含...

      spring入门的所有代码,可以运行

      Spring框架是Java开发中广泛使用的轻量级框架,它以依赖注入(Dependency Injection,简称DI)为核心,旨在简化企业级应用开发。...记得在学习过程中多思考、多实践,祝你在Spring的学习旅程中取得丰硕的成果!

      SPRING3技术内幕.z01

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

      spring3.2源码包

      Spring框架由多个模块组成,包括Core Container(核心容器)、Data Access/Integration(数据访问/集成)、Web、AOP(面向切面编程)、Instruments(仪表)和Messaging(消息)。这些模块相互独立,可以根据项目...

    Global site tag (gtag.js) - Google Analytics