问题的引出:
传统的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; } }