Aop切面问题

AOP的使用

1. 在引入命名空间头的时候.顺序要保持一致
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" 
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation=" 
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
    http://www.springframework.org/schema/mvc 
    http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd 
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
2. SpringMVC中使用aop注解无效的问题
详细情况是这样的:项目引用了SpringMVC框架,在编写Controller以及Service的时候添加@Transactional的情况下和编写AspectJ的切面的情况下,事务和AOP都没有生效,而我的AOP配置是这样的:AOP命名空间和<aop:aspectj-autoproxy  proxy-target-class="true />这两个都配在了ApplicationContext.xml里面了,而不是SpringMVC框架自己约定的配置文件中(我这个项目里面,这个配置文件叫做springmvc-servlet.xml),正因为这样,出问题了。后来,我把AOP命名空间和<aop:aspectj-autoproxy  proxy-target-class="true />挪到SpringMVC自己的配置文件里面,AOP就生效了。同理,把注解相应的命名空间和<tx:annotation-driven>放在SpringMVC的配置文件里,事务也生效了。

另外以上所述的是对controller进行切面时的配置,如果是对service进行切面,那么


这两个注释就要用在ApplicationContext.xml里面了,注意此时不要开启aop的cglib代理模式。

解释:

1.SpringMVC这个框架很好用,没问题,他的注解也简化了很多的配置,但是请注意@Controller和@Service都是SpringMVC框架包里面的,也就是说,这些类的实例化以及注入也是由SpringMVC这个框架完成的(确切的来说是这个框架自己有的上下文的IoC容器完成的)。

2.而对AOP和事务的支持是Spring框架本身完成的,是Spring框架的应用上下文所扫描并处理的。

从1.2可以得出一个结论,如果SpringMVC和Spring本身用的是一个应用上下文,一个Ioc容器,那随便你的和命名空间配置在哪里,无论是Spring的ApplicationContext.xml还是SpringMVC的springmvc-servlet.xml里面,反正都是一个容器,怎么扫描,怎么处理都能找到。

但关键的是以上假设不成立,总的来说SpringMVC的应用上下文的 “ 父 ” 上下文才是Spring的应用上下文。那么这个也就是说Spring的应用上下文初始化完成的时候,它开始扫描到底哪些Bean用了AspectJ的注解,哪些用了Transactional的注解,但是利用SpringMVC注解配置的这些Bean它是找不到的,因为用了这些注解的Bean还没有被实例化甚至是还没有被装载,为什么呢?因为管理这些bean的SpringMVC的上下文可能还没有完成初始化。OK,既然Spring的上下文找不到到底哪些Bean应用了注解,那他自然也没有办法给这些Bean提供声明式AOP和事务的支持了。

### 问题3.
当 环绕通知捕获了异常, 异常通知 则不能执行

案列

1.创建注解
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; 

/** 
 * 表示对标记有xxx注解的类,做代理 注解@Retention可以用来修饰注解,是注解的注解,称为元注解。 
 * Retention注解有一个属性value,是RetentionPolicy类型的,Enum RetentionPolicy是一个枚举类型, 
 * 这个枚举决定了Retention注解应该如何去保持,也可理解为Rentention 搭配 
 * RententionPolicy使用。RetentionPolicy有3个值:CLASS RUNTIME SOURCE 
 * 用@Retention(RetentionPolicy.CLASS)修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,但不会被虚拟机读取在运行的时候; 
 * 用@Retention(RetentionPolicy.SOURCE)修饰的注解,表示注解的信息会被编译器抛弃,不会留在class文件中,注解的信息只会留在源文件中; 
 * 用@Retention(RetentionPolicy.RUNTIME)修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,会被虚拟机保留在运行时, 
 * 所以他们可以用反射的方式读取。RetentionPolicy.RUNTIME 
 * 可以让你从JVM中读取Annotation注解的信息,以便在分析程序的时候使用. 
 *  
 * 类和方法的annotation缺省情况下是不出现在javadoc中的,为了加入这个性质我们用@Documented 
 *  java用  @interface Annotation{ } 定义一个注解 @Annotation,一个注解是一个类。 
 *  @interface是一个关键字,在设计annotations的时候必须把一个类型定义为@interface,而不能用class或interface关键字 
  */
/**
 * 自定义注解 拦截方法 
 * @author xzb_l
 *
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented 
public @interface SystemMethodLog {
    String description() default "";
}
2.创建切面类
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.ServletWebRequest;

import com.ai.civil.common.Constants;
import com.ai.civil.common.util.SystemLogUtil;
import com.ai.civil.cs.entity.TbCivilUser;
import com.ai.civil.log.MongoLogWriter;
import com.ai.trial.ct.session.SessionValueHoderFactory;
import com.ai.trial.ct.session.SessionValueHolder;

/**
 * 系统日志切入点
 * @author xzb_l
 *
 */
@Aspect  
@Component
public class SystemLogAspect {
    @Autowired
    SessionValueHoderFactory sessionValueHoderFactory;
    @Resource
    MongoLogWriter logWriter;
    /**本地异常日志记录对象 */
    private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect.class);  

    /**
     * Method 切入点
     */
    @Pointcut("@annotation(com.ai.civil.annotation.SystemMethodLog)")
    public void sysMethodAspect() {}

    /**记录日志信息*/
    private static Map<String,String> loggerMap;

    /** 
     * 异常通知 用于拦截Method记录用户的操作 
     * 异常通知执行(最后),则后置通知不执行
     * @param joinPoint 切点 
     */  
   @AfterThrowing(value ="sysMethodAspect()",throwing = "e")  
   public void handleThrowing(JoinPoint joinPoint, Throwable e) { 
        try {  
            // 写入日志
            loggerMap = SystemLogUtil.exceptionInfoCollect(joinPoint, e,logWriter,loggerMap);
            loggerMap = null;
        } catch (Exception ex) {  
            //记录本地异常日志  
            logger.error("收集异常出错");  
            ex.printStackTrace();
        }  
    }
   /**
    * 前置通知
    */
   @Before("sysMethodAspect()")
   public void beforeInfo(JoinPoint point) {
       try {
           // 用于保存信息
           loggerMap = new LinkedHashMap<String,String>();
           HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            //请求的IP  
           String ip = this.getIpAddr(request);  
           // 记录方法执行之前的各项参数
           loggerMap = SystemLogUtil.permissionCheckInfo(point,getUserInfo(), ip,loggerMap);
        } catch (Exception e) {
            logger.error("收集异常出错");  
            e.printStackTrace();
        }
   }

   /**
    * 环绕通知
    * @param point
    * @throws Throwable
    */
   @Around("sysMethodAspect()")
   public Object process(ProceedingJoinPoint point) throws Throwable{
           // 执行目标方法
       Object returnValue = point.proceed();
       return  returnValue;
   }

   /**
    * 后置通知:当方法执行完会触发(写入日志)
    * 没有异常时后置通知执行最后
    * @param point
    * @param returnValue
    */
    @AfterReturning(value = "sysMethodAspect()", returning="returnValue")
    public void afterReturnInfo(JoinPoint point, Object returnValue) {
        try {
            loggerMap = SystemLogUtil.afterReturnInfo(point, getUserInfo(), returnValue,logWriter,loggerMap);
            loggerMap = null;
        } catch (Exception e) {
            logger.error("收集异常出错");  
            e.printStackTrace();
        }
    }

    /**
     * 最终通知 (始终执行)
     * @param point
     */
    @After("sysMethodAspect()")
    public void afterInfo(JoinPoint point) {
        try {
            // 记录方法执行之后的各项参数
          loggerMap = SystemLogUtil.releaseResourceInfo(point,loggerMap);
        } catch (Exception e) {
            logger.error("收集异常出错");  
            e.printStackTrace();
        }
    }

    /**
     * 获取当前操作用户
     * @return
     */
    public TbCivilUser getUserInfo() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        ServletWebRequest servletWebRequest=new ServletWebRequest(request);
        HttpServletResponse response=servletWebRequest.getResponse();
        SessionValueHolder sessionValueHolder = sessionValueHoderFactory.getSessionValueHolder(request, response);
        TbCivilUser user = (TbCivilUser)sessionValueHolder.getValue(Constants.CUR_USER);
        if (user == null) {
            user = new TbCivilUser(); 
        }
        return user;
    }

    /**
     * 获取系统登录IP
     * @param request
     * @return
     */
    public String getIpAddr(HttpServletRequest request){    
        String ipAddress = request.getHeader("x-forwarded-for");    
            if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {    
                ipAddress = request.getHeader("Proxy-Client-IP");    
            }    
            if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {    
                ipAddress = request.getHeader("WL-Proxy-Client-IP");    
            }    
            if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {    
                ipAddress = request.getRemoteAddr();    
                if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){    
                    //根据网卡取本机配置的IP    
                    InetAddress inet=null;    
                    try {    
                        inet = InetAddress.getLocalHost();    
                    } catch (UnknownHostException e) {    
                        e.printStackTrace();    
                    }    
                    ipAddress= inet.getHostAddress();    
                }    
            }    
            //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割    
            if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15    
                if(ipAddress.indexOf(",")>0){    
                    ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));    
                }    
            }    
            return ipAddress;     
    }  
}
4.记录日志
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;

/**
 * 
 * 记录日志处理
 * 
 * @author xzb
 * 
 */
public class SystemLogUtil {

    private static final Logger logger = LoggerFactory.getLogger(SystemLogUtil.class);

    private static String[] types = { "java.lang.Integer", "java.lang.Double",  
                "java.lang.Float", "java.lang.Long", "java.lang.Short",  
                "java.lang.Byte", "java.lang.Boolean", "java.lang.Char",  
                "java.lang.String", "int", "double", "long", "short", "byte",  
                "boolean", "char", "float" }; 
    // 定义异常
    //private static final String EXCEPTION_START = "@AfterThrowing:抛出异常";
    //private static final String EXCEPTION_DATA = "@AfterThrowing:异常发生时间";
    private static final String EXCEPTION_NAME = "@AfterThrowing:异常名称";
    private static final String EXCEPTION_METHOD = "@AfterThrowing:异常方法";
    //private static final String EXCEPTION_DISCRIPTION = "@AfterThrowing:方法描述";
    //private static final String EXCEPTION_USER = "@AfterThrowing:请求人";
    //private static final String EXCEPTION_IP = "@AfterThrowing:请求IP";
    private static final String EXCEPTION_PARAMS = "@AfterThrowing:请求参数";
    private static final String EXCEPTION_INFO = "@AfterThrowing:抛出异常信息";

    // 执行方法之前
    //private static final String BEFORE_START = "@Before:模拟权限检查";
    private static final String BEFORE_METHOD = "@Before:目标方法为";
    private static final String BEFORE_PARAMS = "@Before:参数为(初始参数)";
    //private static final String BEFORE_DISCRIPTION = "@Before:方法描述";
    private static final String BEFORE_USER = "@Before:请求人";
    private static final String BEFORE_IP = "@Before:请求IP";

    // 执行方法之后
    //private static final String AFTER_START = "@After:模拟释放资源";
    //private static final String AFTER_METHOD = "@After:目标方法为";
    private static final String AFTER_PARAMS = "@After:参数为(或者参数改变之后的参数)";
    //private static final String AFTER_DISCRIPTION = "@After:方法描述";

    // 执行结果
    //private static final String RETURN_START = "@AfterReturning:执行结果";
    //private static final String RETURN_METHOD = "@AfterReturning:目标方法为";
    private static final String RETURN_RESULT = "@AfterReturning:返回值";

    /**
     * 异常处理
     * @return 
     */
    public static Map<String, String> exceptionInfoCollect(JoinPoint joinPoint, Throwable e, MongoLogWriter logWriter,
            Map<String, String> loggerMap) throws Exception {
        if (MatchUtil.isEmpty(loggerMap)) {
            loggerMap = new LinkedHashMap<String,String>();
        }
        loggerMap.put(EXCEPTION_NAME, e.getClass().getName());
        loggerMap.put(EXCEPTION_METHOD, (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
        loggerMap.put(EXCEPTION_PARAMS, getParameterNames(joinPoint));
        loggerMap.put(EXCEPTION_INFO, e.getMessage());
        // 记录本地日志
        logger.error(loggerMap.toString()+"\r\n");
        // 记录MongoDB
        logWriter.insert(loggerMap);
        return loggerMap;
    }

    /**
     * 收集方法执行之前的参数信息
     * @param point
     * @return 
     * @throws Exception 
     */
    public static Map<String, String> permissionCheckInfo(JoinPoint joinPoint,TbCivilUser user,String ip,Map<String,String> loggerMap) throws Exception {
        if (MatchUtil.isEmpty(loggerMap)) {
            loggerMap = new LinkedHashMap<String,String>();
        }
        loggerMap.put(BEFORE_METHOD, (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
        loggerMap.put(BEFORE_PARAMS, getParameterNames(joinPoint));
        loggerMap.put(BEFORE_USER, user.getUserName());
        loggerMap.put(BEFORE_IP, ip);
        return loggerMap;
    }

    /**
     * 收集执行方法的结果
     * @param logWriter 
     * @return 
     */
    public static Map<String, String> afterReturnInfo(JoinPoint point, TbCivilUser user, Object returnValue,MongoLogWriter logWriter, Map<String,String> loggerMap) throws Exception {
        if (MatchUtil.isEmpty(loggerMap)) {
            loggerMap = new LinkedHashMap<String,String>();
        }
        if (returnValue == null) {
            returnValue = "结果为null";
        }
        loggerMap.put(RETURN_RESULT, returnValue.toString());
        // 记录本地日志
        logger.error(loggerMap.toString()+"\r\n");
        // 记录MongoDB
        logWriter.insert(loggerMap);
        return loggerMap;
    }

    /**
     * 收集所有参数信息
     * @param point
     * @param exceptionFlag 
     * @return 
     * @throws Exception 
     */
    public static Map<String, String> releaseResourceInfo(JoinPoint point,Map<String,String> loggerMap) throws Exception {
        if (MatchUtil.isEmpty(loggerMap)) {
            loggerMap = new LinkedHashMap<String,String>();
        }
        loggerMap.put(AFTER_PARAMS, getParameterNames(point));
        return loggerMap;
    }

    /** 
     * 获取注解中对方法的描述信息
     * 
     * @param joinPoint 切点 
     * @return 方法描述 
     * @throws Exception 
     */  
    @SuppressWarnings("rawtypes")
    public static String getMethodDescription(JoinPoint joinPoint) throws Exception {  
        String targetName = joinPoint.getTarget().getClass().getName();  
        String methodName = joinPoint.getSignature().getName();  
        Object[] arguments = joinPoint.getArgs();  
        Class targetClass = Class.forName(targetName);  
        Method[] methods = targetClass.getMethods();  
        String description = "";  
        for (Method method : methods) {  
            if (method.getName().equals(methodName)) {  
                Class[] clazzs = method.getParameterTypes();  
                if (clazzs.length == arguments.length) {  
                    description = method.getAnnotation(SystemMethodLog.class).description();  
                    break;  
                }  
            }  
        }  
        return description;  
    } 

    /**
     * 参数名称
     * @param paramNames
     * @param joinPoint
     * @return
     */
    private static String writeLogInfo(String[] paramNames, JoinPoint joinPoint){  
        Object[] args = joinPoint.getArgs();  
        StringBuilder sb = new StringBuilder();  
        boolean clazzFlag = true;  
        for(int k=0; k<args.length; k++){  
            Object arg = args[k];  
            sb.append(paramNames[k]+" ");  
            // 获取对象类型  
            String typeName = arg.getClass().getTypeName();  
            for (String t : types) {  
                if (t.equals(typeName)) {  
                    sb.append("=" + arg+"; ");  
                }  
            }  
            if (clazzFlag) {  
                sb.append(getFieldsValue(arg));  
            }  
        }  
        return sb.toString();  
    }  
    /** 
     * 得到方法参数的名称 
     * @param cls 
     * @param clazzName 
     * @param methodName 
     * @return 
     * @throws NotFoundException 
     */  
    @SuppressWarnings("rawtypes")
    private static String[] getFieldsName(Class cls, String clazzName, String methodName) throws NotFoundException{  
        ClassPool pool = ClassPool.getDefault();  
        //ClassClassPath classPath = new ClassClassPath(this.getClass());  
        ClassClassPath classPath = new ClassClassPath(cls);  
        pool.insertClassPath(classPath);  
        CtClass cc = pool.get(clazzName);  
        CtMethod cm = cc.getDeclaredMethod(methodName);  
        MethodInfo methodInfo = cm.getMethodInfo();  
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();  
        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);  
        if (attr == null) {  
            // exception  
        }  
        String[] paramNames = new String[cm.getParameterTypes().length];  
        int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;  
        for (int i = 0; i < paramNames.length; i++){  
            paramNames[i] = attr.variableName(i + pos); //paramNames即参数名  
        }  
        return paramNames;  
    }  
    /** 
     * 得到参数的值 
     * @param obj 
     */  
    public static String getFieldsValue(Object obj) {  
        Field[] fields = obj.getClass().getDeclaredFields();  
        String typeName = obj.getClass().getTypeName();  
        for (String t : types) {  
            if(t.equals(typeName))  
                return "";  
        }  
        StringBuilder sb = new StringBuilder();  
        sb.append("【");  
        for (Field f : fields) {  
            f.setAccessible(true);  
            try {  
                for (String str : types) {  
                    if (f.getType().getName().equals(str)){  
                        sb.append(f.getName() + " = " + f.get(obj)+"; ");  
                    }  
                }  
            } catch (IllegalArgumentException e) {  
                e.printStackTrace();  
            } catch (IllegalAccessException e) {  
                e.printStackTrace();  
            }  
        }  
        sb.append("】");  
        return sb.toString();  
    }  

    /**
     * 获取参数的名称
     * @param point
     * @return
     * @throws Exception
     */
    public static String getParameterNames(JoinPoint point) throws Exception {
        String classType = point.getTarget().getClass().getName();  
        Class<?> clazz = Class.forName(classType);  
        String clazzName = clazz.getName();  
       // String clazzSimpleName = clazz.getSimpleName();  
        String methodName = point.getSignature().getName();  
        String[] paramNames = getFieldsName(SystemLogAspect.class, clazzName, methodName);  
        String logContent = writeLogInfo(paramNames, point);
        return logContent;
    }

}
5.在使用的方法上加入注解
@SystemMethodLog(description = "庭审问题")
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值