标签:exce exception res == tostring 切面 ring web 实现
在不论什么一个项目中都不可或缺的存在两种bean,一种是实现系统核心功能的bean,我们称之为业务类,第二种是与系统核心业务无关但同一时候又提供十分重要服务bean,我们称之为服务类。业务类的bean依据每一个系统自身核心功能的不同能够有随意多个,可是服务类的种类在各个系统之间的差异却并非非常大。在系统中经经常使用到的服务有下面几种。权限服务,日志服务。缓存服务,事务服务以及预警服务等。在整个系统的不断进化过程中。服务类与业务类的关系也不断的发生着变化,由当初垂直模式变为横切模式,这也是编程思想不断演化过程。服务类与业务类本来就不应耦合在一起,否则不但会造成大量的代码冗余同一时候也难以对服务进行可控性变更。
那么怎样解决依据不同业务类自身要求为其提供不同服务的问题呢?spring aop给出了完美解决 方案。Spring解决这个难题的核心思想是将服务类与业务类统统交由spring容器管理。依据不同业务类的不同要求动态配置服务类。也即动态联编服务类与业务类实现两者的自由组合。至于业务类与服务类之间的关系演变能够用下图简单呈现一下:
这张图是最原始的业务-服务关系图,看到这连想都不敢想了,相同的服务反复出如今N多个业务中,想想也是醉了,假设哪天服务内容改变除了跳楼预计也没有别的选择了,还好Spring AOP的出现将这个让人头疼的问题。使用Spring 注解方式将切面类横切到各个服务类中就能够一绝解决代码冗余。难于维护的问题
本图在代码中的提现例如以下:
package com.test.util; @Aspect public class AuthorityService { @Autowired private LogManager logManager; @Before("execution(* com.test.web.*.*(..))") public void logAll(JoinPoint point) throws Throwable { System.out.println("======authority-before======"); } @After("execution(* com.test.web.*.*(..))") public void after() { System.out.println("=========authority-after========="); } // 方法运行的前后调用 @Around("execution(* com.test.web.*.*(..))") public Object around(ProceedingJoinPoint point) throws Throwable { System.out.println("======authority-around開始之前before======"); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder .getRequestAttributes()).getRequest(); // 获得具体时间 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // Calendar ca = Calendar.getInstance(); // String operDate = df.format(ca.getTime()); Log sysLog = new Log(); // 開始时间 sysLog.setStartTime(df.format(new Date())); // 获取ip地址 String ip = TCPIPUtil.getIpAddr(request); String loginName; String name; String methodRemark = getMthodRemark(point); String methodName = point.getSignature().getName(); String packages = point.getThis().getClass().getName(); if (packages.indexOf("$$EnhancerByCGLIB$$") > -1) { // 假设是CGLIB动态生成的类 try { packages = packages.substring(0, packages.indexOf("$$")); } catch (Exception ex) { ex.printStackTrace(); } } Object object; try { // method_param = point.getArgs(); //获取方法參数 // String param=(String) point.proceed(point.getArgs()); object = point.proceed(); } catch (Exception e) { // 异常处理记录日志..log.error(e); throw e; } sysLog.setIp(ip); sysLog.setClazz(packages); sysLog.setMethod(methodName); sysLog.setMessage(methodRemark); // 结束时间 sysLog.setEndTime(df.format(new Date())); // 返回结果 if (object == null) { sysLog.setResult("无返回值"); } else { sysLog.setResult(object.toString()); } logManager.addLog(sysLog); System.out.println("======authority-around開始之前after======"); return object; } @AfterReturning("execution(* com.test.web.*.*(..))") public void x(){ System.out.println("-------authority-afterreturning-------"); } // 获取方法的中文备注____用于记录用户的操作日志描写叙述 public static String getMthodRemark(ProceedingJoinPoint joinPoint) throws Exception { String targetName = joinPoint.getTarget().getClass().getName(); String methodName = joinPoint.getSignature().getName(); Object[] arguments = joinPoint.getArgs(); Class targetClass = Class.forName(targetName); Method[] method = targetClass.getMethods(); String methode = ""; for (Method m : method) { if (m.getName().equals(methodName)) { Class[] tmpCs = m.getParameterTypes(); if (tmpCs.length == arguments.length) { Logger methodCache = m.getAnnotation(Logger.class); // 获得标记,为空时没有标记 if (methodCache != null) { methode = methodCache.remark(); } break; } } } return methode; } }
此时我们须要如何做呢?还好Spring同一时候提供了基于xml配置方式的aop,这种方式在相当大的程度上弥补了@Aspect不足,他能够依据不同的配置方式将不同的服务切入到不同类的不同方法上。这样细的粒度足以让我们实现各种服务对业务的动态组合。说道这可能会有人问既然spring提供了基于xml配置的aop。那我们仅仅须要将不同的服务均配置在xml文件里不是相同能够实现业务与服务的动态组合吗?听上去似乎非常有道理,果真这种话似乎基于注解的aop似乎就能够被替代了。可是程序效率的问题又让我们不得不正确xml配置方式和注解方式进行再次衡量。
因为xml是在执行期动态联编确定切面的,解析xml的过程毫无疑问的会占用系统资源,假设将大量的aop配置配置在xml文件里将会得不偿失,而@Aspect方式支持编译期织入且不须要生成代理,这样就使得效率上会有优势。如此来看仅仅要将xml方式与@Aspect方式混合使用。将粗粒度的服务(如日志和权限服务)使用@Aspect方式进行切入,对于细粒度的服务(如缓存服务)使用xml方式配置在spring中就能够完美解决以上问题了。
以下是两种方式结合使用的实例。先来看配置文件:
<?xml version="1.0" encoding="UTF-8"?
> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd"> <!-- 注解扫描包 --> <context:component-scan base-package="com.test" /> <!-- 开启注解 --> <mvc:annotation-driven /> <!-- 静态资源(js/image)的訪问 --> <mvc:resources location="/js/" mapping="/js/**" /> <!-- 定义视图解析器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/"></property> <property name="suffix" value=".jsp"></property> </bean> <!-- 启用Spring对基于@AspectJ aspects的配置支持 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <bean id="logService" class="com.test.util.LogService"></bean> <bean id="cacheService" class="com.test.util.CacheService"></bean> <aop:config proxy-target-class="true"> <aop:aspect ref="cacheService"> <aop:pointcut id="log" expression="execution(* com.test.web.UserController.getAllUser(..))"/> <aop:before pointcut-ref="log" method="logAll"/> <aop:after pointcut-ref="log" method="after"/> <aop:after-returning pointcut-ref="log" method="x"/> <aop:around pointcut-ref="log" method="around"/> </aop:aspect> </aop:config> </beans>
package com.test.util; @Aspect public class LogService { @Autowired private LogManager logManager; @Before("execution(* com.test.web.*.*(..))") public void logAll(JoinPoint point) throws Throwable { System.out.println("======log-before======"); } @After("execution(* com.test.web.*.*(..))") public void after() { System.out.println("=========cache-after========="); } // 方法运行的前后调用 @Around("execution(* com.test.web.*.*(..))") public Object around(ProceedingJoinPoint point) throws Throwable { System.out.println("======log-around開始之前before======"); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder .getRequestAttributes()).getRequest(); // 获得具体时间 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Log sysLog = new Log(); // 開始时间 sysLog.setStartTime(df.format(new Date())); // 获取ip地址 String ip = TCPIPUtil.getIpAddr(request); String loginName; String name; String methodRemark = getMthodRemark(point); String methodName = point.getSignature().getName(); String packages = point.getThis().getClass().getName(); if (packages.indexOf("$$EnhancerByCGLIB$$") > -1) { // 假设是CGLIB动态生成的类 try { packages = packages.substring(0, packages.indexOf("$$")); } catch (Exception ex) { ex.printStackTrace(); } } // String operatingcontent = ""; // Object[] method_param = null; Object object; try { // method_param = point.getArgs(); //获取方法參数 // String param=(String) point.proceed(point.getArgs()); object = point.proceed(); } catch (Exception e) { // 异常处理记录日志..log.error(e); throw e; } sysLog.setIp(ip); sysLog.setClazz(packages); // 包名.+方法名 // packages + "." + methodName sysLog.setMethod(methodName); sysLog.setMessage(methodRemark); // 结束时间 sysLog.setEndTime(df.format(new Date())); // 返回结果 if (object == null) { sysLog.setResult("无返回值"); } else { sysLog.setResult(object.toString()); } logManager.addLog(sysLog); System.out.println("======log-around開始之前after======"); return object; } @AfterReturning("execution(* com.test.web.*.*(..))") public void x(){ System.out.println("-------log-afterreturning-------"); } // 获取方法的中文备注____用于记录用户的操作日志描写叙述 public static String getMthodRemark(ProceedingJoinPoint joinPoint) throws Exception { String targetName = joinPoint.getTarget().getClass().getName(); String methodName = joinPoint.getSignature().getName(); Object[] arguments = joinPoint.getArgs(); Class targetClass = Class.forName(targetName); Method[] method = targetClass.getMethods(); String methode = ""; for (Method m : method) { if (m.getName().equals(methodName)) { Class[] tmpCs = m.getParameterTypes(); if (tmpCs.length == arguments.length) { Logger methodCache = m.getAnnotation(Logger.class); // 获得标记,为空时没有标记 if (methodCache != null) { methode = methodCache.remark(); } break; } } } return methode; } }
package com.test.util; public class LogService { @Autowired private CacheManager logManager; public void pointcut() { } public void logAll(JoinPoint point) throws Throwable { System.out.println("======cache-before======"); } public void after() { System.out.println("=========cache-after========="); } // 方法运行的前后调用 public Object around(ProceedingJoinPoint point) throws Throwable { System.out.println("======cache-around開始之前before======"); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder .getRequestAttributes()).getRequest(); // 获得具体时间 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // Calendar ca = Calendar.getInstance(); // String operDate = df.format(ca.getTime()); Log sysLog = new Log(); // 開始时间 sysLog.setStartTime(df.format(new Date())); // 获取ip地址 String ip = TCPIPUtil.getIpAddr(request); String loginName; String name; String methodRemark = getMthodRemark(point); String methodName = point.getSignature().getName(); String packages = point.getThis().getClass().getName(); if (packages.indexOf("$$EnhancerByCGLIB$$") > -1) { // 假设是CGLIB动态生成的类 try { packages = packages.substring(0, packages.indexOf("$$")); } catch (Exception ex) { ex.printStackTrace(); } } Object object; try { // method_param = point.getArgs(); //获取方法參数 // String param=(String) point.proceed(point.getArgs()); object = point.proceed(); } catch (Exception e) { // 异常处理记录日志..log.error(e); throw e; } sysLog.setIp(ip); sysLog.setClazz(packages); // 包名.+方法名 // packages + "." + methodName sysLog.setMethod(methodName); sysLog.setMessage(methodRemark); // 结束时间 sysLog.setEndTime(df.format(new Date())); // 返回结果 if (object == null) { sysLog.setResult("无返回值"); } else { sysLog.setResult(object.toString()); } logManager.addLog(sysLog); System.out.println("======cache-around開始之前after======"); return object; } public void x(){ System.out.println("-------cache-afterreturning-------"); } }
Spring容器装饰者模式应用之实现业务类与服务类自由组合的解决方式
标签:exce exception res == tostring 切面 ring web 实现
原文地址:http://www.cnblogs.com/yangykaifa/p/6977761.html