問題的引出:
傳統的OOP程序經常表現出一些不自然的現象,核心業務中總摻雜着一些不相關聯的特殊業務,如日志記錄,權限驗證,事務控制,性能檢測,錯誤信息檢測等等,這些特殊業務可以說和核心業務沒有根本上的關聯而且核心業務也不關心。
這些特殊業務會帶來哪些問題呢?
1.代碼混亂,大量的外圍操作可能會混亂核心操作的代碼,而且當外圍模塊有重大修改時也會影響到核心模塊。
2.代碼分散和冗余:同樣的功能代碼,在其他的模塊幾乎隨處可見,導致代碼分散並且冗余度高。
3.代碼質量低擴展難:由於不太相關的業務代碼混雜在一起,無法專注核心業務代碼,當進行類似無關業務擴展時又會直接涉及到核心業務的代碼,導致拓展性低。
解決:
假設現在我們把日志、權限、事務、性能監測等外圍業務看作單獨的關注點(也可以理解為單獨的模塊),每個關注點都可以在需要它們的時刻及時被運用而且無需提前整合到核心模塊中。將每個關注點與核心業務模塊分離,作為單獨的功能,橫切幾個核心業務模塊。
這就叫AOP(面向切面編程)
其中的幾個應用:aop配置
<aop:aspectj-autoproxy /> <beans:bean id="controllerAop" class="xxx.common.aop.ControllerAOP" /> <aop:config> <aop:aspect id="myAop" ref="controllerAop"> <aop:pointcut id="target" expression="execution(public xxx.common.beans.ResultBean *(..))" /> <aop:around method="handlerControllerMethod" pointcut-ref="target" /> </aop:aspect> </aop:config>
ResultBean定義帶泛型
@Data public class ResultBean<T> implements Serializable { private static final long serialVersionUID = 1L; public static final int NO_LOGIN = -1; public static final int SUCCESS = 0; public static final int FAIL = 1; public static final int NO_PERMISSION = 2; private String msg = "success"; private int code = SUCCESS; private T data; public ResultBean() { super(); } public ResultBean(T data) { super(); this.data = data; } public ResultBean(Throwable e) { super(); this.msg = e.toString(); this.code = FAIL; } }
AOP代碼打印日志,捕獲異常,異常區分已知異常和未知異常,包括接口執行時間
這個關於自定義異常https://xwjie.github.io/rule/exception.html還是不錯的
/** * 處理和包裝異常 */ public class ControllerAOP { private static final Logger logger = LoggerFactory.getLogger(ControllerAOP.class); public Object handlerControllerMethod(ProceedingJoinPoint pjp) { long startTime = System.currentTimeMillis(); ResultBean<?> result; try { result = (ResultBean<?>) pjp.proceed(); logger.info(pjp.getSignature() + "use time:" + (System.currentTimeMillis() - startTime));//日志去記錄接口執行時間 } catch (Throwable e) { result = handlerException(pjp, e); } return result; } /** * 封裝異常信息,注意區分已知異常(自己拋出的)和未知異常 */ private ResultBean<?> handlerException(ProceedingJoinPoint pjp, Throwable e) { ResultBean<?> result = new ResultBean(); // 已知異常 if (e instanceof CheckException) { result.setMsg(e.getLocalizedMessage()); result.setCode(ResultBean.FAIL); } else if (e instanceof UnloginException) { result.setMsg("Unlogin"); result.setCode(ResultBean.NO_LOGIN); } else { logger.error(pjp.getSignature() + " error ", e); //TODO 未知的異常,應該格外注意,可以發送郵件通知等 result.setMsg(e.toString()); result.setCode(ResultBean.FAIL); } return result; } }