理論是實踐的基礎,實踐是檢驗真理的唯一標準
一、快速入門指引(所見即所得)
-
Spring AOP核心概念
-
在我們開始使用AOP之前,我們先熟悉AOP概念和術語,這些術語并非特定于Spring,而是與AOP相關,理解這些概念和術語非常有助于理解本文,

-
切面在專案中應用場景

二、核心業務場景實戰之 "記錄業務操作行為"
-
快速上手的核心步驟
- SpringBoot啟動類開啟AOP:@EnableAspectJAutoProxy(proxyTargetClass = true)
- 定義切面注解類:ArticleOperational
- 定義切面核心類:ArticleContentAspect
- 在核心業務中使用切面注解:@ArticleOperational(action = "取消置頂")
-
SpringBoot啟動類開啟Aop
package com.demo.content;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* @author youyun.xu
* @ClassName: ContentApplication
* @Description: 內容管理微服務
* @date 2020/7/23 上午09:00
*/
@SpringBootApplication(scanBasePackages = "com.demo")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ContentApplication {
public static void main(String[] args) {
SpringApplication.run(ContentApplication.class, args);
}
}
-
定義切面注解類
package com.demo.annotation;
import java.lang.annotation.*;
/**
* @author youyun.xu
* @ClassName: ArticleOperational
* @Description: 切面管理檔案操作注解
* @date 2020/7/23 上午09:00
*/
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ArticleOperational {
String action() default "";
}
-
定義切面核心類
package com.demo.aop;
import com.alibaba.fastjson.JSON;
import com.demo.annotation.ArticleOperational;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* @author youyun.xu
* @ClassName: ArticleContentAspect
* @Description: 切面監控文章操作狀態
* @date 2020/7/23 上午09:00
*/
@Aspect
@Component
public class ArticleContentAspect{
// 定義切入點
@Pointcut("@annotation(com.tcl.uf.content.annotation.ArticleOperational)")
public void operational() {}
/**
* 獲取引數串列
* @param joinPoint
* @return
* @throws ClassNotFoundException
* @throws NoSuchMethodException
*/
private static Map<String, Object> getFieldsName(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer();
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
String[] parameterNames = pnd.getParameterNames(method);
Map<String, Object> paramMap = new HashMap<String, Object>();
for (int i = 0; i < parameterNames.length; i++) {
paramMap.put(parameterNames[i], args[i]);
}
return paramMap;
}
@AfterReturning(value = "operational()")
public void p1(JoinPoint joinPoint){
//HttpServletRequest 和 HttpServletResponse 物件(示例)
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
HttpServletResponse response = attributes.getResponse();
User user = getUserInfo(request);
//獲取請求引數和值(示例)
Map<String,Object> params = getFieldsName(joinPoint);
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
//獲取注解資訊(示例)
ArticleOperational articleOperational= method.getDeclaredAnnotation(ArticleOperational.class);
//持久化操作日志
saveArticleOperationalRecord(articleOperational.action(),user.getUserId(),JSON.toJSONString(params));
}
private void saveArticleOperationalRecord(String operational,String userId,String remarks){
//持久化操作記錄到資料庫
}
private User getUserInfo(HttpServletRequest request){
//我此處寫的是偽代碼、僅供參考
return new User("youyun.xu","13246738031");
}
}
-
業務使用AOP切面注解
package com.demo.service.impl;
import com.demo.annotation.ArticleOperational;
import com.demo.service.ArticleContentService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @author youyun.xu
* @ClassName: ArticleContentServiceImpl
* @Description: 文章內容服務Service
* @date 2020/7/23 上午09:00
*/
@Service("articleContentService")
public class ArticleContentServiceImpl implements ArticleContentService {
private static final Logger log = LoggerFactory.getLogger(ArticleContentServiceImpl.class);
@Override
@Transactional(rollbackFor = Exception.class)
@ArticleOperational(action = "取消置頂")
public void cancelArticleTop(Long articleId) {
//取消置頂業務核心代碼
}
@Override
@Transactional(rollbackFor = Exception.class)
@ArticleOperational(action = "洗掉文章")
public void delete(List<Long> articleIds) {
//洗掉文章業務核心代碼
}
@Override
@Transactional(rollbackFor = Exception.class)
@ArticleOperational(action = "文章下線")
public void offline(List<Long> articleIds) {
//文章下線業務核心代碼
}
@Override
@Transactional(rollbackFor = Exception.class)
@ArticleOperational(action = "文章發布")
public void publish(List<Long> articleIds) {
//文章發布業務核心代碼
}
}
在核心業務代碼的函式上添加自定義注解 @ArticleOperational(action = "洗掉文章") 即可,
-
小結
- 高效、靈活、對代碼無任何侵入性
- 減少大量冗余代碼、代碼可讀性更好
- 原創不易,你如果喜歡請給幫我反手點個贊,
人生不要怕做選擇,因為選錯才是必然的,選對才是偶然的,不要太多勉強,做自己喜歡做的事情,不要怕選錯,而是提高選對的成功率,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/242426.html
標籤:其他
下一篇:無線傳感器網路
