Skip to content

Conversation

youjie23
Copy link
Contributor

@youjie23 youjie23 commented Dec 14, 2024

Fix apache/skywalking#12858 The CreateAopProxyInterceptor in the Spring core-patch indeed changes the implementation of the Spring AOP proxy

  • Add a unit test to verify that the fix works.
  • Explain briefly why the bug exists and how to fix it.
    The current version of CreateAopProxyInterceptor does not account for scenarios where the proxy target class implements UserSuppliedInterface and should work correctly with only JdkDynamicAopProxy. This can lead to inconsistencies in behavior when the SkyWalking agent is used.

This PR fixes the issue by adding restrictions on when the behavior changes, ensuring that the proxy mechanism reverts to using JdkDynamicAopProxy when appropriate. Specifically, it ensures that the application's behavior remains consistent both with and without the SkyWalking agent enhancement.

@youjie23 youjie23 changed the title #12858:The CreateAopProxyInterceptor in the Spring core-patch indeed changes the implementation of the Spring AOP proxy #12858 - The CreateAopProxyInterceptor in the Spring core-patch indeed changes the implementation of the Spring AOP proxy Dec 14, 2024
@wu-sheng wu-sheng added the bug Something isn't working label Dec 14, 2024
@wu-sheng wu-sheng added this to the 9.4.0 milestone Dec 14, 2024
@wu-sheng
Copy link
Member

You missed the update of changes.md. Please fix it if all tests can pass.

private boolean onlyImplementsEnhancedInstanceAndSpringProxy(AdvisedSupport advisedSupport) {
Class<?>[] ifcs = advisedSupport.getProxiedInterfaces();
Class targetClass = advisedSupport.getTargetClass();
return ifcs.length == 2 && EnhancedInstance.class.isAssignableFrom(targetClass) && SpringProxy.class.isAssignableFrom(targetClass);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When is SpringProxy.class added into the hierarchy tree?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the review.
As shown below, the hasNoUserSuppliedProxyInterfaces method in DefaultAopProxyFactory is defined as follows:
spring4/spring5

         /**
	 * Determine whether the supplied {@link AdvisedSupport} has only the
	 * {@link org.springframework.aop.SpringProxy} interface specified
	 * (or no proxy interfaces specified at all).
	 */
	private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
		Class<?>[] ifcs = config.getProxiedInterfaces();
		return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
	}

spring3

         /**
	 * Determine whether the supplied {@link AdvisedSupport} has only the
	 * {@link org.springframework.aop.SpringProxy} interface specified
	 * (or no proxy interfaces specified at all).
	 */
	private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
		Class[] interfaces = config.getProxiedInterfaces();
		return (interfaces.length == 0 || (interfaces.length == 1 && SpringProxy.class.equals(interfaces[0])));
	}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, this seems ok. Could you update the changelog? Then I could merge this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the review.
The Changes.md file has been updated.

@wu-sheng wu-sheng changed the title #12858 - The CreateAopProxyInterceptor in the Spring core-patch indeed changes the implementation of the Spring AOP proxy Fix CreateAopProxyInterceptor in the Spring core-patch indeed changes the implementation of the Spring AOP proxy Dec 15, 2024
Copy link
Member

@wu-sheng wu-sheng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Wait for CI passed.

@wu-sheng wu-sheng merged commit 26600e7 into apache:main Dec 15, 2024
193 checks passed
public void testInterceptClassImplementsEnhancedInstance() throws Throwable {
doReturn(MockClassImplementsEnhancedInstance.class).when(advisedSupport).getTargetClass();
doReturn(MockClassImplementsEnhancedInstance.class.getInterfaces()).when(advisedSupport).getProxiedInterfaces();
assertThat(true, is(interceptor.afterMethod(enhancedInstance, null, new Object[] {advisedSupport}, new Class[] {Object.class}, false)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://stackoverflow.com/questions/45124660/the-bean-could-not-be-injected-as-a-type-because-it-is-a-jdk-dynamic-proxy-tha

According to the answer in this SO thread, we basically should not expect classes that both use @Transactional annotation and being enhanced by SkyWalking Agent to use JDK Proxy.

We are facing startup failures after upgrading to SkyWalking 9.4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug] The CreateAopProxyInterceptor in the Spring core-patch indeed changes the implementation of the Spring AOP proxy.
3 participants