📄 cglib2aopproxy.java
字号:
/**
* 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 + -