In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/02 Report--
This article is to share with you about how to call proxy object embedding in Springboot. The editor thinks it is very practical, so I share it with you. I hope you can get something after reading this article.
@ Async and @ Transactional coexist @ Component public class AsyncWithTransactional {@ Async @ Transactional public void test () {}}
What happens to a piece of code like this? People who are familiar with it will feel confused. Is it effective? Who is enhanced by the agent first?
The automatic proxy creator AbstractAutoProxyCreator is actually a BeanPostProcessor, so the order in which they are executed is very important.
Both inherit from ProxyProcessorSupport so they can create proxies and implement the Ordered interface---AsyncAnnotationBeanPostProcessor default order value is Ordered.LOWEST_PRECEDENCE. However, you can change this value by specifying the order property with @ EnableAsync.
AsyncAnnotationBeanPostProcessor has this logic when creating a proxy: if you are already an Advised object, you just need to add the @ Async enhancer to it. If it is not a proxy object, it will be created by itself.
Public abstract class AbstractAdvisingBeanPostProcessor extends ProxyProcessorSupport implements BeanPostProcessor {@ Override public Object postProcessAfterInitialization (Object bean, String beanName) {if (bean instanceof Advised) {advised.addAdvisor (this.advisor); return bean } / / there is no return above, so we will continue to judge ourselves to create an agent ~}}.
The default value of AbstractAutoProxyCreator is the same as above. But there is a line when adding the automatic proxy creator to the container: beanDefinition.getPropertyValues (). Add ("order", Ordered.HIGHEST_PRECEDENCE); automatic proxy creator, this processor is the highest priority.
As can be seen from the above, because @ Transactional is marked, the automatic agent takes effect, so it will first give AbstractAutoProxyCreator to generate the proxy object, and then to the later processor to execute. Because AsyncAnnotationBeanPostProcessor executes first, Bean is already a proxy object at this time when AsyncAnnotationBeanPostProcessor executes. At this time, it will continue to use this proxy, just add the section.
Method call order influence
We all know that similar method calls are enhanced only when entry methods are proxied. This is because the source code level only deals with entry method calls, and if it is you, you also design it, otherwise the method stack is so deep. Can you control that much? Now that we know the reason, let's take a look at the following column.
Follow the proxy object java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to' true' to make it available. At org.springframework.aop.framework.AopContext.currentProxy (AopContext.java:69) at com.fsx.dependency.B.funTemp (B.java:14) at sun.reflect.NativeMethodAccessorImpl.invoke0 (NativeMethod) at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke (Method At org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection (AopUtils.java:343) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke (JdkDynamicAopProxy.java:206) at com.sun.proxy.$Proxy44.funTemp (Unknown Source).
This exception is most likely to occur in the above situations, but the solution is @ EnableAspectJAutoProxy (exposeProxy = true)
Why, can we get the proxy object from the container? Yes, getting a proxy object from a container is also a way to use a proxy object to invoke a method chain, but can you use it? Writing code depending on the specific implementation of the agent will result in poor portability.
Reveal @ EnableAspectJAutoProxy (exposeProxy = true)
Spring built-in classes are also processing classes for proxy classes: CglibAopProxy and JdkDynamicAopProxy are very similar in handling this logic. Therefore, we can only use JdkDynamicAopProxy as the representative here.
We know that when executing the target method of the proxy object, it will be handed over to InvocationHandler, so the thing to do is in the invoke () method:
Final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {. @ Override @ Nullable public Object invoke (Object proxy, Method method, Object [] args) throws Throwable {. If (this.advised.exposeProxy) {/ / Make invocation available if necessary. OldProxy = AopContext.setCurrentProxy (proxy); setProxyContext = true;}. Finally {if (setProxyContext) {/ / Restore old proxy. AopContext.setCurrentProxy (oldProxy);}}
The final decision on whether or not to call the set method is determined by the value of this.advised.exposeProxy, so we only need to care about when the value of the ProxyConfig.exposeProxy property is assigned to true.
The default value for the ProxyConfig.exposeProxy attribute is false. In fact, the final call to the setting value is the Advised.setExposeProxy () method of the same name, and it is called through reflection. Once again, it is emphasized to see clearly the post processor. The scope of @ EnableAspectJAutoProxy (exposeProxy = true) is not good in the AbstractAutoProxyCreator creator, asynchronous annotations and cache annotations. How to solve the problem is analyzed later.
Class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {AspectJAutoProxyRegistrar () {} public void registerBeanDefinitions (AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary (registry); AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor (importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAspectJAutoProxy! = null) {if (enableAspectJAutoProxy.getBoolean ("proxyTargetClass")) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying (registry) } / / process whether the property if (enableAspectJAutoProxy.getBoolean ("exposeProxy")) {AopConfigUtils.forceAutoProxyCreatorToExposeProxy (registry);}} is set
Take a look at how to set the property value, which we can set later in this way.
Public static void forceAutoProxyCreatorToExposeProxy (BeanDefinitionRegistry registry) {if (registry.containsBeanDefinition (AUTO_PROXY_CREATOR_BEAN_NAME)) {BeanDefinition definition = registry.getBeanDefinition (AUTO_PROXY_CREATOR_BEAN_NAME); definition.getPropertyValues () .add ("exposeProxy", Boolean.TRUE);}}
When did you use it?
AopContext.setCurrentProxy (@ Nullable Object proxy) is used in both CglibAopProxy and JdkDynamicAopProxy agents.
Case study @ Component public class AsyncWithTransactional {/ / entry method @ Transactional public void transactional () {/ / if the proxy object is not used, the subsequent method will not be enhanced AsyncWithTransactional asyncWithTransactional = AsyncWithTransactional.class.cast (AopContext.currentProxy ()); asyncWithTransactional.async () } @ Async public void async () {}}
This is all completely ok, but if you change it, it will run abnormal.
Problems caused by child threads @ Transactional//@Transactional have this comment and have nothing to do with @ Async public void transactional () {AsyncWithTransactional asyncWithTransactional = AsyncWithTransactional.class.cast (AopContext.currentProxy ()); asyncWithTransactional.async ();} public void async () {}
The root cause is the timing of execution of key nodes. When executing the proxy object transactional method, the binding action AopContext.setCurrentProxy (proxy) is executed first; then the target method executes (including the execution of the enhancer) invocation.proceed (). As a matter of fact, the binding is performed in the main thread rather than the new asynchronous thread, so if you execute AopContext.currentProxy () in the method body (which is already an asynchronous thread), you will report an error.
Therefore, the use of @ Async effect annotations in the entry method will result in incorrect binding of the proxy object, which in turn leads to a call error.
How to solve the problems caused by subthreads? Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@ Override public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException {BeanDefinition beanDefinition = beanFactory.getBeanDefinition (TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME); beanDefinition.getPropertyValues () .add ("exposeProxy", true);}}
This solves the binding problem of @ Async, and @ EnableCaching can also be solved based on this idea. The above is my simple example, but with my text explanation, I believe you can use examples and play with the calling relationship between them at will. In fact, if Spring makes source code changes, it will solve this problem better.
@ Async's agent is also handed over to the automatic agent creator (Spring makes source code changes)
@ EnableAsync adds exposeProxy attribute. The default value is false (Spring makes source code changes)
Summary:
Do not use AopContext.currentProxy () in asynchronous threads
AopContext.currentProxy () cannot be used in the same method as a non-proxy object.
The above is how to call the proxy object embedding in Springboot. The editor believes that there are some knowledge points that we may see or use in our daily work. I hope you can learn more from this article. For more details, please follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.