最近在考虑数据流压缩的问题,因为不想去更改程序了,所以选择使用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可以对传入参数进行安全验证、权限控制等等一系列操作。