前言
面向切面编程(aspect-oriented programming,AOP),前面的文章里面描述AOP主要的作用是:日志记录,性能统计,安全控制,事务处理,异常处理,权限登录等等。本文中,我们使用切面来配置日志记录,其他的使用方式基本和这个一样。
相关文章
源码下载
该项目持续更新中,会在代码以及该文档里面详细注释和介绍。项目托管在码云
开源平台上,持续更新项目源码链接:
https://gitee.com/nelucifer/ssm-note,点击克隆/下载
获取该项目。
本文内容
一、注解
注解(Annotation):一个注解就是一个类,@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。
- 定义注解格式: public @interface 注解名 {定义体,定义体中的方法名称就是注解参数名称}
- 注解参数的可支持数据类型:
- 所有基本数据类型(int、float、boolean、byte、double、char、long、short);
- String 类型;
- Class 类型;
- enum 枚举类型;
- Annotation类型;
- 以上所有类型的数组
二、面向切面编程
面向切面编程(AOP):利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。可以参考本文内容:Spring系列学习之IoC与AOP;切面就是为了实现各个业务模块通用功能的复用,比如业务操作(Service)中我们需要记录日志,就使用切面来织入各业务模块。5种通知类型:前置通知、后置通知、环绕通知、返回通知、异常通知。
Spring 提供
配置注解驱动的切面
一、添加依赖
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <spring.version>4.2.5.RELEASE</spring.version> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> <type>jar</type> <scope>compile</scope> </dependency>
|
二、配置注解类
这个类是为了打印日志的时候声明该方法作用,也就是方法的注释。
Log.java
1 2 3 4 5 6 7 8 9 10 11
| package com.weyoung.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Log { String value() default ""; }
|
该注解的使用方式,如下:
1 2 3 4 5 6 7
| @Log("登录") @RequestMapping(value = "/login", method = RequestMethod.POST) public String systemLogin(HttpServletRequest request, HttpServletResponse response) throws Exception { String viewName = "/welcome"; return viewName; }
|
三、配置切面
LogAspect.java
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| package com.weyoung.aspect;
@Aspect @Component public class LogAspect {
@Autowired LoggerService loggerService;
private static final Logger logger = LogManager.getLogger(LogAspect.class);
@Pointcut("@annotation(com.weyoung.annotation.Log)") public void logPointCut() { }
@Around("logPointCut()") public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable { logger.info("进入切点..."); StopWatch stopWatch = new StopWatch(); stopWatch.start(); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); Log log = method.getAnnotation(Log.class); String description = ""; if (log != null) { description = log.value(); } String className = joinPoint.getTarget().getClass().getName(); String methodName = signature.getName(); Object[] args = joinPoint.getArgs(); logger.info("进入方法..."); Object returnValue = joinPoint.proceed(args); stopWatch.stop(); logger.info("执行之后..."); stopWatch.getTotalTimeMillis() ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attributes != null) { HttpServletRequest request = attributes.getRequest(); } return returnValue; } }
|
四、Spring装配该日志切面
spring-mvc.xml
1 2 3
| <aop:aspectj-autoproxy /> <bean class="com.weyoung.aspect.LogAspect" />
|
注意: 在spring-mvc中添加如上配置即可,不需要再添加其他扫描。配置的日志执行后如下:
使用AOP方式配置事务
使用xml方式管理AOP事务;
一、添加依赖
pom.xml
1 2 3 4 5 6 7 8
| <spring.version>4.2.5.RELEASE</spring.version> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> <type>jar</type> <scope>compile</scope> </dependency>
|
二、配置AOP事务
spring-config.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="MySQLDataSource"/> </bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="insert*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="edit*" propagation="REQUIRED"/> <tx:method name="save*" propagation="REQUIRED"/> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="new*" propagation="REQUIRED"/> <tx:method name="set*" propagation="REQUIRED"/> <tx:method name="remove*" propagation="REQUIRED"/> <tx:method name="delete*" propagation="REQUIRED"/> <tx:method name="change*" propagation="REQUIRED"/> <tx:method name="get*" propagation="REQUIRED" read-only="true"/> <tx:method name="find*" propagation="REQUIRED" read-only="true"/> <tx:method name="load*" propagation="REQUIRED" read-only="true"/> <tx:method name="*" propagation="REQUIRED" read-only="true"/> </tx:attributes> </tx:advice>
<aop:config> <aop:pointcut id="serviceOperation" expression="execution(* com.weyoung.service.*.*Impl.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation"/> </aop:config>
|
三、测试事务配置
- 代码添加保存方法,确保该保存方法能够正常保存。
- 添加两条参数,确保一条可以成功一条不能成功,在一个符合事务配置格式的service方法中调用该方法;
- 查询数据库:无数据插入,后台报错;
- 添加两条参数,确保一条可以成功一条不能成功,注释掉事务配置切面,再调用方法进行测试;
- 查询数据库:有一条数据插入,后台报错;
- 结论:事务配置成功,可正常回滚。
service中方法示例代码如下,具体内容可在文首查看源码或留言讨论:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public void saveTest() { Map<String, Object> map1 = new HashMap<>(); map1.put("userId", "007"); map1.put("petname", "genius"); map1.put("name", "weyoung"); map1.put("sex", "man"); map1.put("birth", "2019-03-03"); map1.put("icon", "icon"); map1.put("phone", "phone"); map1.put("email", "ne_lucifer@163.com"); map1.put("address", ""); map1.put("level", 0); map1.put("signature", "signature"); map1.put("brief", "brief"); loginDao.saveUserInfo(map1); Map<String, Object> map = new HashMap<>(); map.put("userId", "001"); map.put("petname", "weyoug"); map.put("name", "lixia"); map.put("sex", "man"); map.put("birth", "2019-03-03"); map.put("icon", "icon"); map.put("phone", "phone"); map.put("email", "ne_lucifer@163.com"); map.put("address", ""); map.put("level", 0); map.put("signature", "signature"); map.put("brief", "brief"); loginDao.saveUserInfo(map); }
|
日志切面和事务切面配置成功!
分享
欢迎扫描下方二维码,关注weyoung公众号,一起交流学习~~
更多联系方式