前言
你是不是还在类里面直接拿到日志对象调用方法来输出日志?接下来教你如何简单使用AOP+自定义注解优雅的实现一个日志记录功能
提示:以下是本篇文章正文内容,案例仅供参考
一、技术介绍
1.AOP是什么?
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。 --摘自百度百科
二、开始使用
1.代码目录结构
2.开始编写代码
POM.xml
org.springframework.boot
spring-boot-starter-aop
咱们这里采用SpringBoot 写一个按需注入的方式开启注解,编写一个按需注入的注解
package com.hyh.log.annotation;
import com.hyh.log.config.HyhLogAutoConfiguration;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**
* 开启日志注解
*
* @Author: heyuhua
* @Date: 2021/1/28 15:32
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({HyhLogAutoConfiguration.class})
public @interface EnableHyhLog {
}
自动配置类
package com.hyh.log.config;
import com.hyh.log.aspect.LogAspect;
import com.hyh.log.service.LogService;
import com.hyh.log.service.impl.LogServiceImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Log AutoConfiguration
*
* @Author: heyuhua
* @Date: 2021/1/28 16:02
*/
@ConditionalOnWebApplication
@Configuration(proxyBeanMethods = false)
public class HyhLogAutoConfiguration {
@Bean
public LogAspect logAspect() {
return new LogAspect();
}
@Bean
public LogService logService() {
return new LogServiceImpl();
}
}
自定义日志注解
package com.hyh.log.annotation;
import java.lang.annotation.*;
/**
* 日志注解
*
* @Author: heyuhua
* @Date: 2021/1/28 16:02
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HyhLog {
/**
* 描述
*
* @return
*/
String value() default "";
}
复制代码
日志切面代码编写
package com.hyh.log.aspect;
import com.hyh.log.annotation.HyhLog;
import com.hyh.log.service.LogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import javax.annotation.Resource;
/**
* Log Aspect
*
* @Author: heyuhua
* @Date: 2021/1/28 16:02
*/
@Aspect
public class LogAspect {
/**
* 日志服务
*/
@Resource
private LogService logService;
/**
* 环绕操作
*
* @param point
* @param hyhLog
* @return
* @throws Throwable
*/
@Around("@annotation(hyhLog)")
public Object around(ProceedingJoinPoint point, HyhLog hyhLog) throws Throwable {
String className = point.getTarget().getClass().getName();
String methodName = point.getSignature().getName();
logService.info("【类】:{},【方法】:{}", className, methodName);
Object obj = point.proceed();
// do something
return obj;
}
/**
* 前置操作
*
* @param point
* @param hyhLog
* @return
* @throws Throwable
*/
@Before("@annotation(hyhLog)")
public void before(JoinPoint point, HyhLog hyhLog) throws Throwable {
logService.info("执行前置操作..." + hyhLog.value());
// do something
}
/**
* 后置操作
*
* @param point
* @param hyhLog
* @return
* @throws Throwable
*/
@After("@annotation(hyhLog)")
public void after(JoinPoint point, HyhLog hyhLog) throws Throwable {
logService.info("执行后置操作..." + hyhLog.value());
// do something
}
}
复制代码
日志服务接口
package com.hyh.log.service;
/**
* Log 接口
*
* @Author: heyuhua
* @Date: 2021/1/28 15:37
*/
public interface LogService {
/**
* info
*
* @param msg
*/
void info(String msg);
/**
* info
*
* @param msg
* @param o
*/
void info(String msg, Object o);
/**
* info
*
* @param msg
* @param throwable
*/
void info(String msg, Throwable throwable);
/**
* info
*
* @param msg
* @param o
*/
void info(String msg, Object... o);
/**
* info
*
* @param msg
* @param o
* @param throwable
*/
void info(String msg, Object o, Throwable throwable);
/**
* error
*
* @param msg
*/
void error(String msg);
/**
* error
*
* @param msg
* @param o
*/
void error(String msg, Object o);
/**
* error
*
* @param msg
* @param throwable
*/
void error(String msg, Throwable throwable);
/**
* error
*
* @param msg
* @param o
* @param throwable
*/
void error(String msg, Object o, Throwable throwable);
}
复制代码
日志服务接口实现
package com.hyh.log.service.impl;
import com.hyh.log.service.LogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
/**
* 日志服务接口实现
*
* @Author: heyuhua
* @Date: 2021/1/28 17:04
*/
@Service
public class LogServiceImpl implements LogService {
/**
* 日志
*/
private static final Logger LOGGER = LoggerFactory.getLogger(LogServiceImpl.class);
@Override
public void info(String msg) {
LOGGER.info(msg);
}
@Override
public void info(String msg, Object o) {
LOGGER.info(msg, o);
}
@Override
public void info(String msg, Throwable throwable) {
LOGGER.info(msg, throwable);
}
@Override
public void info(String msg, Object... o) {
LOGGER.info(msg, o);
}
@Override
public void info(String msg, Object o, Throwable throwable) {
LOGGER.info(msg, o, throwable);
}
@Override
public void error(String msg) {
LOGGER.error(msg);
}
@Override
public void error(String msg, Object o) {
LOGGER.error(msg, o);
}
@Override
public void error(String msg, Throwable throwable) {
LOGGER.error(msg, throwable);
}
@Override
public void error(String msg, Object o, Throwable throwable) {
LOGGER.error(msg, o, throwable);
}
}
复制代码
三、单元测试
OK,不废话,直接上单元测试,先在SpringBoot项目中开启使用我们的注解
看红框框选的我们写的一个按需导入的注解,然后Controller层写一个接口,使用HyhLog注解
@HyhLog(value = "hello world test")
@RequestMapping(value = "hello", method = RequestMethod.GET)
public String hello() {
return "hello";
}
访问hello接口来看下执行结果
总结
AOP基于动态代理可以实现很多功能,例如权限控制、日志记录、事务提交与回滚等一系列操作,通过无侵入式的方式实现业务解耦、功能强化,让我们能用最优雅的代码实现最复杂的功能。
来源:https://www.tuicool.com/articles/FFJNNzf