From d1ee9dcbed019f02a568b1a0a38f828daa8d505c Mon Sep 17 00:00:00 2001 From: liubao68 Date: Tue, 30 Jul 2024 11:33:58 +0800 Subject: [PATCH] [#2740]support factory bean eager injection of RpcReference (#4436) --- .../springmvc/client/TestFactoryBean.java | 42 ++++++++++++++++ .../springmvc/client/factory/ServiceBean.java | 30 ++++++++++++ .../client/factory/ServiceFactoryBean.java | 48 +++++++++++++++++++ .../client/factory/ServiceWithReference.java | 22 +++++++++ .../factory/ServiceWithReferenceImpl.java | 33 +++++++++++++ .../inject/InjectBeanPostProcessor.java | 4 ++ .../RpcReferenceBeanDefinitionRegistry.java | 42 ++++++++++++++++ .../pojo/reference/RpcReferenceProcessor.java | 20 ++++---- .../reference/TestRpcReferenceProcessor.java | 8 +++- 9 files changed, 235 insertions(+), 14 deletions(-) create mode 100644 demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestFactoryBean.java create mode 100644 demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceBean.java create mode 100644 demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceFactoryBean.java create mode 100644 demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceWithReference.java create mode 100644 demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceWithReferenceImpl.java create mode 100644 providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/RpcReferenceBeanDefinitionRegistry.java diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestFactoryBean.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestFactoryBean.java new file mode 100644 index 00000000000..78295f47a8a --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestFactoryBean.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.springmvc.client.factory.ServiceBean; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +@Component +public class TestFactoryBean implements CategorizedTestCase, ApplicationContextAware { + ApplicationContext applicationContext; + + @Override + public void testRestTransport() throws Exception { + ServiceBean serviceBean = (ServiceBean) this.applicationContext.getBean("ServiceFactoryBean"); + TestMgr.check("a-3", serviceBean.getName()); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceBean.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceBean.java new file mode 100644 index 00000000000..1a25838d083 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceBean.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client.factory; + +public class ServiceBean { + private final String name; + + public ServiceBean(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceFactoryBean.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceFactoryBean.java new file mode 100644 index 00000000000..9bee6805c48 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceFactoryBean.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client.factory; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("ServiceFactoryBean") +public class ServiceFactoryBean implements FactoryBean { + + ServiceWithReference serviceWithReference; + + @Autowired + public ServiceFactoryBean(ServiceWithReference serviceWithReference) { + this.serviceWithReference = serviceWithReference; + } + + @Override + public ServiceBean getObject() throws Exception { + return new ServiceBean(serviceWithReference.test("a")); + } + + @Override + public Class getObjectType() { + return ServiceBean.class; + } + + @Override + public boolean isSingleton() { + return true; + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceWithReference.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceWithReference.java new file mode 100644 index 00000000000..f371bf35148 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceWithReference.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client.factory; + +public interface ServiceWithReference { + String test(String name); +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceWithReferenceImpl.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceWithReferenceImpl.java new file mode 100644 index 00000000000..a5f8d7c6bb1 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceWithReferenceImpl.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client.factory; + +import org.apache.servicecomb.demo.springmvc.client.SchemeInterfaceSpringmvc; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +@Component +public class ServiceWithReferenceImpl implements ServiceWithReference { + @RpcReference(schemaId = "SchemeInterfaceSpringmvc", microserviceName = "springmvc") + private SchemeInterfaceSpringmvc springmvc; + + @Override + public String test(String name) { + return name + "-" + springmvc.add(1, 2); + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/inject/InjectBeanPostProcessor.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/inject/InjectBeanPostProcessor.java index a5202504dbd..1e8cd763c59 100644 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/inject/InjectBeanPostProcessor.java +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/inject/InjectBeanPostProcessor.java @@ -22,13 +22,17 @@ import org.apache.servicecomb.config.priority.PriorityPropertyManager; import org.apache.servicecomb.foundation.common.utils.BeanUtils; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @Component public class InjectBeanPostProcessor implements BeanPostProcessor { private final PriorityPropertyManager priorityPropertyManager; + @Autowired + @Lazy public InjectBeanPostProcessor(PriorityPropertyManager priorityPropertyManager) { this.priorityPropertyManager = priorityPropertyManager; } diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/RpcReferenceBeanDefinitionRegistry.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/RpcReferenceBeanDefinitionRegistry.java new file mode 100644 index 00000000000..2e7c7e16406 --- /dev/null +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/RpcReferenceBeanDefinitionRegistry.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.provider.pojo; + +import org.apache.servicecomb.provider.pojo.reference.RpcReferenceProcessor; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; +import org.springframework.stereotype.Component; + +/** + * In order to support FactoryBean eager inject @RpcReference, add RpcReferenceProcessor + * before FactoryBean is initialized. + */ +@Component +public class RpcReferenceBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor { + @Override + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { + + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + beanFactory.addBeanPostProcessor(new RpcReferenceProcessor(beanFactory)); + } +} diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/reference/RpcReferenceProcessor.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/reference/RpcReferenceProcessor.java index 0663ac00185..ba5ded3f12c 100644 --- a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/reference/RpcReferenceProcessor.java +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/reference/RpcReferenceProcessor.java @@ -23,14 +23,15 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.context.EmbeddedValueResolverAware; -import org.springframework.stereotype.Component; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.util.ReflectionUtils; -import org.springframework.util.StringValueResolver; -@Component -public class RpcReferenceProcessor implements BeanPostProcessor, EmbeddedValueResolverAware { - private StringValueResolver resolver; +public class RpcReferenceProcessor implements BeanPostProcessor { + private final ConfigurableBeanFactory beanFactory; + + public RpcReferenceProcessor(ConfigurableBeanFactory beanFactory) { + this.beanFactory = beanFactory; + } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { @@ -62,11 +63,6 @@ protected void processConsumerField(Object bean, Field field) { handleReferenceField(bean, field, reference); } - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.resolver = resolver; - } - private void handleReferenceMethod(Object bean, String beanName, Method method, RpcReference reference) throws BeansException { try { @@ -86,7 +82,7 @@ private void handleReferenceField(Object obj, Field field, private PojoReferenceMeta createPojoReferenceMeta(RpcReference reference, Class consumerInterface) { String microserviceName = reference.microserviceName(); - microserviceName = resolver.resolveStringValue(microserviceName); + microserviceName = beanFactory.resolveEmbeddedValue(microserviceName); PojoReferenceMeta pojoReference = new PojoReferenceMeta(); pojoReference.setMicroserviceName(microserviceName); diff --git a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/reference/TestRpcReferenceProcessor.java b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/reference/TestRpcReferenceProcessor.java index d32a9b9c5d6..72fe8ec30ab 100644 --- a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/reference/TestRpcReferenceProcessor.java +++ b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/reference/TestRpcReferenceProcessor.java @@ -28,9 +28,13 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; public class TestRpcReferenceProcessor { - RpcReferenceProcessor consumers = new RpcReferenceProcessor(); + static ConfigurableBeanFactory beanFactory = Mockito.mock(ConfigurableBeanFactory.class); + + RpcReferenceProcessor consumers = new RpcReferenceProcessor(beanFactory); @BeforeEach public void setUp() { @@ -56,7 +60,7 @@ public void testReference() { Assertions.assertNull(bean.person); - consumers.setEmbeddedValueResolver((strVal) -> strVal); + Mockito.when(beanFactory.resolveEmbeddedValue("test")).thenReturn("test"); Assertions.assertSame(bean, consumers.postProcessBeforeInitialization(bean, "id")); Assertions.assertNotNull(bean.person);