- 浏览: 490385 次
- 性别:
- 来自: 济南
文章分类
最新评论
-
effort0829:
更重要的是可以通过 URL打开特定的资源,然而再windows ...
【转载】自定义URL Protocol 协议 -
追梦人zxy:
mark。我记得cglib代理的话就用set注入
通过CGLIB实现AOP的浅析(顺便简单对比了一下JDK的动态代理) -
zacry:
这个问题最近也困扰了我很久,我是从一个老项目里迁移代码时遇到的 ...
通过CGLIB实现AOP的浅析(顺便简单对比了一下JDK的动态代理) -
bo_hai:
netfork 写道哎,大家都回家过中秋节了,自己的问题,自己 ...
Struts 2中验证失败后,radio回复到默认值的问题 -
greatghoul:
看不出有什么严重的,加上 <%- %> 不就可以了 ...
不要在erb中加注释,后果很严重
注:希望javaeye的管理员同志不要再把俺的这个贴丢到“问答”里了,但愿手下留情。
本人前天发了个贴,被转至“问答”后,有一位朋友根据错误信息给提了一条路,我测试了一下,解决了异常的问题,但是感觉很不爽:类中既要有默认构造函数,还要有一个提供注入Dao的构造函数。当然这个默认的构造函数纯粹是为了应付spring aop框架不能正确代理类的问题,没有其他任何用处。
今天Debug了一天,还是没搞明白原因到底是什么。
恳请对cglib熟悉的朋友给剖析一下。
不胜感激。
原问题地址:
http://www.iteye.com/problems/7876
我Debug到Spring的org.springframework.aop.framework.DefaultAopProxyFactory这个类中有一个内部类。
调用这个内部类的代码是DefaultAopProxyFactory的下面的方法:
然后,看一下Cglib2AopProxy这个类。
大家注意下面Cglib2AopProxy类的第197~202行。
大家再结合上面生成AopProxy对象的代码,我发现通过上面的CglibProxyFactory内部类生成aop对象后,再也没有调用Cglib2AopProxy类的setConstructorArguments方法设定构造函数的参数和参数类型,于是在当代码执行到下面类的第197行时,显然this.constructorArgs是null,这样,就会继续执行第201行,此时如果类没有默认的构造函数,就会抛出异常,也就会出现http://www.iteye.com/problems/7876里提到的问题。
难道这是spring在aop上处理的一个Bug?应该不会吧,如此成熟的框架,那原因又是什么呢?难道其他人没有碰到过吗?
由于spring中的调用过程东一块西一块的,我想改sping框架的代码,但感到无从下手,所以,请大家帮我耐心分析一下。
我已经将结果分析出来。
如果你有相同的问题,请读下面的文章。
http://netfork.iteye.com/blog/286215
本人前天发了个贴,被转至“问答”后,有一位朋友根据错误信息给提了一条路,我测试了一下,解决了异常的问题,但是感觉很不爽:类中既要有默认构造函数,还要有一个提供注入Dao的构造函数。当然这个默认的构造函数纯粹是为了应付spring aop框架不能正确代理类的问题,没有其他任何用处。
今天Debug了一天,还是没搞明白原因到底是什么。
恳请对cglib熟悉的朋友给剖析一下。
不胜感激。
原问题地址:
http://www.iteye.com/problems/7876
我Debug到Spring的org.springframework.aop.framework.DefaultAopProxyFactory这个类中有一个内部类。
/** * Inner factory class used to just introduce a CGLIB2 dependency * when actually creating a CGLIB proxy. */ private static class CglibProxyFactory { public static AopProxy createCglibProxy(AdvisedSupport advisedSupport) { return new Cglib2AopProxy(advisedSupport); } }
调用这个内部类的代码是DefaultAopProxyFactory的下面的方法:
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface()) { return new JdkDynamicAopProxy(config); } if (!cglibAvailable) { throw new AopConfigException( "Cannot proxy target class because CGLIB2 is not available. " + "Add CGLIB to the class path or specify proxy interfaces."); } return CglibProxyFactory.createCglibProxy(config); } else { return new JdkDynamicAopProxy(config); } }
然后,看一下Cglib2AopProxy这个类。
大家注意下面Cglib2AopProxy类的第197~202行。
大家再结合上面生成AopProxy对象的代码,我发现通过上面的CglibProxyFactory内部类生成aop对象后,再也没有调用Cglib2AopProxy类的setConstructorArguments方法设定构造函数的参数和参数类型,于是在当代码执行到下面类的第197行时,显然this.constructorArgs是null,这样,就会继续执行第201行,此时如果类没有默认的构造函数,就会抛出异常,也就会出现http://www.iteye.com/problems/7876里提到的问题。
难道这是spring在aop上处理的一个Bug?应该不会吧,如此成熟的框架,那原因又是什么呢?难道其他人没有碰到过吗?
由于spring中的调用过程东一块西一块的,我想改sping框架的代码,但感到无从下手,所以,请大家帮我耐心分析一下。
/* * Copyright 2002-2008 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.aop.framework; import java.io.Serializable; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.UndeclaredThrowableException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.WeakHashMap; import net.sf.cglib.core.CodeGenerationException; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.CallbackFilter; import net.sf.cglib.proxy.Dispatcher; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.Factory; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import net.sf.cglib.proxy.NoOp; import net.sf.cglib.transform.impl.UndeclaredThrowableStrategy; import org.aopalliance.aop.Advice; import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.aop.Advisor; import org.springframework.aop.PointcutAdvisor; import org.springframework.aop.RawTargetAccess; import org.springframework.aop.TargetSource; import org.springframework.aop.support.AopUtils; import org.springframework.core.SmartClassLoader; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; /** * CGLIB2-based {@link AopProxy} implementation for the Spring AOP framework. * * <p><i>Requires CGLIB 2.1+ on the classpath.</i>. * As of Spring 2.0, earlier CGLIB versions are not supported anymore. * * <p>Objects of this type should be obtained through proxy factories, * configured by an {@link AdvisedSupport} object. This class is internal * to Spring's AOP framework and need not be used directly by client code. * * <p>{@link DefaultAopProxyFactory} will automatically create CGLIB2-based * proxies if necessary, for example in case of proxying a target class * (see the {@link DefaultAopProxyFactory attendant javadoc} for details). * * <p>Proxies created using this class are thread-safe if the underlying * (target) class is thread-safe. * * @author Rod Johnson * @author Rob Harrop * @author Juergen Hoeller * @author Ramnivas Laddad * @see net.sf.cglib.proxy.Enhancer * @see AdvisedSupport#setProxyTargetClass * @see DefaultAopProxyFactory */ final class Cglib2AopProxy implements AopProxy, Serializable { // Constants for CGLIB callback array indices private static final int AOP_PROXY = 0; private static final int INVOKE_TARGET = 1; private static final int NO_OVERRIDE = 2; private static final int DISPATCH_TARGET = 3; private static final int DISPATCH_ADVISED = 4; private static final int INVOKE_EQUALS = 5; private static final int INVOKE_HASHCODE = 6; /** Logger available to subclasses; static to optimize serialization */ protected final static Log logger = LogFactory.getLog(Cglib2AopProxy.class); /** Keeps track of the Classes that we have validated for final methods */ private static final Map validatedClasses = new WeakHashMap(); /** The configuration used to configure this proxy */ protected final AdvisedSupport advised; private Object[] constructorArgs; private Class[] constructorArgTypes; /** Dispatcher used for methods on Advised */ private final transient AdvisedDispatcher advisedDispatcher; private transient Map fixedInterceptorMap; private transient int fixedInterceptorOffset; /** * Create a new Cglib2AopProxy for the given AOP configuration. * @param config the AOP configuration as AdvisedSupport object * @throws AopConfigException if the config is invalid. We try to throw an informative * exception in this case, rather than let a mysterious failure happen later. */ public Cglib2AopProxy(AdvisedSupport config) throws AopConfigException { Assert.notNull(config, "AdvisedSupport must not be null"); if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) { throw new AopConfigException("No advisors and no TargetSource specified"); } this.advised = config; this.advisedDispatcher = new AdvisedDispatcher(this.advised); } /** * Set constructor arguments to use for creating the proxy. * @param constructorArgs the constructor argument values * @param constructorArgTypes the constructor argument types */ public void setConstructorArguments(Object[] constructorArgs, Class[] constructorArgTypes) { if (constructorArgs == null || constructorArgTypes == null) { throw new IllegalArgumentException("Both 'constructorArgs' and 'constructorArgTypes' need to be specified"); } if (constructorArgs.length != constructorArgTypes.length) { throw new IllegalArgumentException("Number of 'constructorArgs' (" + constructorArgs.length + ") must match number of 'constructorArgTypes' (" + constructorArgTypes.length + ")"); } this.constructorArgs = constructorArgs; this.constructorArgTypes = constructorArgTypes; } public Object getProxy() { return getProxy(null); } public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating CGLIB2 proxy: target source is " + this.advised.getTargetSource()); } try { Class rootClass = this.advised.getTargetClass(); Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy"); Class proxySuperClass = rootClass; if (AopUtils.isCglibProxyClass(rootClass)) { proxySuperClass = rootClass.getSuperclass(); Class[] additionalInterfaces = rootClass.getInterfaces(); for (int i = 0; i < additionalInterfaces.length; i++) { Class additionalInterface = additionalInterfaces[i]; this.advised.addInterface(additionalInterface); } } // Validate the class, writing log messages as necessary. validateClassIfNecessary(proxySuperClass); // Configure CGLIB Enhancer... Enhancer enhancer = createEnhancer(); if (classLoader != null) { enhancer.setClassLoader(classLoader); if (classLoader instanceof SmartClassLoader && ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { enhancer.setUseCache(false); } } enhancer.setSuperclass(proxySuperClass); enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class)); enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setInterceptDuringConstruction(false); Callback[] callbacks = getCallbacks(rootClass); enhancer.setCallbacks(callbacks); enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); Class[] types = new Class[callbacks.length]; for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } enhancer.setCallbackTypes(types); // Generate the proxy class and create a proxy instance. Object proxy; if (this.constructorArgs != null) { proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs); } else { proxy = enhancer.create(); } return proxy; } catch (CodeGenerationException ex) { throw new AopConfigException("Could not generate CGLIB subclass of class [" + this.advised.getTargetClass() + "]: " + "Common causes of this problem include using a final class or a non-visible class", ex); } catch (IllegalArgumentException ex) { throw new AopConfigException("Could not generate CGLIB subclass of class [" + this.advised.getTargetClass() + "]: " + "Common causes of this problem include using a final class or a non-visible class", ex); } catch (Exception ex) { // TargetSource.getTarget() failed throw new AopConfigException("Unexpected AOP exception", ex); } } /** * Creates the CGLIB {@link Enhancer}. Subclasses may wish to override this to return a custom * {@link Enhancer} implementation. */ protected Enhancer createEnhancer() { return new Enhancer(); } /** * Checks to see whether the supplied <code>Class</code> has already been validated and * validates it if not. */ private void validateClassIfNecessary(Class proxySuperClass) { if (logger.isWarnEnabled()) { synchronized (validatedClasses) { if (!validatedClasses.containsKey(proxySuperClass)) { doValidateClass(proxySuperClass); validatedClasses.put(proxySuperClass, Boolean.TRUE); } } } } /** * Checks for final methods on the <code>Class</code> and writes warnings to the log * for each one found. */ private void doValidateClass(Class proxySuperClass) { Method[] methods = proxySuperClass.getMethods(); for (int i = 0; i < methods.length; i++) { Method method = methods[i]; if (!Object.class.equals(method.getDeclaringClass()) && Modifier.isFinal(method.getModifiers())) { logger.warn("Unable to proxy method [" + method + "] because it is final: " + "All calls to this method via a proxy will be routed directly to the proxy."); } } } private Callback[] getCallbacks(Class rootClass) throws Exception { // Parameters used for optimisation choices... boolean exposeProxy = this.advised.isExposeProxy(); boolean isFrozen = this.advised.isFrozen(); boolean isStatic = this.advised.getTargetSource().isStatic(); // Choose an "aop" interceptor (used for AOP calls). Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised); // Choose a "straight to target" interceptor. (used for calls that are // unadvised but can return this). May be required to expose the proxy. Callback targetInterceptor = null; if (exposeProxy) { targetInterceptor = isStatic ? (Callback) new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) : (Callback) new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()); } else { targetInterceptor = isStatic ? (Callback) new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) : (Callback) new DynamicUnadvisedInterceptor(this.advised.getTargetSource()); } // Choose a "direct to target" dispatcher (used for // unadvised calls to static targets that cannot return this). Callback targetDispatcher = isStatic ? (Callback) new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp(); Callback[] mainCallbacks = new Callback[]{ aopInterceptor, // for normal advice targetInterceptor, // invoke target without considering advice, if optimized new SerializableNoOp(), // no override for methods mapped to this targetDispatcher, this.advisedDispatcher, new EqualsInterceptor(this.advised), new HashCodeInterceptor(this.advised) }; Callback[] callbacks; // If the target is a static one and the advice chain is frozen, // then we can make some optimisations by sending the AOP calls // direct to the target using the fixed chain for that method. if (isStatic && isFrozen) { Method[] methods = rootClass.getMethods(); Callback[] fixedCallbacks = new Callback[methods.length]; this.fixedInterceptorMap = new HashMap(methods.length); // TODO: small memory optimisation here (can skip creation for // methods with no advice) for (int x = 0; x < methods.length; x++) { List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass); fixedCallbacks[x] = new FixedChainStaticTargetInterceptor( chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass()); this.fixedInterceptorMap.put(methods[x].toString(), new Integer(x)); } // Now copy both the callbacks from mainCallbacks // and fixedCallbacks into the callbacks array. callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length]; for (int x = 0; x < mainCallbacks.length; x++) { callbacks[x] = mainCallbacks[x]; } for (int x = 0; x < fixedCallbacks.length; x++) { callbacks[x + mainCallbacks.length] = fixedCallbacks[x]; } this.fixedInterceptorOffset = mainCallbacks.length; } else { callbacks = mainCallbacks; } return callbacks; } /** * Wrap a return of this if necessary to be the proxy */ private static Object massageReturnTypeIfNecessary(Object proxy, Object target, Method method, Object retVal) { // Massage return value if necessary if (retVal != null && retVal == target && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { // Special case: it returned "this". // Note that we can't help if the target sets a reference // to itself in another returned object. retVal = proxy; } return retVal; } public boolean equals(Object other) { return (this == other || (other instanceof Cglib2AopProxy && AopProxyUtils.equalsInProxy(this.advised, ((Cglib2AopProxy) other).advised))); } public int hashCode() { return Cglib2AopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode(); } /** * Serializable replacement for CGLIB's NoOp interface. * Public to allow use elsewhere in the framework. */ public static class SerializableNoOp implements NoOp, Serializable { } /** * Method interceptor used for static targets with no advice chain. The call * is passed directly back to the target. Used when the proxy needs to be * exposed and it can't be determined that the method won't return * <code>this</code>. */ private static class StaticUnadvisedInterceptor implements MethodInterceptor, Serializable { private final Object target; public StaticUnadvisedInterceptor(Object target) { this.target = target; } public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object retVal = methodProxy.invoke(this.target, args); return massageReturnTypeIfNecessary(proxy, this.target, method, retVal); } } /** * Method interceptor used for static targets with no advice chain, when the * proxy is to be exposed. */ private static class StaticUnadvisedExposedInterceptor implements MethodInterceptor, Serializable { private final Object target; public StaticUnadvisedExposedInterceptor(Object target) { this.target = target; } public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; try { oldProxy = AopContext.setCurrentProxy(proxy); Object retVal = methodProxy.invoke(this.target, args); return massageReturnTypeIfNecessary(proxy, this.target, method, retVal); } finally { AopContext.setCurrentProxy(oldProxy); } } } /** * Interceptor used to invoke a dynamic target without creating a method * invocation or evaluating an advice chain. (We know there was no advice * for this method.) */ private static class DynamicUnadvisedInterceptor implements MethodInterceptor, Serializable { private final TargetSource targetSource; public DynamicUnadvisedInterceptor(TargetSource targetSource) { this.targetSource = targetSource; } public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object target = this.targetSource.getTarget(); try { Object retVal = methodProxy.invoke(target, args); return massageReturnTypeIfNecessary(proxy, target, method, retVal); } finally { this.targetSource.releaseTarget(target); } } } /** * Interceptor for unadvised dynamic targets when the proxy needs exposing. */ private static class DynamicUnadvisedExposedInterceptor implements MethodInterceptor, Serializable { private final TargetSource targetSource; public DynamicUnadvisedExposedInterceptor(TargetSource targetSource) { this.targetSource = targetSource; } public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; Object target = this.targetSource.getTarget(); try { oldProxy = AopContext.setCurrentProxy(proxy); Object retVal = methodProxy.invoke(target, args); return massageReturnTypeIfNecessary(proxy, target, method, retVal); } finally { AopContext.setCurrentProxy(oldProxy); this.targetSource.releaseTarget(target); } } } /** * Dispatcher for a static target. Dispatcher is much faster than * interceptor. This will be used whenever it can be determined that a * method definitely does not return "this" */ private static class StaticDispatcher implements Dispatcher, Serializable { private Object target; public StaticDispatcher(Object target) { this.target = target; } public Object loadObject() { return this.target; } } /** * Dispatcher for any methods declared on the Advised class. */ private static class AdvisedDispatcher implements Dispatcher, Serializable { private final AdvisedSupport advised; public AdvisedDispatcher(AdvisedSupport advised) { this.advised = advised; } public Object loadObject() throws Exception { return this.advised; } } /** * Dispatcher for the <code>equals</code> method. * Ensures that the method call is always handled by this class. */ private static class EqualsInterceptor implements MethodInterceptor, Serializable { private final AdvisedSupport advised; public EqualsInterceptor(AdvisedSupport advised) { this.advised = advised; } public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) { Object other = args[0]; if (proxy == other) { return Boolean.TRUE; } AdvisedSupport otherAdvised = null; if (other instanceof Factory) { Callback callback = ((Factory) other).getCallback(INVOKE_EQUALS); if (!(callback instanceof EqualsInterceptor)) { return Boolean.FALSE; } otherAdvised = ((EqualsInterceptor) callback).advised; } else { return Boolean.FALSE; } return (AopProxyUtils.equalsInProxy(this.advised, otherAdvised) ? Boolean.TRUE : Boolean.FALSE); } } /** * Dispatcher for the <code>hashCode</code> method. * Ensures that the method call is always handled by this class. */ private static class HashCodeInterceptor implements MethodInterceptor, Serializable { private final AdvisedSupport advised; public HashCodeInterceptor(AdvisedSupport advised) { this.advised = advised; } public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) { return new Integer(Cglib2AopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode()); } } /** * Interceptor used specifically 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, Class targetClass) { this.adviceChain = adviceChain; this.target = target; this.targetClass = targetClass; } public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object retVal = null; MethodInvocation invocation = new CglibMethodInvocation(proxy, this.target, method, args, this.targetClass, this.adviceChain, methodProxy); // If we get here, we need to create a MethodInvocation. retVal = invocation.proceed(); retVal = massageReturnTypeIfNecessary(proxy, this.target, method, retVal); return retVal; } } /** * General purpose AOP callback. Used when the target is dynamic or when the * proxy is not frozen. */ private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable { private AdvisedSupport advised; public DynamicAdvisedInterceptor(AdvisedSupport advised) { this.advised = advised; } 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; Object target = null; try { Object retVal = null; if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // May be <code>null</code>. 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(); } List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // Check whether we only have one InvokerInterceptor: that is, // no real advice, but just reflective invocation of the target. if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { // 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 CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy); // If we get here, we need to create a MethodInvocation. retVal = invocation.proceed(); } retVal = massageReturnTypeIfNecessary(proxy, target, method, retVal); return retVal; } finally { if (target != null) { releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } } public boolean equals(Object other) { return (this == other || (other instanceof DynamicAdvisedInterceptor && this.advised.equals(((DynamicAdvisedInterceptor) other).advised))); } /** * CGLIB uses this to drive proxy creation. */ public int hashCode() { return this.advised.hashCode(); } protected Object getTarget() throws Exception { return this.advised.getTargetSource().getTarget(); } protected void releaseTarget(Object target) throws Exception { this.advised.getTargetSource().releaseTarget(target); } } /** * Implementation of AOP Alliance MethodInvocation used by this AOP proxy. */ private static class CglibMethodInvocation extends ReflectiveMethodInvocation { private final MethodProxy methodProxy; private boolean protectedMethod; public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments, Class targetClass, List interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) { super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers); this.methodProxy = methodProxy; this.protectedMethod = Modifier.isProtected(method.getModifiers()); } /** * Gives a marginal performance improvement versus using reflection to * invoke the target when invoking public methods. */ protected Object invokeJoinpoint() throws Throwable { if (this.protectedMethod) { return super.invokeJoinpoint(); } else { return this.methodProxy.invoke(this.target, this.arguments); } } } /** * CallbackFilter to assign Callbacks to methods. */ private static class ProxyCallbackFilter implements CallbackFilter { private final AdvisedSupport advised; private final Map fixedInterceptorMap; private final int fixedInterceptorOffset; public ProxyCallbackFilter(AdvisedSupport advised, Map fixedInterceptorMap, int fixedInterceptorOffset) { this.advised = advised; this.fixedInterceptorMap = fixedInterceptorMap; this.fixedInterceptorOffset = fixedInterceptorOffset; } /** * 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 <code>ProxyFactory.getExposeProxy()</code> returns <code>false</code>, * 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> */ public int accept(Method method) { if (AopUtils.isFinalizeMethod(method)) { logger.debug("Found finalize() method - using NO_OVERRIDE"); return NO_OVERRIDE; } if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { if (logger.isDebugEnabled()) { logger.debug("Method is declared on Advised interface: " + method); } return DISPATCH_ADVISED; } // We must always proxy equals, to direct calls to this. if (AopUtils.isEqualsMethod(method)) { logger.debug("Found 'equals' method: " + method); return INVOKE_EQUALS; } // We must always calculate hashCode based on the proxy. if (AopUtils.isHashCodeMethod(method)) { logger.debug("Found 'hashCode' method: " + method); return INVOKE_HASHCODE; } Class targetClass = this.advised.getTargetClass(); // Proxy is not yet available, but that shouldn't matter. List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); boolean haveAdvice = !chain.isEmpty(); boolean exposeProxy = this.advised.isExposeProxy(); boolean isStatic = this.advised.getTargetSource().isStatic(); boolean isFrozen = this.advised.isFrozen(); if (haveAdvice || !isFrozen) { // If exposing the proxy, then AOP_PROXY must be used. if (exposeProxy) { if (logger.isDebugEnabled()) { logger.debug("Must expose proxy on advised method: " + method); } 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 && this.fixedInterceptorMap.containsKey(key)) { if (logger.isDebugEnabled()) { logger.debug("Method has advice and optimisations are enabled: " + method); } // We know that we are optimising so we can use the // FixedStaticChainInterceptors. int index = ((Integer) this.fixedInterceptorMap.get(key)).intValue(); return (index + this.fixedInterceptorOffset); } else { if (logger.isDebugEnabled()) { logger.debug("Unable to apply any optimisations to advised method: " + method); } 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 // massage and can use a dispatcher. // If the proxy is being exposed, then must use the interceptor the // correct one is already configured. 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.isDebugEnabled()) { logger.debug("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.isDebugEnabled()) { logger.debug("Method " + method + " has return type that ensures this cannot be returned- using DISPATCH_TARGET"); } return DISPATCH_TARGET; } else { if (logger.isDebugEnabled()) { logger.debug("Method " + method + "has return type that is assignable from the target type (may return this) - " + "using INVOKE_TARGET"); } return INVOKE_TARGET; } } } public boolean equals(Object other) { if (other == this) { return true; } if (!(other instanceof ProxyCallbackFilter)) { return false; } ProxyCallbackFilter otherCallbackFilter = (ProxyCallbackFilter) other; AdvisedSupport otherAdvised = otherCallbackFilter.advised; if (this.advised == null || otherAdvised == null) { return false; } if (this.advised.isFrozen() != otherAdvised.isFrozen()) { return false; } if (this.advised.isExposeProxy() != otherAdvised.isExposeProxy()) { return false; } if (this.advised.getTargetSource().isStatic() != otherAdvised.getTargetSource().isStatic()) { return false; } if (!AopProxyUtils.equalsProxiedInterfaces(this.advised, otherAdvised)) { return false; } // Advice instance identity is unimportant to the proxy class: // All that matters is type and ordering. Advisor[] thisAdvisors = this.advised.getAdvisors(); Advisor[] thatAdvisors = otherAdvised.getAdvisors(); if (thisAdvisors.length != thatAdvisors.length) { return false; } for (int i = 0; i < thisAdvisors.length; i++) { Advisor thisAdvisor = thisAdvisors[i]; Advisor thatAdvisor = thatAdvisors[i]; if (!equalsAdviceClasses(thisAdvisor, thatAdvisor)) { return false; } if (!equalsPointcuts(thisAdvisor, thatAdvisor)) { return false; } } return true; } private boolean equalsAdviceClasses(Advisor a, Advisor b) { Advice aa = a.getAdvice(); Advice ba = b.getAdvice(); if (aa == null || ba == null) { return (aa == ba); } return aa.getClass().equals(ba.getClass()); } private boolean equalsPointcuts(Advisor a, Advisor b) { // If only one of the advisor (but not both) is PointcutAdvisor, then it is a mismatch. // Takes care of the situations where an IntroductionAdvisor is used (see SPR-3959). if (a instanceof PointcutAdvisor ^ b instanceof PointcutAdvisor) { return false; } // If both are PointcutAdvisor, match their pointcuts. if (a instanceof PointcutAdvisor && b instanceof PointcutAdvisor) { return ObjectUtils.nullSafeEquals(((PointcutAdvisor) a).getPointcut(), ((PointcutAdvisor) b).getPointcut()); } // If neither is PointcutAdvisor, then from the pointcut matching perspective, it is a match. return true; } public int hashCode() { int hashCode = 0; Advisor[] advisors = this.advised.getAdvisors(); for (int i = 0; i < advisors.length; i++) { Advice advice = advisors[i].getAdvice(); if (advice != null) { hashCode = 13 * hashCode + advice.getClass().hashCode(); } } hashCode = 13 * hashCode + (this.advised.isFrozen() ? 1 : 0); hashCode = 13 * hashCode + (this.advised.isExposeProxy() ? 1 : 0); hashCode = 13 * hashCode + (this.advised.isOptimize() ? 1 : 0); hashCode = 13 * hashCode + (this.advised.isOpaque() ? 1 : 0); return hashCode; } } }
我已经将结果分析出来。
如果你有相同的问题,请读下面的文章。
http://netfork.iteye.com/blog/286215
发表评论
文章已被作者锁定,不允许评论。
相关推荐
为了在不改变原代码的情况下增加日志记录功能,我们创建了一个名为HelloProxy的代理类,该代理类也实现了IHello接口。代理类中的sayHello()方法会在调用原Hello类的sayHello()方法之前和之后分别调用Logger类进行...
写了基于C#使用Spring.Net的演示实例,希望能给有需要的人带来帮助,其中演示了配置下的IOC、AOP、属性注入、构造函数注入、通知过滤器、以及不使用配置直接代码硬编的AOP动态代码过程,另外还增加了Castle实现IOC及...
- 创建代理对象时,Spring使用`java.lang.reflect.Proxy`类的静态方法`newProxyInstance()`,传入目标对象的类加载器、接口数组以及InvocationHandler实现,后者处理实际的调用逻辑。 2. **CGLIB代理**: - 如果...
Unity支持这种注入方式,只需在接口的实现中使用构造函数或属性注入。 此外,AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,它允许开发者在不修改源代码的情况下,添加新的行为或关注点。Unity...
写了基于C#使用Spring.Net的演示实例,希望能给有需要的人带来帮助,其中演示了配置下的IOC、AOP、属性注入、构造函数注入、通知过滤器、以及不使用配置直接代码硬编的AOP动态代码过程,另外还增加了Castle实现IOC及...
C#作为一种强大的.NET开发语言,虽然原生并不支持AOP,但可以通过一些第三方库来实现,如我们这里提到的`Mono.Cecil`。 `Mono.Cecil`是一个强大的.NET元数据操作库,它允许开发者在运行时动态地读取、修改并保存IL...
在Spring框架中,DI主要通过构造器注入、setter方法注入和接口注入三种方式实现。 1. **构造器注入**:通过在类的构造器中传入依赖对象来实现。Spring会根据构造器参数类型找到合适的bean并注入。 ```java public ...
在软件开发中,Unity是一个流行的依赖注入容器,它主要用于.NET应用程序,尤其是对于Unity游戏引擎的开发者来说,这个框架可以帮助他们更好地管理和组织代码。另一方面,面向切面编程(AOP)是一种设计模式,允许...
在Spring AOP中,`Proxy`类会根据目标对象的接口生成一个代理类,这个代理类会实现目标对象的所有接口,并在每个方法调用前后插入相应的通知。`InvocationHandler`接口定义了一个`invoke`方法,当调用代理对象的方法...
4. **创建代理**:使用`java.lang.reflect.Proxy.newProxyInstance()`方法,传入目标对象的类加载器、目标对象实现的接口列表以及我们的InvocationHandler实例,生成代理对象。 5. **注册到Bean工厂**:将代理对象...
springboot+拦截器+aop+自定义注解+本地线程实现统一接口日志记录,记录下接口所在模块、接口描述、接口请求参数、接口返回参数、接口请求时间以及接口耗时用于接口优化,接口记录参数以及操作人防止使用人员误操作...
在运行时,JDK动态代理会创建一个新的类,该类实现目标对象的所有接口,并在方法调用时插入自定义的行为(通知)。Spring的`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口是实现JDK动态...
- CGLIB代理:如果目标对象没有实现接口,或者我们希望为类创建代理,Spring会使用CGLIB库生成一个子类来实现AOP代理。CGLIB代理在运行时通过字节码技术生成目标类的子类,并在子类的方法上插入切面逻辑。 3. AOP...
- 如果目标对象实现了接口,Spring将使用JDK的`java.lang.reflect.Proxy`类来创建代理,这样就可以在不修改原有代码的情况下,为对象添加额外的行为。 2. **CGLIB代理**: - 对于没有实现接口的对象,Spring会...
6. **代理模式的其他实现**:除了Java的动态代理,还有其他实现方式,比如CGLIB库,它通过字节码生成技术创建代理对象,即使目标类没有实现接口也能进行代理。 学习AOP动态代理有助于我们理解面向切面编程的核心...
使用动态代理实现AOP需要有四个角色:被代理的类,被代理类的接口,织入器,和InvocationHandler,而织入器使用接口反射机制生成一个代理类,然后在这个代理类中织入代码。被代理的类是AOP里所说的目标,...
在Java中,动态代理可以用来实现AOP,通过 InvocationHandler接口提供一个执行处理器,然后通过Proxy类获取一个代理对象,通过这个代理对象来执行商业方法。在商业方法被调用时,执行处理器会被自动调用,从而实现了...
2. **CGLIB动态代理**:如果目标类没有实现接口,Spring会使用CGLIB库创建一个目标类的子类,子类覆盖目标类的方法并在方法调用前后插入通知。CGLIB代理提供了更广泛的应用场景,但相比JDK动态代理,它的性能稍差。 ...