Spring AOP 方式一 ProxyFactoryBean
先看例子
<bean id="personTarget" class="com.mycompany.PersonImpl"> <property name="name" value="Tony"/> <property name="age" value="51"/> </bean> <bean id="myAdvisor" class="com.mycompany.MyAdvisor"> <property name="someProperty" value="Custom string property value"/> </bean> <bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"> </bean> <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces" value="com.mycompany.Person"/> <property name="target" ref="personTarget"/> <property name="interceptorNames"> <list> <value>myAdvisor</value> <value>debugInterceptor</value> </list> </property> </bean>
配置点:
1、interceptorNames 拦截器数组
2、targetName 目标类
3、singleton 是否单例,默认true
4、proxyInterfaces 代理接口
5、optimize 建议使用cglib
6、proxyTargetClass
问题:
1、如何判断是使用jdk代理还是使用CGLIB?
答:默认使用jdk,如果没有使用接口或optimize 为true或proxyTargetClass 为true
2、为什么interceptorNames可以是什么类型?
答:可以是Advisor 或 MethodInterceptor 或MethodBeforeAdvice 或 AfterReturningAdvice 或 ThrowsAdvice 的实现类,Spring会自动把以上类封装成Advisor
实现原理:
ProxyFactoryBean是FactoryBean的实现类,其接口getObject会返回一个代理对象;如果代理方式为JDK,那么获取对象将返回一个JDK的代理对象,执行方式时将执行继承InvocationHandler的invoke方法
JdkDynamicAopProxy.invoke方法流程如下
1、如果方法是equals或hashCode 会特殊处理,暂不将
2、如果方式是继承自Advice,将直接执行
3、然后以递归的方式执行各个拦截器
MethodBeforeAdviceInterceptor 执行如下 public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); return mi.proceed(); }
AfterReturningAdviceInterceptor 执行如下 public Object invoke(MethodInvocation mi) throws Throwable { Object retVal = mi.proceed(); this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); return retVal; }
ThrowsAdviceInterceptor 执行如下 public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } catch (Throwable ex) { Method handlerMethod = getExceptionHandler(ex); if (handlerMethod != null) { invokeHandlerMethod(mi, ex, handlerMethod); } throw ex; } } /** * Determine the exception handle method. Can return null if not found. * @param exception the exception thrown * @return a handler for the given exception type */ private Method getExceptionHandler(Throwable exception) { Class exceptionClass = exception.getClass(); if (logger.isTraceEnabled()) { logger.trace("Trying to find handler for exception of type [" + exceptionClass.getName() + "]"); } Method handler = this.exceptionHandlerMap.get(exceptionClass); while (handler == null && !exceptionClass.equals(Throwable.class)) { exceptionClass = exceptionClass.getSuperclass(); handler = this.exceptionHandlerMap.get(exceptionClass); } if (handler != null && logger.isDebugEnabled()) { logger.debug("Found handler for exception of type [" + exceptionClass.getName() + "]: " + handler); } return handler; } private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable { Object[] handlerArgs; if (method.getParameterTypes().length == 1) { handlerArgs = new Object[] { ex }; } else { handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex}; } try { method.invoke(this.throwsAdvice, handlerArgs); } catch (InvocationTargetException targetEx) { throw targetEx.getTargetException(); } }