1. Design principle
When generating proxy objects through JDK's Proxy or CGLIB mode, the relevant interceptors have been configured into the proxy object;
Callback via interceptor
JDK dynamic proxy: The proxy class and the target class implement a common interface, usingInvocationHandler
interface. (See the code below)
CGLIB Dynamic Proxy: The proxy class is a subclass of the target class, and it is usedMethodInterceptor
interface. (See the code below)
jdk dynamic proxy is implemented by the reflection mechanism inside Java;
The underlying layer of cglib dynamic proxy is implemented with the help of asm.
jdk (Proxy)
Using Proxy
newProxyInstance()
Method to create proxy objects
final UserService target=new UserServiceImpl(); Class<UserService> clazz = ; ClassLoader loader = (); Object proxyInstance = (loader, new Class[]{clazz}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { ("Before..."); Object result = (target, args); ("After..."); return result; } }); UserService service = (UserService) proxyInstance; ();
cglib
Dynamic class object
Enhancer
, it is the core class of CGLIB; the Enhancer classsetSuperclass()
Method to determine the target object;setCallback()
Methods add callback function. Finally, the created proxy class object is returned through the return statement. The intercept() method is called when the program executes the target method, and the enhanced methods (before and after) in the facet class are executed when the method is running.
Enhancer enhancer=new Enhancer(); (); (new Callback[]{new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { ("Before..."); Object result = (o, objects); ("After..."); return result; } }}); UserInfo userInfo = (UserInfo) (); ();
(Spring-Core)
Before generating the proxy object, ProxyFactory needs to decide whether to use JDK dynamic proxy or CGLIB technology;
getProxy()
returnCglibAopProxy
orJdkDynamicAopProxy
UserService target=new UserServiceImpl(); ProxyFactory proxyFactory=new ProxyFactory(); (target); //addAdvice() adds multiple to automatically form a chain of responsibility (new AopMethodAroundAdvice()); (new AopMethodBeforeAdvice()); (new AopMethodAfterAdvice()); (new AopMethodThrowsAdvice()); //Advisor settings specific pointCut and advice// (new AopPointcutAdvisor()); UserService userService = (UserService) (); (); ();
public Object getProxy() { return createAopProxy().getProxy(); }
2.1 JdkDynamicAopProxy
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { @Override public Object getProxy() { return getProxy(()); } @Override public Object getProxy(@Nullable ClassLoader classLoader) { if (()) { ("Creating JDK dynamic proxy: " + ()); } return (classLoader, , this); } @Override @Nullable public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { ...Omitted... Object retVal; if () { // Make invocation available if necessary. oldProxy = (proxy); setProxyContext = true; } // Get as late as possible to minimize the time we "own" the target, // in case it comes from a pool. target = (); Class<?> targetClass = (target != null ? () : null); //Focus: Get the intercepting chain of this method List<Object> chain = (method, targetClass); // Check whether we have any advice. If we don't, we can fallback on direct // reflective invocation of the target, and avoid creating a MethodInvocation. if (()) { // 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. Object[] argsToUse = (method, args); retVal = (target, method, argsToUse); } else { // We need to create a method invocation... MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. retVal = (); } // Massage return value if necessary. Class<?> returnType = (); if (retVal != null && retVal == target && returnType != && (proxy) && !(())) { // Special case: it returned "this" and the return type of the method // is type-compatible. Note that we can't help if the target sets // a reference to itself in another returned object. retVal = proxy; } else if (retVal == null && returnType != && ()) { throw new AopInvocationException( "Null return value from advice does not match primitive return type for: " + method); } return retVal; } finally { if (target != null && !()) { // Must have come from TargetSource. (target); } if (setProxyContext) { // Restore old proxy. (oldProxy); } } }
2.2 CglibAopProxy
class CglibAopProxy implements AopProxy, Serializable { @Override public Object getProxy() { return getProxy(null); } @Override public Object getProxy(@Nullable ClassLoader classLoader) { if (()) { ("Creating CGLIB proxy: " + ()); } try { Class<?> rootClass = (); (rootClass != null, "Target class must be available for creating a CGLIB proxy"); Class<?> proxySuperClass = rootClass; if (().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) { proxySuperClass = (); Class<?>[] additionalInterfaces = (); for (Class<?> additionalInterface : additionalInterfaces) { (additionalInterface); } } // Validate the class, writing log messages as necessary. validateClassIfNecessary(proxySuperClass, classLoader); // Configure CGLIB Enhancer... Enhancer enhancer = createEnhancer(); if (classLoader != null) { (classLoader); if (classLoader instanceof SmartClassLoader && ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { (false); } } (proxySuperClass); (()); (); (new ClassLoaderAwareGeneratorStrategy(classLoader)); //Focus: Setting Callbacks[] Callback[] callbacks = getCallbacks(rootClass); Class<?>[] types = new Class<?>[]; for (int x = 0; x < ; x++) { types[x] = callbacks[x].getClass(); } // fixedInterceptorMap only populated at this point, after getCallbacks call above (new ProxyCallbackFilter( (), , )); (types); // Generate the proxy class and create a proxy instance. return createProxyClassAndInstance(enhancer, callbacks); } catch (CodeGenerationException | IllegalArgumentException ex) { throw new AopConfigException("Could not generate CGLIB subclass of " + () + ": Common causes of this problem include using a final class or a non-visible class", ex); } catch (Throwable ex) { // () failed throw new AopConfigException("Unexpected AOP exception", ex); } } //Get Callbacks[] private Callback[] getCallbacks(Class<?> rootClass) throws Exception { // Parameters used for optimization choices... boolean exposeProxy = (); boolean isFrozen = (); boolean isStatic = ().isStatic(); // Choose an "aop" interceptor (used for AOP calls). (Important class) Callback aopInterceptor = new DynamicAdvisedInterceptor(); // 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; if (exposeProxy) { targetInterceptor = (isStatic ? new StaticUnadvisedExposedInterceptor(().getTarget()) : new DynamicUnadvisedExposedInterceptor(())); } else { targetInterceptor = (isStatic ? new StaticUnadvisedInterceptor(().getTarget()) : new DynamicUnadvisedInterceptor(())); } // Choose a "direct to target" dispatcher (used for // unadvised calls to static targets that cannot return this). Callback targetDispatcher = (isStatic ? new StaticDispatcher(().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, , new EqualsInterceptor(), new HashCodeInterceptor() }; Callback[] callbacks; ...Omitted... return callbacks; }
DynamicAdvisedInterceptor
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable { private final AdvisedSupport advised; public DynamicAdvisedInterceptor(AdvisedSupport advised) { = advised; } @Override @Nullable public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Object target = null; TargetSource targetSource = (); try { if () { // Make invocation available if necessary. oldProxy = (proxy); setProxyContext = true; } // Get as late as possible to minimize the time we "own" the target, in case it comes from a pool... target = (); Class<?> targetClass = (target != null ? () : null); //Focus: Get the intercepting chain of this method List<Object> chain = (method, targetClass); Object retVal; // Check whether we only have one InvokerInterceptor: that is, // no real advice, but just reflective invocation of the target. if (() && (())) { // 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. Object[] argsToUse = (method, args); retVal = (target, argsToUse); } else { // We need to create a method invocation... retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } retVal = processReturnType(proxy, target, method, retVal); return retVal; } finally { if (target != null && !()) { (target); } if (setProxyContext) { // Restore old proxy. (oldProxy); } } } }
2.3 Main source code part
public class AdvisedSupport extends ProxyConfig implements Advised { public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) { MethodCacheKey cacheKey = new MethodCacheKey(method); List<Object> cached = (cacheKey); if (cached == null) { cached = ( this, method, targetClass); (cacheKey, cached); } return cached; }
DefaultAdvisorChainFactory
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable { @Override public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, @Nullable Class<?> targetClass) { // This is somewhat tricky... We have to process introductions first, // but we need to preserve order in the ultimate list. AdvisorAdapterRegistry registry = (); Advisor[] advisors = (); List<Object> interceptorList = new ArrayList<>(); Class<?> actualClass = (targetClass != null ? targetClass : ()); Boolean hasIntroductions = null; for (Advisor advisor : advisors) { if (advisor instanceof PointcutAdvisor) { // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (() || ().getClassFilter().matches(actualClass)) { MethodMatcher mm = ().getMethodMatcher(); boolean match; if (mm instanceof IntroductionAwareMethodMatcher) { if (hasIntroductions == null) { hasIntroductions = hasMatchingIntroductions(advisors, actualClass); } match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions); } else { match = (method, actualClass); } if (match) { //Point: Convert the advice in the advisor to the MethodInterceptor. MethodInterceptor[] interceptors = (advisor); if (()) { // Creating a new object instance in the getInterceptors() method // isn't a problem as we normally cache created chains. for (MethodInterceptor interceptor : interceptors) { (new InterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { ((interceptors)); } } } } else if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (() || ().matches(actualClass)) { Interceptor[] interceptors = (advisor); ((interceptors)); } } else { Interceptor[] interceptors = (advisor); ((interceptors)); } } return interceptorList; }
DefaultAdvisorAdapterRegistry
The constructor method has been registered
MethodBeforeAdviceAdapter
、AfterReturningAdviceAdapter
、ThrowsAdviceAdapter
3 Adapter templates
Convert the total advisor advice to MethodInterceptor through the getInterceptor advisor advisor method
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable { private final List<AdvisorAdapter> adapters = new ArrayList<>(3); /** * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters. */ public DefaultAdvisorAdapterRegistry() { registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); registerAdvisorAdapter(new AfterReturningAdviceAdapter()); registerAdvisorAdapter(new ThrowsAdviceAdapter()); } ...Omitted... @Override public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List<MethodInterceptor> interceptors = new ArrayList<>(3); Advice advice = (); if (advice instanceof MethodInterceptor) { ((MethodInterceptor) advice); } for (AdvisorAdapter adapter : ) { if ((advice)) { ((advisor)); } } if (()) { throw new UnknownAdviceTypeException(()); } return (new MethodInterceptor[0]); } @Override public void registerAdvisorAdapter(AdvisorAdapter adapter) { (adapter); } }
1.
AfterReturningAdviceAdapter
passgetInterceptor
Method GetAfterReturningAdviceInterceptor
Filter
2.AfterReturningAdviceInterceptor
invoke()
Method: First execute the target method, then execute (post-set) advice method
class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable { @Override public boolean supportsAdvice(Advice advice) { return (advice instanceof AfterReturningAdvice); } @Override public MethodInterceptor getInterceptor(Advisor advisor) { AfterReturningAdvice advice = (AfterReturningAdvice) (); return new AfterReturningAdviceInterceptor(advice); } } public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable { private final AfterReturningAdvice advice; /** * Create a new AfterReturningAdviceInterceptor for the given advice. * @param advice the AfterReturningAdvice to wrap */ public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) { (advice, "Advice must not be null"); = advice; } @Override @Nullable public Object invoke(MethodInvocation mi) throws Throwable { Object retVal = (); (retVal, (), (), ()); return retVal; } }
This is all about this article about Spring Core dynamic proxy. For more relevant Spring Core dynamic proxy content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!