Aop:面向切面编程,相对于OOP面向对象编程。
Aop存在的目的是为了解耦,Aop可以让一组类共享相同的行为。在OOP中只能通过继承类和实现接口,来使得代码的耦合度增强,且类只能为单继承,阻碍更多行为添加到一个类上,Aop弥补了这个不足。
结合实际例子来了解Aop,给项目添加用户的操作日志。
引入Aop依赖
<!--AOP-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
添加Log对象实体类
package com.springboot.template.entity.entity;
import com.springboot.template.entity.base.BaseEntity;
import java.util.Date;
public class Log extends BaseEntity {
private String username;
private String ip;
private String url;
private String param;
private String operation;
private Date createtime;
public String getUsername() {
return username;
}
public Log setUsername(String username) {
this.username = username;
return this;
}
public String getIp() {
return ip;
}
public Log setIp(String ip) {
this.ip = ip;
return this;
}
public String getUrl() {
return url;
}
public Log setUrl(String url) {
this.url = url;
return this;
}
public String getParam() {
return param;
}
public Log setParam(String param) {
this.param = param;
return this;
}
public String getOperation() {
return operation;
}
public Log setOperation(String operation) {
this.operation = operation;
return this;
}
public Date getCreatetime() {
return createtime;
}
public Log setCreatetime(Date createtime) {
this.createtime = createtime;
return this;
}
}
添加自定义注解类
package com.springboot.template.config;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyLog {
/**
* 操作事件
*/
String operation() default "";
}
@Target注解放置的目标位置METHOD方法上面
@Retention注解在哪个阶段执行
@Documented生成文档
定义切面
package com.springboot.template.config;
import com.alibaba.fastjson.JSONObject;
import com.springboot.template.entity.entity.Log;
import com.springboot.template.mapper.LogMapper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.Date;
import java.util.Map;
@Configuration
@Aspect
public class LogConfig {
@Autowired
private LogMapper logMapper;
private final Logger log = LogManager.getLogger(LogConfig.class);
@Pointcut("@annotation(com.springboot.template.config.MyLog)")
private void logPointCut() {
}
@Before("logPointCut()")
public void saveOperation(JoinPoint joinPoint) throws Exception {
log.info("使用aop记录操作日志");
Log logEntity = new Log();
//获取方法名
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
MyLog myLog = method.getAnnotation(MyLog.class);
if (myLog != null) {
String operation = myLog.operation();
logEntity.setOperation(operation);
}
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String url = request.getRequestURL().toString();
logEntity.setUrl(url);
Map<String, String[]> param = request.getParameterMap();
logEntity.setParam(JSONObject.toJSONString(param));
log.info(request.getLocalAddr());
InetAddress ip4 = Inet4Address.getLocalHost();
System.out.println(ip4.getHostAddress());
logEntity.setIp(ip4.getHostAddress());
logEntity.setUsername("user");
logEntity.setCreatetime(new Date());
logMapper.insertSelective(logEntity);
}
}
@Aspect定义该类是一个切面
@Pointcut("@annotation(com.springboot.template.config.MyLog)")定义切点
@Before("logPointCut()")在方法调用之前执行某些操作
也可以使用@Pointcut("execution(...)")定义切入点