Spring中AOP功能在實踐中具體應用
阿新 • • 發佈:2018-12-15
spring以秋風掃落葉的姿態進入java開發的方方面面,特別是在大型的企業級開發上面,所依靠的主要武器就是ioc和aop,關於ioc和aop的具體含義和意義,網上已經說得相當明白了.
通俗來說ioc就相當於一箇中介,它可以幫你管理各個類之間呼叫等關係,使用時直接用@Autowired引用,而不用再自己通過new來建立物件.aop則是相當於你的祕書,你自己只需要專注核心業務邏輯,而一些邊緣和不重要的功能統統可以交給他,比如說,統計每個方法的執行時間,操作日誌等等,都可以交給aop.
有了ioc和aop這2個利器,在大型企業級的開發中,將大大降低專案的複雜度,使得非常方便的在後期進行修改和優化.
這篇部落格主要講解aop的使用流程,aop的基本知識,大家網上一搜全是,這次主要講解aop在專案中的真實應用.具體場景就是:將專案中的操作日誌寫入到資料,比如說是:在2018-10-16 18:59:23張三查詢了來訪記錄的歷史資料,這樣有利於後期劃定責任
1,想要使用aop的功能需要在配置檔案進行如下的配置
<aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true"/>
2,第一步先寫個列舉類(enum),有利於後面的使用,程式碼如下
public enum OperateEnum { OPERATE_ADD("operate_add","新增操作"), OPERATE_INQUIRE("operate_inquire","查詢操作"), OPERATE_UPDATE("operate_update","更新操作"), OPERATE_DELETE("operate_delete","刪除操作"); private String code; private String msg; private OperateEnum(String code, String msg) { this.code = code; this.msg = msg; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public static String getByValue(String code) { for (OperateEnum operateEnum : values()) { if (operateEnum.getCode().equals(code)) { return operateEnum.getMsg(); } } return null; } }
3,自定義一個註解類,用於每一個需要記錄的方法上面,程式碼如下
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperateLog {
OperateEnum operate() default OperateEnum.INQUIRE;
String description() default "";
}
至於各個註解的具體解釋,大家可以自行百度,都解釋的很清楚
4,將註解類配置到你要控制的方法上面,如下所示
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping(value="/save",method =RequestMethod.POST)
@ResponseBody
@OperateLog(operate = OperateEnum.OPERATE_ADD,description="新增操作")
public RespData save(HttpServletRequest request, HttpServletResponse response,User user){
RespData respData = userService.save(user);
return respData;
}
}
5,編寫切面類,切面類是具體負責處理的類,這樣分割核心業務和邊緣業務的好處就是,前期可以專注於編寫核心業務,而不用考慮邊緣業務,後期可以隨意新增,這樣就將兩者分割開了,程式碼如下:
@Component
@Aspect
public class OperateAspect {
@Pointcut("@annotation(com.lgg.aspect.OperateLog)")//括號內為註解類OperateLog的具體路徑
public void operatePointCut(){}//宣告一個切入點
@AfterReturning(pointcut = "operatePointCut()",returning = "result")
public void save(JoinPoint joinPoint,Object result){
//獲取引數
Object[] objs=joinPoint.getArgs();
//獲取返回值
Object obj=objs[0];
Map<String ,Object> inMap = getParameter(obj);
Map<String ,Object> outMap = getParameter(result);
// 獲取註解自定義引數
OperateLog operateLog = getOperateLog(joinPoint);
//接下來將inMap,outMap,operateLog按照需要寫入到資料即可
}
//拓展日誌的功能,對攔截的入參進行反射獲取資訊
private Map<String, Object> getParameter(Object obj) {
try {
//反射物件中的屬性
Class clazz=obj.getClass();
Field[] fields= clazz.getDeclaredFields();
Map<String,Object> resultMap=new java.util.HashMap<>();
//遍歷並返回
for(Field field:fields){
String fieldName=field.getName();
PropertyDescriptor pd=new PropertyDescriptor(fieldName,clazz);
Method readMethod = pd.getReadMethod();
Object resultObj= readMethod.invoke(obj);
resultMap.put(fieldName,resultObj);
}
return resultMap;
}
catch (Exception e){
e.printStackTrace();
}
return null;
}
private static OperateLog getOperateLog(JoinPoint joinPoint) throws Exception{
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if(method != null)
{
return method.getAnnotation(OperateLog.class);
}
return null;
}
}