`

Spring AOP对日志记录、Exception日志记录

 
阅读更多
Spring AOP对日志记录、Exception日志记录

利用spring aop对日志进行管理,还是采用对比的方式进行,
修改前:

偶们的做法是在action里记录日志,注意这个日志是面向用户的日志,姑且称它为业务日志,至于后台日志,则在此文章中暂不考虑,基本是通过log4j打印到后台日志文件中。看下面一段代码:

try {   
  employeInfoManageService.saveEmploye(vo, authForm.getLoginName());   
    
        LogVO logVO = new LogVO(Constants.LOG_LEVEL_INFO,   
                    Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()   
                                + "增加员工成功!");   
        logService.saveLog(logVO);   
    } catch (Exception e) {   
        log.error(e);   
       LogVO logVO = new LogVO(Constants.LOG_LEVEL_ERROR,   
              Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()   
                               + "增加员工失败!");   
       try {   
           logService.saveLog(logVO);   
       } catch (Exception e1) {   
          log.error(e1);     
       return messageForward("error", "alert.db.exception",      
                       new Object[] {});   }   
   }  


这段代码实际上已经将写日志的过程封装起来,开发者只需要传入3个参数:操作者、是前台系统还是后台系统、以及日志的错误等级,其它的如操作者机器IP, 日志时间等信息由系统统一设定,即使是这样,如果一个action里面有多个操作,代码看起来也非常臃肿,而且给开发者增加了工作量,既然有了aop,为 什么不利用一下?看下面改造的代码:

 LogVO logVO = new LogVO(Constants.LOG_LEVEL_INFO,   
                    Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()   
                                + "增加员工");   
    try {   
        employeInfoManageService.saveEmploye(vo, authForm.getLoginName(), logVO);   
    } catch (Exception e) {   
        log.error(e);   
        return messageForward("error", "alert.db.exception",   
                        new Object[] {});   
   }  

既然是应用到aop,当然少不了aop的配置了,看下面的配置代码:


1.  <aop:config> 
   2.     <aop:advisor pointcut="execution(* *..*Service.*(..))" advice-ref="txAdvice"/> 
     3.     <aop:advisor pointcut="execution(* *..*Service.save*(..)) || execution(* *..*Service.update*(..)) || execution(* *..*Service.delete*(..))" advice-ref="logAfterAdvice"/> 
   4. </aop:config> 
   5.  
   6. <bean id="logAfterAdvice" class="com.fudannet.framework.aop.LogAfterAdvice"/> 


噢,aop:config的第一行是不是很熟悉啊,对,就是我们前面所配置的事务管理,这里,应该很清楚采用统一的aop配置的好处了吧。下面贴出logAfterAdvice的代码:

 public void afterReturning(Object returnObj, Method method, Object[] args,   
                Object targetObj) throws Throwable {   
        if(method.getName().equals("saveLog")) return;   
        for(int i = 0; i < args.length; i++){   
            if(args[i] instanceof LogVO){   
                log.info("开始写入日志......");   
                writeLog((LogVO)args[i]);   
            }   
        }   
   }   
     
   private void writeLog(LogVO vo){   
       try {   
           vo.setDescription(vo.getDescription() + "成功!");   
           logService.saveLog(vo);   
       } catch (RuntimeException e) {   
           log.error(e);   
   }   
     
   public void setLogService(LogService logService) {   
       this.logService = logService;   
   }  


这段代码应该很清楚了,将logService注入到拦截log的advice里,进行正确操作的日志记录,而afterReturning方法里 的第一行判断是由于logService里的写日志的方法是以save开始的。所以,如果拦截器拦截到此方法,不需要记录日志。

正确的日志记录完,当然如果发生异常,我们需要记录操作的失败日志,当然了,我们也是通过aop来做,但是这次是通过实现exception advice来实现,代码如下:

public void afterThrowing(Method method,Object[] args,Object target,Exception e) throws Throwable {   
        if(method.getName().equals("saveLog")) return;   
        for(int i = 0; i < args.length; i++){   
            if(args[i] instanceof LogVO){   
                log.info开始写入日志......");  
                writeLog((LogVO)args[i]);  
            }  
        }  
    }  
    
   private void writeLog(LogVO vo){  
       try {  
           vo.setDescription(vo.getDescription() + "失败!");   
           logThrowService.saveLog(vo);   
       } catch (RuntimeException e) {   
           log.error(e);   
       }   
   }   
     
   public void setLogThrowService(LogService logThrowService) {   
       this.logThrowService = logThrowService;   
   }  


上面代码已经很好的说明了,如果发生exception的话,日志是怎么记录的,这里要提到的一点的是,异常的处理稍微有一些复杂,就拿本例的代码能看出 来,只要在service层有异常的时候,都会记录失败日志,实际上,很多时候,未必是这样,在某个模块,可能需要定义一种特殊的异常,而一旦这种异常发 生,则需要进入另外一个流程或者做一些特殊的处理,这个时候需要根据具体情况做一些变更,比如在上面代码我们加上:

public void afterThrowing(Method method,Object[] args,Object target,OrderException e) throws Throwable {   
        log.info("......");   
        //do something   
    }  


则如果OrderException被抛出,就会到此方法中执行,而不会去写日志。
--------------------------------------------------------------------------------
其中的封装方式虽然一般,但是还是比较好的解决了问题!对于LogVO类我们可以把他继续扩展下去,比如设定访问用户,IP,seq文等.

reference:http://www.360doc.com/editart2.aspx?articleid=271503637

**************
spring AOP 是基于面向切面的编程,它能够使得我们专注于我们的业务处理,将一些其他的东西由它来统一完成,程序的侵入性很小,所以被广泛应用,至于实现原理我就不多说了,两个字:"代理"!

下面说说标题所示的应用,记录日志,什么时候记录日志,都记录什么?想想,可不 就是在调用方法的时候写日志嘛,之前如果使用logger的话,都会在方法的开始写一个logger.info("xxxxxxxxxxxx");结束的 时候再写一个,这不是很麻烦吗,每次都要写。实际上这个时候我们就可以用aop来做,当方法进入的时候写一条日志,结束的时候再写一条,分别对应“前置通 知”和”后置通知“,如果我们都日志有新的写法,值需要修改控制日志的这个类,对程序没有丝毫影响,也就谈不上改动大量的代码了。下面开始:

1.引入aop的命名空间(其中有AOP的那部分):
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">


2.书写记录日志的类:
package com.yjck.fm.util;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
public class LogUtil {
Logger logger = Logger.getLogger(LogUtil.class);
public void logAll(JoinPoint jp){
String methodName = jp.getSignature().getName();
logger.info(jp.getTarget().getClass().getName()+"---"+methodName);
Object[] args = jp.getArgs();
for(int i=0;i<args.length;i++){
logger.info("params["+i+"]:"+ args[i].toString());
}
}
}


上面这段代码实现了输出要调用的类名,方法已经参数。

3.配置xml文件:
<!-- 日志管理aop -->
<!-- 强制使用cglib代理,如果不设置,将默认使用jdk的代理,但是jdk的代理是基于接口的 -->
<aop:config proxy-target-class="true" />  
<aop:config>
 <aop:aspect id="myAspect" ref="logUtil">
  <aop:pointcut expression="execution(* com.yjck.fm.*.action.*.*(..))" id="logPointCut"/>
  <aop:before method="logAll" pointcut-ref="logPointCut"/>
 </aop:aspect>
</aop:config>
<!-- 日志记录类 -->        
 <bean id="logUtil" class="com.yjck.fm.util.LogUtil"></bean>


注意:我这里配置的是拦截所有action的所有方法,可以根据自己的情况配置,同时也只配了一个”前置通知“before,如果要需要还可以配置其他的。

实现已经完毕了!

*****************

首先,需要将log4j先配置好在web.xml中加入解析器servlet的配置
<context-param>     
 <param-name>log4jConfigLocation</param-name>     
 <param-value>/WEB-INF/classes/log4j.properties</param-value>  
</context-param>  
  
<servlet>     
 <servlet-name>log4j</servlet-name>  
 <servlet-class>  
  org.springframework.web.util.Log4jConfigServlet  
 </servlet-class>  
 <load-on-startup>2</load-on-startup>  
</servlet>  
  
<listener>     
  <listener-class>  
   org.springframework.web.util.Log4jConfigListener  
  </listener-class>  
 </listener> 


之后,由于我项目当中配置了大量的service类,类名都以Service结尾,为了方便配置使用spring当中的BeanNameAutoProxyCreator类进行aop配置。
在spring配置文件中配置如下:
<bean class="cn.aresoft.fw.log.LoggerAdvice" id="loggerAdvice"/>  
 <bean class=  
  "org.springframework.aop.framework  
  .autoproxy.BeanNameAutoProxyCreator" >  
<!-- 始终以CGLib技术动态代理-->  
<!-- <property name="optimize"><value>true</value></property>  -->  
<!-- 配置开关  这句不加getBean()方法获得bean是会报类型转换异常-->  
 <property name="proxyTargetClass"><value>true</value></property>  
  
 <property name="interceptorNames">  
   <list>  
   <value>loggerAdvice</value>  
   </list>  
 </property>  
 <property name="beanNames">  
   <list>  
   <value>*Service</value>  
   </list>  
 </property>  
</bean>  


再来就是写Advice类了也就是配置中的LoggerAdvice,代码如下:
public class LoggerAdvice implements MethodBeforeAdvice,   
AfterReturningAdvice,ThrowsAdvice {  
public void before(Method method, Object[] args,  
                Object target)throws Throwable {  
   Logger logger = Logger.getLogger(target.getClass());   
   logger.debug("+Class : "+ target.getClass().getName());   
   logger.debug("+Method : "+ method.getName());   
 }  
  
public void afterReturning(Object retuVal, Method method,  
 Object[] args,Object target) throws Throwable {  
   Log log = LogFactory.getLog(target.getClass());  
   //do log  
 }  
      
public void  afterThrowing(Method method,Object[] args,  
 Object target,Exception ex){  
   Logger logger = Logger.getLogger(target.getClass());   
   logger.error("数据处理时发生异常",ex);   
 }  
}  


http://www.weishuzhai.com/learn-spring-part-three/

*********************************************************************
注解方式---spring的AOP拦截用户操作

配置文件:
<!-- 操作日志切面声明  -->     
   <bean id="logAspect" class="com.tq365.service.sys.log.SystemLogAspect"/>  
   <aop:config>  
       <aop:aspect ref="logAspect">  
       </aop:aspect>  
   </aop:config>  


实现代码:
/** 
 * 系统操作日志切面 
 *  
 * @author archie2010 
 *  since 2011-3-17 下午02:44:03 
 */  
@Aspect  
public class SystemLogAspect {  
  
    // int与long之Class会自动转为其封装类型之Class  
    private static final String integerClazz = "class java.lang.Integer";  
    private static final String longClazz = "class java.lang.Long";  
  
    @Resource  
    private SystemLogService systemLogService;  
  
    private Logger logger = Logger.getLogger(this.getClass().getName());  
  
    @Pointcut("execution(* com.tq365.service..*.*(..))")  
    public void myAspect() {  
    };  
  
    @AfterThrowing(pointcut = "myAspect()", throwing = "e")  
    public void doAfterThrowing(JoinPoint jp, Throwable e) {  
        System.out.println("出现异常:" + e.getMessage());  
        System.out.println(e.getClass().getName());  
        System.out.println("异常所在类:" + jp.getTarget().getClass().getName());  
        System.out.println("" + jp.getSignature().getName()  
                + "方法 throw exception");  
        // logger.error("错误! error级别的!!!"+e.getMessage());  
        logger.error("Oops===" + jp.getTarget().getClass().getName() + "中的"  
                + jp.getSignature().getName() + "方法抛出" + e.getClass().getName()  
                + "异常");  
        System.out.println("参数:");  
        ;  
        if (jp.getArgs() != null && jp.getArgs().length > 0) {  
            for (int i = 0; i < jp.getArgs().length; i++) {  
                System.out.println(jp.getArgs()[i].toString());  
                logger.error("参数:--" + jp.getArgs()[i].toString());  
            }  
        }  
    }  
  
    @SuppressWarnings("unchecked")  
    @After("@annotation(com.tq365.sys.annotation.SystemLogAnnotation)")  
    public void doAfter(JoinPoint jp) {  
        System.out.println("----------后置通知");  
        System.out.println("方法所在类:" + jp.getTarget().getClass().getName());  
        System.out.println("" + jp.getSignature().getName() + "方法");  
  
        String methodName = jp.getSignature().getName();  
  
        // 操作日志对象-----------------  
        SystemLog sysLog = new SystemLog();  
  
        // 操作参数-----------------  
        String descArgs = "参数";  
        if (jp.getArgs() != null && jp.getArgs().length > 0) {  
            for (int i = 0; i < jp.getArgs().length; i++) {  
                if(jp.getArgs()[i]!=null){  
                    //System.out.println(jp.getArgs()[i].toString());  
                    descArgs += jp.getArgs()[i].toString()+",";  
                }else{  
                    descArgs +="null"+",";  
                }  
            }  
            System.out.println("------参数" + descArgs);  
        }  
        sysLog.setOperateArgs(descArgs);  
  
        String des = null;//方法描述  
        if (!(methodName.startsWith("set") || methodName.startsWith("get"))) {  
  
            Class targetClass = jp.getTarget().getClass();  
  
            //方法不定向参数Clazz...  
            Class[] claszs = new Class[jp.getArgs().length];  
  
            for (int i = 0; i < jp.getArgs().length; i++) {  
                //System.out.println(jp.getArgs()[i]);  
                if(jp.getArgs()[i]!=null){  
                    System.out.println(jp.getArgs()[i].getClass());  
                    if (jp.getArgs()[i].getClass().toString().equals(integerClazz)) {  
                        claszs[i] = int.class;  
                    } else if (jp.getArgs()[i].getClass().toString().equals(  
                            longClazz)) {  
                        claszs[i] = long.class;  
                    }else{  
                        claszs[i] =jp.getArgs()[i].getClass();  
                    }  
                }else if(jp.getArgs()[i]==null){  
                    claszs[i] = String.class;  
                }  
            }  
            Method method=null;  
            try {  
                method = targetClass.getMethod(methodName, claszs);  
            } catch (SecurityException e) {  
            } catch (NoSuchMethodException e) {  
            }  
            //若方法为空(描述无法获得则des=null)  
            if(method!=null){  
                System.out.println(method.getAnnotation(SystemLogAnnotation.class)  
                        .description());  
                des = method.getAnnotation(SystemLogAnnotation.class).description();  
            }  
  
        }  
        // 获得Session  
        HttpSession session = ServletActionContext.getRequest().getSession();  
        // 取到当前的操作用户  
        User appUser = (User) session.getAttribute("USER");  
  
        if (appUser != null) {  
            System.out.println("用户已经存在Session中");  
            // 操作日志对象  
  
            sysLog.setUid(appUser.getUserId());  
            sysLog.setUsername(appUser.getFullName());  
  
        }  
        HttpServletRequest request = ServletActionContext.getRequest();  
        String ip = request.getRemoteAddr();  
        sysLog.setOperateTime(DateUtil.getCurrentTime());  
        sysLog.setOperateDes(methodName +"->"+ des);  
        sysLog.setIp(ip);  
  
        systemLogService.save(sysLog);  
        System.out.println("----------保存操作日志");  
    }  
  
}  


**************************************************************************
xml方式---spring的AOP拦截用户操作

需要日志记录,将所有的web操作记录到数据库中,使用aop来记录日志,当然是一个好的选择,spring中集成aop记录日志的方式有多种(aop的配置方式有多种,注解、xml配置),这里只说一个xml配置的例子。

   1、编写日志记录类
   2、配置aop

   1、编写日志记录类

@SuppressWarnings("unchecked")    
public class LogService {        
   public void logAll(JoinPoint jp){        
  System.out.println("in LogService, method logAll invoked.");        
 System.out.println("========================");       
     StringBuilder sb = new StringBuilder();        
   sb.append("method:" + jp.getSignature().getName());          
 HttpServletRequest request = ServletActionContext.getRequest();    
        Iterator<Entry<String, Object>> iter = request.getParameterMap().entrySet().iterator();        
    boolean isFirst = true;       
     sb.append(" paras:");      
      while(iter.hasNext()){        
        Entry<String, Object> entry = iter.next();      
          if(isFirst){         
           isFirst = false;         
       }else{             
       sb.append("#");      
          }               
 sb.append(entry.getKey() + "=");      
          Object[] allValue = (Object[]) entry.getValue();          
      for(int i = 0; i < allValue.length; i++){           
         if(i != 0){        
                sb.append(",");        
            }               
     sb.append(allValue[i].toString());          
      }        
    }           
           System.out.println(sb.toString());        
    System.out.println("========================");      
  }  
  }          


2、配置aop
   在applicationContext.xml中配置

</aop:config>          
    <bean id="logService" class="com.cjnetwork.cms.service.LogService"></bean>           
<aop:config>  
<aop:aspect id="myAspect" ref="logService">  
<aop:pointcut expression="execution(* com.cjnetwork.cms.action.*.*(..))" id="logPointCut"/>  
<aop:before method="logAll" pointcut-ref="logPointCut"/>  
</aop:aspect>  
</aop:config>  
<bean id="logService" class="com.cjnetwork.cms.service.LogService"></bean>  
<aop:config proxy-target-class="true" />   


基本配置就是这样的,这里需要配置<aop:config proxy-target-class="true" /> ,表示强制使用cglib代理,而不是java本身的代理,这个很重要,如果使用java自带的代理,则会抛出异常,提示说代理类无法转换为我们自己的类,这是因为默认的该属性为false,这种代理方式,需要实现接口的方式,代理返回的类可以转换为对应的接口类,但无法直接转换为类的实现,这种方式不推荐。

reference:http://blog.csdn.net/johnjobs/article/details/8667646

**********************************************************************************
**********************************************************************************

如果要在方法执行前或后或抛出异常后加上一个自己的拦截器,或者一个环绕拦截器,在拦截器中执行一些操作,比如执行一些数据库操作,记录一些信 息,这些操作通过调用一个服务类的方法来执行,这个方法也在spring事务管理拦截器的管理之下,那么这个记录方法需要在另一个事务中进行,而不是与被 拦截方法在同一个事务中,不然如果被拦截方法抛出异常需要回滚时,所作的记录也会被回滚,当然有时候确实需要同时回滚,那就要放在同一个事务中。

这和自己的拦截器和事务管理的拦截器的执行顺序有一定关系,spring事务管理拦截器是一个环绕通知,在被拦截方法执行前启动事务,执行后完成 事务,如果自己的拦截器被spring事务管理拦截器包围在里面,那么在自己的拦截器运行时,spring已经启动了一个事务,如果你的记录信息方法需要 与被拦截方法同在一个事务中,将你的记录信息方法的事务传播属性设为默认的REQUIRED就可以了;
如果你记录信息的方法需要单独的一个事务环境,那就要把事务传播属性设为REQUIRES_NEW了,这样spring事务管理器会新建一个事 务,并且新建一个session连接,因为一个数据库连接不可能同时有两个事务,记录信息完了提交事务并且把新建的session连接关闭,自己的拦截器 退出后继续执行被拦截的方法或它的事务处理。

相反如果自己的拦截器在spring事务管理拦截器的外面,那么记录信息的方法会在一个单独的事务中执行,并提交,不管它的事务传播属性是 REQUIRES_NEW还是REQUIRED,因为与被拦截方法的事务处理没有交叉,并且可以使用同一个session连接如果是 OpenSessionInViewFilter。

所以如果记录信息和被拦截方法要在不同事务中执行,分别提交,那么最好将自己的拦截器设在spring事务管理器拦截器的外面;如果需要将记录信 息和被拦截方法在同一个事务中处理,必须将自己的拦截器被包围在spring事务管理拦截器中,并且记录信息方法的事务传播属性为默认的 REQUIRED。

设置拦截器的执行顺序可以让拦截器处理类实现org.springframework.core.Ordered接口,在spring配置文件的 AOP设置中设定自己的拦截器和spring事务管理拦截器的执行顺序,将自己的拦截的序号排在spring事务管理的前面,就可以将该拦截器放到事务管 理拦截器的外面执行了,对于before通知方式会先于事务管理拦截器执行,对于after returning和after和after throwing通知方式会后于事务管理拦截器的执行,对于arount通知方式会包围事务管理拦截器执行。

下面是一个异常拦截器的例子。
有位朋友提到在spring异常拦截器中更新数据不能够提交,做了一下测试,测试环境基本是这样:一个用户登录的功能,spring对 service中的每个方法进行事务管理,在用户检测的service方法上同时加上一个异常拦截器,当用户不存在或密码不正确时用户检测方法会抛出异 常,异常拦截器捕获到该异常,同时记录一些日志。
spring配置文件相关:
<!-- 事务管理 -->  
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">   
    <property name="sessionFactory" ref="sessionFactory"></property>  
</bean>  
  
<!-- 事务通知 -->  
<tx:advice id="txAdvice" transaction-manager="transactionManager">  
    <tx:attributes>  
        <tx:method name="get*" read-only="true"/>  
        <tx:method name="*" propagation="REQUIRES_NEW" rollback-for="Exception"/>  
    </tx:attributes>  
</tx:advice>  
  
<!-- aop代理设置 -->  
<aop:config proxy-target-class="true">  
    <aop:pointcut id="txPointcut" expression="execution(* com.hbs..*Service.*(..))"/>  
    <aop:pointcut id="logPointcut" expression="execution(* com.hbs.customer..*Service.*(..))"/>  
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" order="1"/>  
    <aop:aspect id="logAspect" ref="logInterceptor" order="2" >  
        <aop:after-throwing  
            pointcut-ref="logPointcut"   
            method="serviceIntercept" />  
    </aop:aspect>  
</aop:config>  
  
<!-- log拦截器类 -->  
<bean id="logInterceptor" class="com.hbs.eventlog.EventLogInterceptor">  
    <property name="service" ref="logService"></property>  
</bean>     


service方法中的事务传播属性都设为要求新建事务,spring事务管理切面拦截器的order设为1,而log拦截器的order设为2,这意味 着这两个要同时执行时,先执行事务拦截器,后执行log拦截器,由于事务管理是一个环绕通知(around),实际上是log拦截器被包围在事务管理拦截 器中。

从中可以看出,log异常拦截器在用户登录的事务回滚之前截获异常,在记录日志时,日志记录的service方法也在spring的事务管理之 下,用户登录的事务还没有结束,根据REQUIRES_NEW特性,spring会新开一个事务,这时原来的数据库连接已经在一个事务中,一个连接不可能 同时有两个事务,所以同时新创建一个session连接(虽然我使用了OpenSessionInViewFilter,并且session是单例的), 日志记录就在新建的事务和session中进行,完了提交,并且会把新建的session连接关闭。

然后继续进行被中断的用户登录的事务管理操作,由于抛异常spring将用户登录的事务回滚。
这样能够实现预想的功能,但是如果我去掉指定的REQUIRES_NEW,那么log记录的操作会继续在用户登录的事务中进行,最后会被一起回滚。

如果把事务管理的order设为2,log拦截器的order设为1,也就是log拦截器在事务管理拦截器的外面,会在事务管理拦截器前后执行完了再执行log的异常拦截器。

可以看出,用户登录的事务和日志记录的事务是前后两个不相关的事务,并且在日志记录事务中并不需要新建session连接,而是直接用在 OpenSessionInViewFilter中创建的session。实际上这时也并不需要将propagation设为REQUIRES_NEW, 使用默认的REQUIRES也照样能够正常工作。

所以应该将该异常拦截器设在事务管理拦截器的外面,即使用Order接口排在前面。

reference:http://blog.csdn.net/zmhinzaghi/article/details/7091795
分享到:
评论
3 楼 di1984HIT 2014-04-24  
这里面提到了好几种解决办法。
2 楼 迪伦少校 2013-12-27  
能否将你的代码共享一下看看呢?不胜感激!
1 楼 Jekey 2013-07-30  
    

相关推荐

    java 实现AOP

    目前整个开发社区对AOP(Aspect Oriented Programing)推崇备至,也涌现出大量支持AOP的优秀Framework,--Spring, JAC, Jboss AOP 等等。AOP似乎一时之间成了潮流。Java初学者不禁要发出感慨,OOP还没有学通呢,又来AOP...

    spring-boot mybaits spring security redis整合

    aop日志记录。 4、调度 ====== Spring task, 可以查询已经注册的任务。立即执行一次任务。 5、缓存和Session =========== 注解redis缓存数据,Spring-session和redis实现分布式session同步(建议按功能模块...

    spring-boot mybaits shiro redis整合

    aop日志记录。 4、调度 ====== Spring task, 可以查询已经注册的任务。立即执行一次任务。 5、缓存和Session =========== 注解redis缓存数据,Spring-session和redis实现分布式session同步(建议按功能模块...

    Spring面试题

    AOP 的功能完全集成到了 Spring 事务管理、日志和其他各种特性的上下文中。 IOC 容器 Spring 设计的核心是 org.springframework.beans 包,它的设计目标是与 JavaBean 组件一起使用。这个包通常不是由用户直接使用...

    spring-boot-demo:springboot 2.1+整合各种技术

    春天引导演示 springboot 2.0+整合各种技术 ...所有的测试用例均在springboot默认生成的测试文件夹下的测试类里 √:完结“”:正在更×:待更 模块快速预览: ... :利用spring aop自定义注释解记录日志 :整合jwt

    springboot+dubbo分布式架构,提供分布式缓存、分布式锁、分布式Session、读写分离

    日志:Logback打印日志,默认打印Web和Service简要日志。 工具类:字符串处理,类型转换,日期处理,IO和文件,Excel读写,加密解密,HTTP客户端,XML处理,转码,各种Util等等。 代码生成器:根据数据库表结构生成...

    百度地图开发java源码-jbot:代码生成器(swagger+springboot+spring+mybatis)

    aop ── 切面组件 ├── common ── 公共组件 ├── configs ── 配置组件 ├── dao ── DAO ├── exception ── 异常处理组件 ├── model ── Model ├── rest ── Rest ├── security ── ...

    iBase4J分布式系统-其他

    4、调度:Spring+quartz, 可以查询、修改周期、暂停、删除、新增、立即执行,查询执行记录等。5、基于session的国际化提示信息,职责链模式的本地语言拦截器,Shiro登录、URL权限管理。会话管理,强制结束会话。6、...

    Springboot_v2:SpringBoot_v2项目是努力打造springboot框架的极致细腻的脚手架。包括一套漂亮的前台。无其他杂七杂八的功能,原生纯净

    前言 SpringBoot_v2项目是努力打造springboot框架的极致细腻的脚手架。包括一套漂亮的前台。无其他杂七杂八的功能,...│ ├─log 日志记录AOP │ ├─domain 前台返回包 │ ├─quartz Spring定时器 │ └─support

    Sosoo 1.0网络爬虫程序.doc

    通过上述对功能的定制,我们可以看到在应用中我们对sosoo的编程接口并不多,而且目前系统都是基于set的方式注入aop注入对象,这样很容易和spring等基于set方式的依赖注入(IOC)框架集成。 1.Roboter类,spider...

    asp.net知识库

    使用Relations建立表之间的关系并却使用PagedDataSource类对DataList进行分页 通过作业,定时同步两个数据库 SQLSERVER高级注入技巧 利用反射实现ASP.NET控件和数据实体之间的双向绑定,并且在客户端自动验证输入的...

    JAVA核心知识点整理(有效)

    1. 目录 1. 2. 目录 .........................................................................................................................................................1 JVM ........................

Global site tag (gtag.js) - Google Analytics