什么是AOP
- Aspect Oriented Programming
面向切面编程 - AOP是一种编程思想,是对OOP的补充
可以进一步提高编程效率
AOP术语
- Target:目标类
- JoinPoint:连接点
织入代码的位置 - Weaving:织入
– 编译时织入:效率高,但程序尚未运行对运行情况了解不详细不充分
– 运行时织入:能够对运行的程序有充分的了解,但效率较低 - Ascept:切面
– pointCut:切点
– Advice:实现具体逻辑的位置
非AOP编程的日志处理
public class AlphaService {
public void doSomething() {
//记录日志...
//处理业务...
}
}
需要在每个类或方法中添加日志记录工具,很麻烦
AOP的实现
- AspectJ
– AspectJ是语言级的实现,它扩展了Java语言,定义了AOP语法。
– AspectJ在编译期织入代码,它有一个专门的编译器,用来生成遵守Java字节码规范的class文件。 - Spring AOP
– Spring AOP使用纯Java实现,它不需要专门的编译过程,也不需要特殊的类装载器。
– Spring AOP在运行时通过代理的方式织入代码,只支持方法类型的连接点。
– Spring支持对AspectJ的集成。
SpringAOP
- JDK动态代理
– Java提供的动态代理技术,可以在运行时创建接口的代理实例。
– Spring AOP默认采用此种方式,在接口的代理实例中织入代码。 - CGLib动态代理
–采用底层的字节码技术,在运行时创建子类代理实例。
– 当目标对象不存在接口时,Spring AOP会采用此种方式,在子类实例中织入代码。
具体实现
//@Component
//@Aspect
public class AlphaAspect {
//声明切点(*[返回类型] com.duan.nowcoder.community.service[包名].*[类].*[方法](..[参数]))
@Pointcut("execution(* com.nowcoder.community.service.*.*(..))")
public void pointcut() {
}
//运行前执行
@Before("pointcut()")
public void before() {
System.out.println("before");
}
//运行后执行
@After("pointcut()")
public void after() {
System.out.println("after");
}
//方法返回后执行
@AfterReturning("pointcut()")
public void afterRetuning() {
System.out.println("afterRetuning");
}
//出现异常后执行
@AfterThrowing("pointcut()")
public void afterThrowing() {
System.out.println("afterThrowing");
}
//兼顾Before和After
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("around before");
Object obj = joinPoint.proceed();
System.out.println("around after");
return obj;
}
}
统一记录日志
@Component
@Aspect
public class ServiceLogAspect {
public static final Logger logger = LoggerFactory.getLogger(ServiceLogAspect.class);
//(*[返回类型] com.duan.nowcoder.community.service[包名].*[类].*[方法](..[参数]))
@Pointcut("execution(* com.duan.nowcoder.community.service.*.*(..))")
public void pointcut() {
}
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
//获得request实例
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//获取ip
String ip = request.getRemoteHost();
//获取当前时间
String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
//获得方法路径及方法名
String target = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
// 用户[ip],在[时间],访问了[com.nowcoder.community.service.xxx()].
logger.info(String.format("用户[%s],在[%s],访问了[%s].", ip, date, target));
}
}