Night light brings you into the new field of SSM framework

Keywords: Spring JDK Programming

Preface to the night light:

Cherry trees can't keep the pace of March. ~ ~

 

Text: AOP

 

The underlying principle of aspect oriented programming is dynamic agent implementation. If there is interface implementation for the aspect strategy, the dynamic proxy technology of JDK is used; if there is no interface implementation, CGLIB technology is used to generate the dynamic proxy.

In the business environment, the interface usage is very high. This paper mainly analyzes how Spring uses JDK's dynamic proxy technology to generate dynamic proxy objects. The main code is in the classes of JdkDynamicAopProxy, AdvisedSupport, DefaultAdvisorChainFactory and ReflectiveMethodInvocation

2.1JdkDynamicAopProxy.invoke();

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
// Gets the target source object in the proxy object. Equivalent to a Service implementation class.
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// The purpose of judgment logic is to avoid RuntimeException in the execution of proxy object
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface()
&&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method,
args);
}
Object retVal; // return value, which defines a reference to the returned result data.
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool. Class object of target object
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the perception chain for this method
//Before and after, cut into the interceptor chain. Methods of concern
List<Object> chain =
this.advised.getInterceptorsAndDynamicInterceptionAdvice(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 (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.
// If the proxy object does not have an interceptor to cut people, the methods in the target object are executed.
Object[] argsToUse =
AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method,
argsToUse);
}
else {
// We need to create a method invocation...
// Create an actuator, add interception information, and execute interception code and objectives in order
//Mark the method in the object.
invocation = new ReflectiveMethodInvocation(proxy, target, method,
args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// Method execution. The methods in the intercepting code and the target object are executed in sequence. Concerned party
//method
retVal = invocation.proceed();
}
// Obtain the return result class of the method in the target object
//Type.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// 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 != Void.TYPE &&
returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return
type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}

2.2AdvisedSupport.
getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method,
@Nullable Class<?> targetClass) {
// Method to get the cache in the spring container.
MethodCacheKey cacheKey = new MethodCacheKey(method);
// Get method cache matching information from a known cache.
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
// Query the interception information that the agent object needs to execute. Focus on methods.
cached =
this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
// Save the cached data and provide the cached content for other subsequent codes.
this.methodCache.put(cacheKey, cached);
}
return cached;
}

2.3DefaultAdvisorChainFactory.
getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process sintroduction first,
// but we need to preserve order in the ultimate list.
List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass :
method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
// Notify the Registrar. The spring container uses the Registrar to manage all configured notifications.
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
// Get notification objects from configuration information.
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() ||
pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm =
pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass,
hasIntroductions)) {
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors()
method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new
InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}

 

 

 

 

 

 

 

 

 

 

Posted by JustFoo on Fri, 06 Dec 2019 10:47:12 -0800