写在前面
在这篇文章 中我们已经使得AOP有了雏形,但是代理逻辑的执行还是硬编码的,如下:
@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{if(method.getName().equals("doAction")){System.out.println("-----通过jdk动态代理,代理了类的doAction方法........");returnmethod.invoke(target,args);}returnnull;}当然这样做呢不能算错,但是扩展性就要弱很多了,在不同的业务场景中要做的内容不同,该怎么办呢?本文就一起来把这个问题解决了。
1:正文
对于具体业务方法执行过程的干预,我们可以抽象出一个增强的概念,即增强业务方法本身的能力,如开始没有性能统计的能力,通过AOP就能增加这部分能力,为此定义一个类似于标记的接口,如下:
packagecom.hc.minispring.web.v7_aop.aop;/** * 切面概念接口,更加具象化,使用方法拦截器进行增强(织入) */publicinterfaceAdvisor{MethodInterceptorgetMethodInterceptor();voidsetMethodInterceptor(MethodInterceptormethodInterceptor);}再来定义一个更加具体的拦截接口,代表要通过拦截的方式来增强:
packagecom.hc.minispring.web.v7_aop.aop;/** * 基于拦截的抽象(这里拦截也是一个抽象的概念,并不限定于如何拦截) */publicinterfaceInterceptorextendsAdvice{}在定义一个更加具体的基于方法执行拦截的接口:
/** * 具体的基于方法的拦截,也是我们实现AOP方法动态增强,织入的关键 */publicinterfaceMethodInterceptorextendsInterceptor{/** * 增强逻辑执行,invocation负责执行目标方法 * @param invocation * @return * @throws Throwable */Objectinvoke(MethodInvocationinvocation)throwsThrowable;}当然MethodInterceptor的具体实现类要由用户来指定,这里给出一个追踪方法执行过程的实现类以供测试使用,当然仅仅是个例子了:
packagecom.hc.minispring.web.v7_aop.aop;/** * 方法调用追踪 */publicclassTracingInterceptorimplementsMethodInterceptor{publicObjectinvoke(MethodInvocationi)throwsThrowable{System.out.println("即将执行方法: "+i.getMethod());Objectret=i.proceed();System.out.println("执行方法: "+i.getMethod()+" 成功*★,°*:.☆( ̄▽ ̄)/$:*.°★* 。!");returnret;}}为了能够更加明确的表达要做的事情,再来定义一个类似于Advice不真正干活的接口,Advisor切面(抽象出的概念),因为对方法执行的拦截就好像拦了一个面一样,如下:
packagecom.hc.minispring.web.v7_aop.aop;/** * 切面概念接口,更加具象化,使用方法拦截器进行增强(织入) */publicinterfaceAdvisor{MethodInterceptorgetMethodInterceptor();voidsetMethodInterceptor(MethodInterceptormethodInterceptor);}可以看出真正干活的还是MethodInterceptor,给出实现类:
/** * 默认实现简单,仅仅是维护了方法拦截器信息,更多的是Advisor对于功能的表达语义 * 即更加形象化的存在,并不做具体的工作 */publicclassDefaultAdvisorimplementsAdvisor{privateMethodInterceptormethodInterceptor;publicDefaultAdvisor(){}publicvoidsetMethodInterceptor(MethodInterceptormethodInterceptor){this.methodInterceptor=methodInterceptor;}publicMethodInterceptorgetMethodInterceptor(){returnthis.methodInterceptor;}}接着就来改造现有的类了,从生成代理类的FacotryBean入手,这里是com.hc.minispring.aop.ProxyFactoryBean,修改如下:
packagecom.hc.minispring.aop;// .../** * 真正返回代理bean的工厂bean */publicclassProxyFactoryBeanimplementsFactoryBean<Object>{// .../** 切面相关内容 **/privateStringinterceptorName;privateAdvisoradvisor;/** 切面相关内容 **/// ...protectedAopProxycreateAopProxy(){// System.out.println("----------createAopProxy for :" + target + "--------");// return getAopProxyFactory().createAopProxy(target);// 修改点:创建代理类时增加advisor参数,用来执行织入的增强逻辑returngetAopProxyFactory().createAopProxy(target,advisor);}// ...@OverridepublicObjectgetObject()throwsException{// 修改点:初始化切面initializeAdvisor();returngetSingletonInstance();}// 修改点:privatesynchronizedvoidinitializeAdvisor(){Objectadvice=null;MethodInterceptormi=null;try{// advice = (MethodInterceptor) this.beanFactory.getBean(this.interceptorName);// 正常应该从容器中获取,但是这里为了走通流程,忽略这个次要矛盾了!!!advice=newTracingInterceptor();// } catch (BeansException e) {}catch(Exceptione){e.printStackTrace();}advisor=newDefaultAdvisor();// 给切面设置用户给定的方法拦截器,即用户自定义的增强逻辑advisor.setMethodInterceptor((MethodInterceptor)advice);}// ...}advisor参数一路传,最终传给负责真正干活的代理类JdkDynamicAopProxy,同时修改其逻辑使用methodinterceprot执行增强的织入逻辑:
packagecom.hc.minispring.aop;// ...publicclassJdkDynamicAopProxyimplementsAopProxy,InvocationHandler{Objecttarget;// 修改点:增加切面Advisoradvisor;publicJdkDynamicAopProxy(Objecttarget,Advisoradvisor){this.target=target;this.advisor=advisor;}@OverridepublicObjectgetProxy(){Objectobj=Proxy.newProxyInstance(JdkDynamicAopProxy.class.getClassLoader(),target.getClass().getInterfaces(),this);System.out.println("----------创建基于jdk的动态代理类成功: ---------"+obj);returnobj;}@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{if(method.getName().equals("doAction")){Class<?>targetClass=(target!=null?target.getClass():null);// 修改点:使用切面执行逻辑MethodInterceptorinterceptor=this.advisor.getMethodInterceptor();MethodInvocationinvocation=newReflectiveMethodInvocation(proxy,target,method,args,targetClass);returninterceptor.invoke(invocation);}returnnull;}}先来测试一下,conroller:
@RequestMapping("/hello1746")// public String doTest(String name) {// public String doTest(/*HttpServletRequest request, HttpServletResponse response*/) {publicStringdoTest(/*HttpServletRequest request, HttpServletResponse response*/){System.out.println("action: "+action.getClass());action.doAction();return"index";}}运行:
截至这里源码 。
我们继续来优化。
在很多时候我们可能只需要在方法执行前进行增强,或者是在方法执行后进行增强。当然目前的方式也能够实现,但是对于用户来说还是不够简洁,并且也不够明确,所以我们来进一步进行优化,即分别定义执行前后的增强,方法执行前后的增强,方法执行前后的拦截,如下4个接口,2个类:
- 执行前的增强,方法执行前的增强,方法执行前的拦截
/** * 前置增强 */publicinterfaceBeforeAdviceextendsAdvice{}/** * 方法前置增强 */publicinterfaceMethodBeforeAdviceextendsBeforeAdvice{voidbefore(Methodmethod,Object[]args,Objecttarget)throwsThrowable;}/** * 方法前置拦截器(包装方法前置增强) */publicclassMethodBeforeAdviceInterceptorimplementsMethodInterceptor{privatefinalMethodBeforeAdviceadvice;publicMethodBeforeAdviceInterceptor(MethodBeforeAdviceadvice){this.advice=advice;}@OverridepublicObjectinvoke(MethodInvocationmi)throwsThrowable{// 方法执行前插入的逻辑,由用户给出具体的实现this.advice.before(mi.getMethod(),mi.getArguments(),mi.getThis());// 目标方法执行returnmi.proceed();}}- 执行后的增强,方法执行后的增强,方法执行后的拦截
/** * 后置增强 */publicinterfaceAfterAdviceextendsAdvice{}/** * 方法后置增强 */publicinterfaceAfterReturningAdviceextendsAfterAdvice{voidafterReturning(ObjectreturnValue,Methodmethod,Object[]args,Objecttarget)throwsThrowable;}publicclassAfterReturningAdviceInterceptorimplementsMethodInterceptor,AfterAdvice{privatefinalAfterReturningAdviceadvice;publicAfterReturningAdviceInterceptor(AfterReturningAdviceadvice){this.advice=advice;}@OverridepublicObjectinvoke(MethodInvocationmi)throwsThrowable{ObjectretVal=mi.proceed();this.advice.afterReturning(retVal,mi.getMethod(),mi.getArguments(),mi.getThis());returnretVal;}}修改proxyfactorybean的initAdvisor方法:
privatesynchronizedvoidinitializeAdvisor(){Objectadvice=null;MethodInterceptormi=null;try{// advice = (MethodInterceptor) this.beanFactory.getBean(this.interceptorName);// 正常应该从容器中获取,但是这里为了走通流程,忽略这个次要矛盾了!!!// advice = new TracingInterceptor();try{// advice = new TracingInterceptor();advice=newMethodBeforeAdvice(){@Overridepublicvoidbefore(Methodmethod,Object[]args,Objecttarget)throwsThrowable{System.out.println("method: "+method.getName()+" before execute***********!!!");}};}catch(Exceptione){e.printStackTrace();}if(adviceinstanceofBeforeAdvice){mi=newMethodBeforeAdviceInterceptor((MethodBeforeAdvice)advice);}elseif(adviceinstanceofAfterAdvice){mi=newAfterReturningAdviceInterceptor((AfterReturningAdvice)advice);}elseif(adviceinstanceofMethodInterceptor){mi=(MethodInterceptor)advice;}advisor=newDefaultAdvisor();advisor.setMethodInterceptor(mi);// } catch (BeansException e) {}catch(Exceptione){e.printStackTrace();}// advisor = new DefaultAdvisor();// // 给切面设置用户给定的方法拦截器,即用户自定义的增强逻辑// advisor.setMethodInterceptor((MethodInterceptor) advice);}根据不同的类型增强,进行不同的处理,这里作为测试写死了一个方法前置增强,运行测试:
截至这里源码 。
spring中还有环绕通知,但基本上一个道理。