关于SpringMVC AOP 使用@Aspect方式记录日志

hersing 2015-12-16 10:53:48
加精
项目描述:项目采用SpringMVC搭建,采用注解方式
事物管理使用全注解方式,如下:
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

现在想通过AOP自定义注解来记录系统日志,使用了@Before前置通知 和@AfterThrowing异常通知,现在前置通知能进,而且能记录日志入库,但是异常通知遇到的情况是能进入,但是不能进行数据库操作,事物回滚了, 这样我就没法记录错误异常日志,那么具体应该怎么配置才能实现抛出异常后记录异常日志数据库操作后再回滚事物呢?
下面是AOP日志记录Spring当中配置:
    <aop:aspectj-autoproxy proxy-target-class="true">
<aop:include name="logAspect" />
</aop:aspectj-autoproxy>

<bean id="logAspect" class="com.chip.annotation.SystemLogAspect" />

希望有了解AOP方面的高手来回答下
...全文
5588 点赞 收藏 18
写回复
18 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
daker_129 2016-01-22
Uh oh , It's very amazing !
回复
hersing 2015-12-21
[quote=引用 14 楼 my_God_sky 的回复:] 一个是拦截controller一个是service?springmvc里面controller和service的DI就是两个地方配置,所以要两个地方。好像是因为拦截controller注解里面拦截了service的注解的话controller注解就不起作用了。 那这样逻辑就应该能说通了,applicationContext.xml中是exclude-filter Controller层了,只会DI除开Controller层外的包,暂时就这样了,特别感谢@scmod,以及各位的回答,结贴了,谢谢!
回复
hersing 2015-12-18
这个问题给我的感觉是这样的: 要想@Aspectj到Controller层,必须配置到spring-mvc.xml中(这个貌似好像是公认的了),但是如果想要切到service层,应该是要component-scan service层后才能切到,而我在spring-mvc.xml中只是扫描了Contrller层,context.xml中只是扫描了service,dao,aop的包,但是这样又有逻辑问题了,昨天还查了下配置文件的加载顺序,应该是web.xml-->applicationContext.xml-->spring-mvc.xml,这样的话springmvc主配置文件是最后加载的,这样的话应该不会存在scan两遍的问题,还一种说法是说service层无需扫描,直接交给aop代理,迷糊了。。。。我也说不清楚了,再琢磨看看。
回复
scmod 2015-12-17
引用 13 楼 hersing 的回复:
@scmod 谢了,现在能在抛出异常后记录错误日志信息并且回滚service层中数据库的操作了,但我现在遇到一个情况,因为记录日志是在controller层和service层记录,一个是操作日志,一个是异常日志。 我的applicationContext.xml中配置了一段这样的代码:
<aop:aspectj-autoproxy/>
代表启用@Aspectj 注解, 而且在spring-mvc.xml中也配置有一段启用@Aspectj注解的代码:

<aop:aspectj-autoproxy proxy-target-class="true">
        <aop:include name="logAspect" />
</aop:aspectj-autoproxy>
<bean id="logAspect" class="com.chip.annotation.SystemLogAspect" />    //切面
applicationContext.xml中启用@Aspectj 注解的代码不能删除,删除后,就会拦截不到service层中的@AfterThrowing方法,但是@Before方法能进,现在功能是没问题了,担心项目中存在两个启用@Aspectj注解的代码会不会有问题。 查了下网上资料,如果AOP要拦截Controller层操作,必须把启用@Aspectj这段代码放到spring-mvc.xml中,这样才能拦截到Controller层。 考虑是不是配置文件加载顺序的问题,贴下我的配置文件, applicationContext.xml:

    <context:annotation-config/>
    <aop:aspectj-autoproxy/>
    <import resource="spring/db.xml"/>               //数据库信息及全注解事物配置
    <import resource="spring/cache.xml"/>
    <import resource="spring/content.xml" />     //扫描service,dao及aop切面包并且过滤掉controller层
spring-mvc.xml:

 <!-- 启动对@Aspectj注解支持,使用CGLIB生成代理方法,以便AOP拦截到Controller-->
    <aop:aspectj-autoproxy proxy-target-class="true">
        <aop:include name="logAspect" />
    </aop:aspectj-autoproxy>
    <bean id="logAspect" class="com.chip.annotation.SystemLogAspect" />
   //以及其他配置文件,如只扫描controller层等等一些信息
现在这点有点迷糊,为何要配置两个同样的代码才会拦截到@AfterThrowing操作
额..这个就不大清楚了,但是两个@Aspectj如果切得不是同一个类的话应该没关系,切同一个的话按理也只是代理两边,感觉应该也没关系... 然后两个xml的问题我也一直觉得比较奇怪,我以前遇到是ac.xml里面写了component-scan全部扫进去了,但是如果在mvc.xml里面要启用mvc:annnotion那个的话必需还要再component-scan一遍,也就是会生成同个类的两个实例(或者说就是会再重新new个单例出来,然后之前ac.xml里面生成的那个具体就不知道是被清掉还是说放那里只是我们取不到了),按理说mvc的是能看到父配置xml也就是ac.xml里面扫过的类的,但是不行.....所以我觉得可能是不是你的mvc里面有mvc:annotation这类注解所以把之前那个ac里面生成过要代理的service的信息给重新生成了一遍,但是@Before又能进,这是为啥!!!感觉好像我说的不是很清楚..我自己都看不大懂......我也搞不懂了...这个得等大神出现或者自己钻研下源码什么的...或者你可以找个大神微博或者blog直接问问看看....
回复
_南天北落 2015-12-17
一个是拦截controller一个是service?springmvc里面controller和service的DI就是两个地方配置,所以要两个地方。好像是因为拦截controller注解里面拦截了service的注解的话controller注解就不起作用了。
引用 13 楼 hersing 的回复:
@scmod 谢了,现在能在抛出异常后记录错误日志信息并且回滚service层中数据库的操作了,但我现在遇到一个情况,因为记录日志是在controller层和service层记录,一个是操作日志,一个是异常日志。 我的applicationContext.xml中配置了一段这样的代码:
<aop:aspectj-autoproxy/>
代表启用@Aspectj 注解, 而且在spring-mvc.xml中也配置有一段启用@Aspectj注解的代码:

<aop:aspectj-autoproxy proxy-target-class="true">
        <aop:include name="logAspect" />
</aop:aspectj-autoproxy>
<bean id="logAspect" class="com.chip.annotation.SystemLogAspect" />    //切面
applicationContext.xml中启用@Aspectj 注解的代码不能删除,删除后,就会拦截不到service层中的@AfterThrowing方法,但是@Before方法能进,现在功能是没问题了,担心项目中存在两个启用@Aspectj注解的代码会不会有问题。 查了下网上资料,如果AOP要拦截Controller层操作,必须把启用@Aspectj这段代码放到spring-mvc.xml中,这样才能拦截到Controller层。 考虑是不是配置文件加载顺序的问题,贴下我的配置文件, applicationContext.xml:

    <context:annotation-config/>
    <aop:aspectj-autoproxy/>
    <import resource="spring/db.xml"/>               //数据库信息及全注解事物配置
    <import resource="spring/cache.xml"/>
    <import resource="spring/content.xml" />     //扫描service,dao及aop切面包并且过滤掉controller层
spring-mvc.xml:

 <!-- 启动对@Aspectj注解支持,使用CGLIB生成代理方法,以便AOP拦截到Controller-->
    <aop:aspectj-autoproxy proxy-target-class="true">
        <aop:include name="logAspect" />
    </aop:aspectj-autoproxy>
    <bean id="logAspect" class="com.chip.annotation.SystemLogAspect" />
   //以及其他配置文件,如只扫描controller层等等一些信息
现在这点有点迷糊,为何要配置两个同样的代码才会拦截到@AfterThrowing操作
回复
scmod 2015-12-16
能开个新事务么...没试过这样记录,好像一般都log4j记录到文件里面去了....
回复
hersing 2015-12-16
@深蓝忧郁 @霜之哀伤 求大神解答
回复
ceshizhanghao3 2015-12-16
帮顶,求大神


可不可以在异常通知里用sql插入呢
回复
hersing 2015-12-16
引用 1 楼 ceshizhanghao3 的回复:
[quote=引用 楼主 hersing 的回复:] 项目描述:项目采用SpringMVC搭建,采用注解方式 事物管理使用全注解方式,如下:
<bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>
现在想通过AOP自定义注解来记录系统日志,使用了@Before前置通知 和@AfterThrowing异常通知,现在前置通知能进,而且能记录日志入库,但是异常通知遇到的情况是能进入,但是不能进行数据库操作,事物回滚了, 这样我就没法记录错误异常日志,那么具体应该怎么配置才能实现抛出异常后记录异常日志数据库操作后再回滚事物呢? 下面是AOP日志记录Spring当中配置:
    <aop:aspectj-autoproxy proxy-target-class="true">
        <aop:include name="logAspect" />
    </aop:aspectj-autoproxy>

    <bean id="logAspect" class="com.chip.annotation.SystemLogAspect" />
希望有了解AOP方面的高手来回答下
母鸡[/quote]
回复
hersing 2015-12-16
@scmod 谢了,现在能在抛出异常后记录错误日志信息并且回滚service层中数据库的操作了,但我现在遇到一个情况,因为记录日志是在controller层和service层记录,一个是操作日志,一个是异常日志。 我的applicationContext.xml中配置了一段这样的代码:
<aop:aspectj-autoproxy/>
代表启用@Aspectj 注解, 而且在spring-mvc.xml中也配置有一段启用@Aspectj注解的代码:

<aop:aspectj-autoproxy proxy-target-class="true">
        <aop:include name="logAspect" />
</aop:aspectj-autoproxy>
<bean id="logAspect" class="com.chip.annotation.SystemLogAspect" />    //切面
applicationContext.xml中启用@Aspectj 注解的代码不能删除,删除后,就会拦截不到service层中的@AfterThrowing方法,但是@Before方法能进,现在功能是没问题了,担心项目中存在两个启用@Aspectj注解的代码会不会有问题。 查了下网上资料,如果AOP要拦截Controller层操作,必须把启用@Aspectj这段代码放到spring-mvc.xml中,这样才能拦截到Controller层。 考虑是不是配置文件加载顺序的问题,贴下我的配置文件, applicationContext.xml:

    <context:annotation-config/>
    <aop:aspectj-autoproxy/>
    <import resource="spring/db.xml"/>               //数据库信息及全注解事物配置
    <import resource="spring/cache.xml"/>
    <import resource="spring/content.xml" />     //扫描service,dao及aop切面包并且过滤掉controller层
spring-mvc.xml:

 <!-- 启动对@Aspectj注解支持,使用CGLIB生成代理方法,以便AOP拦截到Controller-->
    <aop:aspectj-autoproxy proxy-target-class="true">
        <aop:include name="logAspect" />
    </aop:aspectj-autoproxy>
    <bean id="logAspect" class="com.chip.annotation.SystemLogAspect" />
   //以及其他配置文件,如只扫描controller层等等一些信息
现在这点有点迷糊,为何要配置两个同样的代码才会拦截到@AfterThrowing操作
回复
scmod 2015-12-16
catch了在外层捕捉的话感觉好像就要改所有原来代码了... aop貌似没想到,不过log4j他自己有jdbc的appender可以让他自己写入数据库的 我说的新事务意思是那个@Transactional不是有个propagation=Propagation.REQUIRES_NEW这样可以开个独立于原本那个事务的事务出来吗...然后不知道@AfterThrowing这样的切面能不能支持propagation=Propagation.REQUIRES_NEW这样类似的东西 找到这么俩 http://stackoverflow.com/questions/16603061/spring-aop-afterthrowing-execution-pointcut-never-matches http://stackoverflow.com/questions/5022235/spring-aop-ordering-transactions-before-advise 这俩是说好像切面执行跟事务处理异常有个顺序可以用order改下试试看 http://stackoverflow.com/questions/5588313/transactional-on-aspect-advice-possible 这个好像不知道里面 private TransactionService transactionService = new TransactionServiceNull(); 这俩类哪里来的....
回复
scmod 2015-12-16
catch了在外层捕捉的话感觉好像就要改所有原来代码了... aop貌似没想到,不过log4j他自己有jdbc的appender可以让他自己写入数据库的 我说的新事务意思是那个@Transactional不是有个propagation=Propagation.REQUIRES_NEW这样可以开个独立于原本那个事务的事务出来吗...然后不知道@AfterThrowing这样的切面能不能支持propagation=Propagation.REQUIRES_NEW这样类似的东西
回复
hersing 2015-12-16
引用 9 楼 shijing266 的回复:
[quote=引用 8 楼 hersing 的回复:] [quote=引用 7 楼 shijing266 的回复:] 参考配置 只是异常存库,没必要这么复杂吧,异常了catch,然后在catch里面保存异常信息即可
首先,service中会加上@Transactional(rollbackFor = Exception.class)注解,来支持事物回滚嘛,如果在异常中catch,catch中的数据库操作也不会执行啊,一样会回滚,现在就是不明白如何配置才会使事务回滚之前把异常信息记录下来[/quote] 你写在同一个service方法里面肯定会被回滚,我的意思是调用service的时候,catch他,catch了去做保存异常信息操作[/quote] 嗯,你这是说的另外一种方式了,是还有别的方式可以捕获异常信息并入库,但是既然已经使用自定义注解来记录日志信息了,就不想再把异常日志单独拿出来去做了,难道说这两者是没法共存的吗,不应该吧
回复
引用 8 楼 hersing 的回复:
[quote=引用 7 楼 shijing266 的回复:] 参考配置 只是异常存库,没必要这么复杂吧,异常了catch,然后在catch里面保存异常信息即可
首先,service中会加上@Transactional(rollbackFor = Exception.class)注解,来支持事物回滚嘛,如果在异常中catch,catch中的数据库操作也不会执行啊,一样会回滚,现在就是不明白如何配置才会使事务回滚之前把异常信息记录下来[/quote] 你写在同一个service方法里面肯定会被回滚,我的意思是调用service的时候,catch他,catch了去做保存异常信息操作
回复
hersing 2015-12-16
引用 7 楼 shijing266 的回复:
参考配置 只是异常存库,没必要这么复杂吧,异常了catch,然后在catch里面保存异常信息即可
首先,service中会加上@Transactional(rollbackFor = Exception.class)注解,来支持事物回滚嘛,如果在异常中catch,catch中的数据库操作也不会执行啊,一样会回滚,现在就是不明白如何配置才会使事务回滚之前把异常信息记录下来
回复
参考配置

只是异常存库,没必要这么复杂吧,异常了catch,然后在catch里面保存异常信息即可
回复
hersing 2015-12-16
引用 5 楼 scmod 的回复:
能开个新事务么...没试过这样记录,好像一般都log4j记录到文件里面去了....
嗯log4j里面会有记录,但是想把异常信息入库,能快速的通过日志定位异常,我有点不太明白你说的开个新事务,能解释下吗
回复
相关推荐
发帖
Web 开发
创建于2007-09-28

8.0w+

社区成员

Java Web 开发
申请成为版主
帖子事件
创建了帖子
2015-12-16 10:53
社区公告
暂无公告