⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cglib2aopproxy.java

📁 Java/J2EE application framework based on [Expert One-on-One J2EE Design and Development] by Rod John
💻 JAVA
📖 第 1 页 / 共 2 页
字号:

	/**
	 * Dispatcher for any methods declared on the Advised class.
	 */
	private class AdvisedDispatcher implements Dispatcher, Serializable {

		public Object loadObject() throws Exception {
			return advised;
		}
	}


	/**
	 * Dispatcher for the equals() method. Ensures that the method call is
	 * always handled by this class.
	 */
	private class EqualsInterceptor implements MethodInterceptor, Serializable {

		private AdvisedSupport advised;

		private EqualsInterceptor(AdvisedSupport advised) {
			this.advised = advised;
		}

		public Object intercept(Object proxy, Method method, Object[] args,
		    MethodProxy methodProxy) throws Throwable {

			Object other = args[0];

			if (other == null)
				return Boolean.FALSE;
			if (other == proxy)
				return Boolean.TRUE;

			AdvisedSupport otherAdvised = null;

			if (other instanceof Factory) {
				// The 0th callback will be the OldCglib2AopProxy if we're
				// correct
				Callback callback = ((Factory) other)
				    .getCallback(INVOKE_EQUALS);
				if (!(callback instanceof EqualsInterceptor))
					return Boolean.FALSE;
				otherAdvised = ((EqualsInterceptor) callback).advised;
			}
			else {
				// Not a valid comparison
				return Boolean.FALSE;
			}

			return Boolean.valueOf(AopProxyUtils.equalsInProxy(advised, otherAdvised));
		}
	}


	/**
	 * Interceptor used specifcally for advised methods on a frozen, static
	 * proxy.
	 */
	private static class FixedChainStaticTargetInterceptor
	    implements MethodInterceptor, Serializable {

		private final List adviceChain;
		private final Object target;
		private final Class targetClass;

		public FixedChainStaticTargetInterceptor(List adviceChain, Object target) {
			this.adviceChain = adviceChain;
			this.target = target;
			this.targetClass = target.getClass();
		}

		public Object intercept(Object proxy, Method method, Object[] args,
		    MethodProxy methodProxy) throws Throwable {

			MethodInvocation invocation = null;

			Object retVal = null;

			// We need to create a method invocation...
			invocation = new MethodInvocationImpl(proxy, target, method, args,
			    targetClass, adviceChain, methodProxy);

			// If we get here, we need to create a MethodInvocation
			retVal = invocation.proceed();

			retVal = massageReturnTypeIfNecessary(proxy, target, retVal);
			return retVal;

		}
	}


	/**
	 * General purpose AOP callback. Used when the target is dynamic or when the
	 * proxy is not frozen.
	 */
	private class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

		public Object intercept(Object proxy, Method method, Object[] args,
		    MethodProxy methodProxy) throws Throwable {

			MethodInvocation invocation = null;
			Object oldProxy = null;
			boolean setProxyContext = false;

			Class targetClass = null; //targetSource.getTargetClass();
			Object target = null;

			try {
				Object retVal = null;

				// May be null. Get as late as possible to minimize the time we
				// "own" the target,
				// in case it comes from a pool.
				target = getTarget();
				if (target != null) {
					targetClass = target.getClass();
				}

				if (advised.exposeProxy) {
					// Make invocation available if necessary
					oldProxy = AopContext.setCurrentProxy(proxy);
					setProxyContext = true;
				}

				List chain = advised.getAdvisorChainFactory()
				    .getInterceptorsAndDynamicInterceptionAdvice(advised,
				        proxy, method, targetClass);

				// Check whether we only have one InvokerInterceptor: that is,
				// no real advice,
				// but just reflective invocation of the target.
				if (chain.isEmpty()) {
					// We can skip creating a MethodInvocation: just invoke the
					// target directly
					// Note that the final invoker must be an InvokerInterceptor
					// so we know it does
					// nothing but a reflective operation on the target, and no
					// hot swapping or fancy proxying
					retVal = methodProxy.invoke(target, args);
				}
				else {
					// We need to create a method invocation...
					invocation = new MethodInvocationImpl(proxy, target,
					    method, args, targetClass, chain, methodProxy);

					// If we get here, we need to create a MethodInvocation
					retVal = invocation.proceed();
				}

				retVal = massageReturnTypeIfNecessary(proxy, target, retVal);
				return retVal;
			}
			finally {
				if (target != null) {
					releaseTarget(target);
				}

				if (setProxyContext) {
					// Restore old proxy
					AopContext.setCurrentProxy(oldProxy);
				}
			}
		}

		/**
		 * CGLIB uses this to drive proxy creation.
		 */
		public int hashCode() {
			return advised.hashCode();
		}

		protected Object getTarget() throws Exception {
			return advised.getTargetSource().getTarget();
		}

		protected void releaseTarget(Object target) throws Exception {
			advised.getTargetSource().releaseTarget(target);
		}
	}


	/**
	 * CallbackFilter to assign Callbacks to methods.
	 */
	private class ProxyCallbackFilter implements CallbackFilter {

		private final AdvisedSupport advised;

		public ProxyCallbackFilter(AdvisedSupport advised) {
			this.advised = advised;
		}

		/**
		 * Implementation of CallbackFilter.accept() to return the index of the
		 * callback we need.
		 * <p/>
		 * The callbacks for each proxy are built up of a set of fixed callbacks
		 * for general use and then a set of callbacks that are specific to a
		 * method for use on static targets with a fixed advice chain.
		 * <p/>
		 * The callback used is determined thus:
		 * <dl>
		 * <dt>For exposed proxies</dt>
		 * <dd>Exposing the proxy requires code to execute before and after the
		 * method/chain invocation. This means we must use
		 * DynamicAdvisedInterceptor, since all other interceptors can avoid the
		 * need for a try/catch block</dd>
		 * <dt>For Object.finalize():</dt>
		 * <dd>No override for this method is used</dd>
		 * <dt>For equals():</dt>
		 * <dd>The EqualsInterceptor is used to redirect equals() calls to a
		 * special handler to this proxy.</dd>
		 * <dt>For methods on the Advised class:</dt>
		 * <dd>the AdvisedDispatcher is used to dispatch the call directly to
		 * the target</dd>
		 * <dt>For advised methods:</dt>
		 * <dd>If the target is static and the advice chain is frozen then a
		 * FixedChainStaticTargetInterceptor specific to the method is used to
		 * invoke the advice chain. Otherwise a DyanmicAdvisedInterceptor is
		 * used.</dd>
		 * <dt>For non-advised methods:</dt>
		 * <dd>Where it can be determined that the method will not return
		 * <code>this</code> or when ProxyFactory.getExposeProxy() return
		 * false then a Dispatcher is used. For static targets the
		 * StaticDispatcher is used and for dynamic targets a
		 * DynamicUnadvisedInterceptor is used. If it possible for the method to
		 * return <code>this</code> then a StaticUnadvisedInterceptor is used
		 * for static targets - the DynamicUnadvisedInterceptor already
		 * considers this.</dd>
		 * </dl>
		 *
		 * @see net.sf.cglib.proxy.CallbackFilter#accept(java.lang.reflect.Method)
		 */
		public int accept(Method method) {

			// don't modify protected methods
			if(Modifier.isProtected(method.getModifiers())) {
				return NO_OVERRIDE;
			}
			
			if (method.getDeclaringClass() == Object.class
			    && method.getName().equals("finalize")) {
				logger
				    .info("Object.finalize () method found - using NO_OVERRIDE");
				return NO_OVERRIDE;
			}

			if (method.getDeclaringClass() == Advised.class) {
				if (logger.isInfoEnabled()) {
					logger
					    .info("Method "
					    + method
					    + " is declared on Advised - using DISPATCH_ADVISED");
				}
				return DISPATCH_ADVISED;
			}

			// We must always proxy equals, to direct calls to this
			if (isEqualsMethod(method)) {
				logger.info("Found equals() method - using INVOKE_EQUALS");
				return INVOKE_EQUALS;
			}

			// Could consider more aggressive optimization in which we have a
			// distinct
			// callback with the advice chain for each method, but it's probably
			// not
			// worth it

			// We can apply optimizations
			// The optimization means that we evaluate whether or not there's an
			// advice chain once only, befre each invocation.

			Class targetClass = advised.getTargetSource().getTargetClass();

			// Proxy is not yet available, but that shouldn't matter

			List chain = advised.getAdvisorChainFactory()
			    .getInterceptorsAndDynamicInterceptionAdvice(advised, null,
			        method, targetClass);

			boolean haveAdvice = !chain.isEmpty();
			boolean exposeProxy = advised.getExposeProxy();
			boolean isStatic = advised.getTargetSource().isStatic();
			boolean isFrozen = advised.isFrozen();

			if (haveAdvice) {

				// if exposing the proxy then AOP_PROXY must be used.
				if (exposeProxy) {
                    if(logger.isInfoEnabled()) {
                        logger.info("Must expose proxy on advised method " + method + " - using AOP_PROXY");
                    }
					return AOP_PROXY;
				}

				String key = method.toString();

				// check to see if we have fixed interceptor to serve this
				// method
				// else use the AOP_PROXY
				if (isStatic && isFrozen
				    && fixedInterceptorMap.containsKey(key)) {
					if (logger.isInfoEnabled()) {
						logger
						    .info("Method "
						    + method
						    + " has Advice and optimisations are enabled - using specific FixedChainStaticTargetInterceptor");
					}

					// we know that we are optimising so we can use the
					// FixedStaticChainInterceptors
					int index = ((Integer) fixedInterceptorMap.get(key))
					    .intValue();
					return (index + fixedInterceptorOffset);
				}
				else {
                    if(logger.isInfoEnabled()) {
                        logger.info("Unable to apply any optimisations to advised method " + method + " - using AOP_PROXY");
                    }
					return AOP_PROXY;
				}

			}
			else {
				// see if the return type of the method is outside the
				// class hierarchy of the target type. If so we know it never
				// needs to have return type massge and can use a dispatcher.

				// if the proxy is being exposed then
				// must use the interceptor
				// the correct one is already configued.
				// if the target is not static cannot use
				// a Dispatcher because the target can not then be released.
				if (exposeProxy || !isStatic) {
					return INVOKE_TARGET;
				}

				Class returnType = method.getReturnType();

				if (targetClass == returnType) {
					if (logger.isInfoEnabled()) {
						logger
						    .info("Method "
						    + method
						    + "has return type same as target type (may return this) - using INVOKE_TARGET");
					}
					return INVOKE_TARGET;
				}
				else if (returnType.isPrimitive()
				    || !returnType.isAssignableFrom(targetClass)) {
					if (logger.isInfoEnabled()) {
						logger
						    .info("Method "
						    + method
						    + "has return type that ensures this cannot be returned- using DISPATCH_TARGET");
					}
					return DISPATCH_TARGET;
				}
				else {
					if (logger.isInfoEnabled()) {
						logger
						    .info("Method "
						    + method
						    + "has return type that is assignable from the target type (may return this) - using INVOKE_TARGET");
					}
					return INVOKE_TARGET;
				}
			}
		}

		public int hashCode() {
			return 0;
		}

		public boolean equals(Object other) {
			if (other == null)
				return false;
			if (other == this)
				return true;

			ProxyCallbackFilter otherCallbackFilter = null;
			if (other instanceof ProxyCallbackFilter) {
				otherCallbackFilter = (ProxyCallbackFilter) other;
			}
			else {
				// Not a valid comparison
				return false;
			}

			if (advised.isFrozen() != otherCallbackFilter.advised.isFrozen()) {
				return false;
			}

			if (advised.getExposeProxy() != otherCallbackFilter.advised.getExposeProxy()) {
				return false;
			}

			if (advised.getTargetSource().isStatic() != otherCallbackFilter.advised
			    .getTargetSource().isStatic()) {
				return false;
			}

			return (AopProxyUtils.equalsProxiedInterfaces(advised,
			    otherCallbackFilter.advised) & AopProxyUtils
			    .equalsAdvisors(advised, otherCallbackFilter.advised));
		}

	}


	/**
	 * Serializable replacement for CGLIB's NoOp interface.
	 */
	private class NoOp implements net.sf.cglib.proxy.NoOp, Serializable {
	}


	/**
	 * Implementation of AOP Alliance MethodInvocation used by this AOP proxy
	 */
	private static class MethodInvocationImpl extends ReflectiveMethodInvocation {

		private final MethodProxy methodProxy;

		public MethodInvocationImpl(Object proxy, Object target, Method m,
		    Object[] arguments, Class targetClass,
		    List interceptorsAndDynamicMethodMatchers,
		    MethodProxy methodProxy) {
			super(proxy, target, m, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
			this.methodProxy = methodProxy;
		}

		/**
		 * Gives a marginal performance improvement versus using reflection to
		 * invoke the target.
		 * @see org.springframework.aop.framework.ReflectiveMethodInvocation#invokeJoinpoint()
		 */
		protected Object invokeJoinpoint() throws Throwable {
			return this.methodProxy.invoke(target, arguments);
		}
	}

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -