diff --git a/README-EN.md b/README-EN.md index b23709402a2df9a6b36d308681020e84112f8917..29aa10317bbec4d49dbfb26e4f2abcae86f8bbf6 100644 --- a/README-EN.md +++ b/README-EN.md @@ -160,11 +160,32 @@ public class NettyServerMain { ### Client(srvice consumer) + +```java +@Component +public class HelloController { + + @RpcReference(version = "version1", group = "test1") + private HelloService helloService; + + public void test() throws InterruptedException { + String hello = this.helloService.hello(new Hello("111", "222")); + //如需使用 assert 断言,需要在 VM options 添加参数:-ea + assert "Hello description is 222".equals(hello); + Thread.sleep(12000); + for (int i = 0; i < 10; i++) { + System.out.println(helloService.hello(new Hello("111", "222"))); + } + } +} +``` + ```java -ClientTransport rpcClient = new NettyClientTransport(); +ClientTransport clientTransport = new SocketRpcClient(); RpcServiceProperties rpcServiceProperties = RpcServiceProperties.builder() - .group("test1").version("version1").build(); -RpcClientProxy rpcClientProxy = new RpcClientProxy(rpcClient, rpcServiceProperties); + .group("test2").version("version2").build(); +RpcClientProxy rpcClientProxy = new RpcClientProxy(clientTransport, rpcServiceProperties); HelloService helloService = rpcClientProxy.getProxy(HelloService.class); String hello = helloService.hello(new Hello("111", "222")); +System.out.println(hello); ``` \ No newline at end of file diff --git a/README.md b/README.md index 0a49c63ea19b1cf52abc97bfef91178711a6bd15..aef34ec37bd00134ea577fe52026897c95d5107d 100644 --- a/README.md +++ b/README.md @@ -201,12 +201,32 @@ public class NettyServerMain { ### 服务消费端 ```java -ClientTransport rpcClient = new NettyClientTransport(); +@Component +public class HelloController { + + @RpcReference(version = "version1", group = "test1") + private HelloService helloService; + + public void test() throws InterruptedException { + String hello = this.helloService.hello(new Hello("111", "222")); + //如需使用 assert 断言,需要在 VM options 添加参数:-ea + assert "Hello description is 222".equals(hello); + Thread.sleep(12000); + for (int i = 0; i < 10; i++) { + System.out.println(helloService.hello(new Hello("111", "222"))); + } + } +} +``` + +```java +ClientTransport clientTransport = new SocketRpcClient(); RpcServiceProperties rpcServiceProperties = RpcServiceProperties.builder() - .group("test1").version("version1").build(); -RpcClientProxy rpcClientProxy = new RpcClientProxy(rpcClient, rpcServiceProperties); + .group("test2").version("version2").build(); +RpcClientProxy rpcClientProxy = new RpcClientProxy(clientTransport, rpcServiceProperties); HelloService helloService = rpcClientProxy.getProxy(HelloService.class); String hello = helloService.hello(new Hello("111", "222")); +System.out.println(hello); ``` ## 相关问题 diff --git a/rpc-framework-simple/src/main/java/github/javaguide/annotation/RpcReference.java b/rpc-framework-simple/src/main/java/github/javaguide/annotation/RpcReference.java index 744d4fe6303e1f3488b43c4c0693256eaec62417..c8ebf782cc50bbb7e03fa98514e05958aa7f567a 100644 --- a/rpc-framework-simple/src/main/java/github/javaguide/annotation/RpcReference.java +++ b/rpc-framework-simple/src/main/java/github/javaguide/annotation/RpcReference.java @@ -1,15 +1,19 @@ package github.javaguide.annotation; -import github.javaguide.spring.ReferenceAnnotationBeanPostProcessor; import org.springframework.stereotype.Component; -import java.lang.annotation.*; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; /** * RPC reference annotation, autowire the service implementation class + * * @author smile2coder - * @see ReferenceAnnotationBeanPostProcessor */ @Documented @Retention(RetentionPolicy.RUNTIME) diff --git a/rpc-framework-simple/src/main/java/github/javaguide/spring/CustomScannerRegistrar.java b/rpc-framework-simple/src/main/java/github/javaguide/spring/CustomScannerRegistrar.java index a8ce3742d467af8616629d33344c9e2df6f4ecf2..545f2b81fdea3abd73307c53b1df5e12cf5fe224 100644 --- a/rpc-framework-simple/src/main/java/github/javaguide/spring/CustomScannerRegistrar.java +++ b/rpc-framework-simple/src/main/java/github/javaguide/spring/CustomScannerRegistrar.java @@ -3,14 +3,9 @@ package github.javaguide.spring; import github.javaguide.annotation.RpcScan; import github.javaguide.annotation.RpcService; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.MutablePropertyValues; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.ConstructorArgumentValues; import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.ResourceLoaderAware; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; -import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.io.ResourceLoader; import org.springframework.core.type.AnnotationMetadata; @@ -57,11 +52,9 @@ public class CustomScannerRegistrar implements ImportBeanDefinitionRegistrar, Re } int springBeanAmount = springBeanScanner.scan(SPRING_BEAN_BASE_PACKAGE); log.info("springBeanScanner扫描的数量 [{}]", springBeanAmount); - int scanCount = rpcServiceScanner.scan(rpcScanBasePackages); - log.info("rpcServiceScanner扫描的数量 [{}]", scanCount); + int rpcServiceCount = rpcServiceScanner.scan(rpcScanBasePackages); + log.info("rpcServiceScanner扫描的数量 [{}]", rpcServiceCount); - beanDefinitionRegistry.registerBeanDefinition(ReferenceAnnotationBeanPostProcessor.BEAN_NAME, - new RootBeanDefinition(ReferenceAnnotationBeanPostProcessor.class)); } } diff --git a/rpc-framework-simple/src/main/java/github/javaguide/spring/ReferenceAnnotationBeanPostProcessor.java b/rpc-framework-simple/src/main/java/github/javaguide/spring/ReferenceAnnotationBeanPostProcessor.java deleted file mode 100644 index ea842d105f25f3e1646649c0eabf75bdae43985c..0000000000000000000000000000000000000000 --- a/rpc-framework-simple/src/main/java/github/javaguide/spring/ReferenceAnnotationBeanPostProcessor.java +++ /dev/null @@ -1,177 +0,0 @@ -package github.javaguide.spring; - -import github.javaguide.annotation.RpcReference; -import github.javaguide.entity.RpcServiceProperties; -import github.javaguide.extension.ExtensionLoader; -import github.javaguide.proxy.RpcClientProxy; -import github.javaguide.registry.ServiceDiscovery; -import github.javaguide.remoting.transport.ClientTransport; -import github.javaguide.remoting.transport.netty.client.NettyClientTransport; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.BeansException; -import org.springframework.beans.PropertyValues; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor; -import org.springframework.beans.factory.annotation.InjectionMetadata; -import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; -import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.core.BridgeMethodResolver; -import org.springframework.core.annotation.AnnotationAttributes; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.core.annotation.MergedAnnotation; -import org.springframework.core.annotation.MergedAnnotations; -import org.springframework.lang.Nullable; -import org.springframework.util.ClassUtils; -import org.springframework.util.ReflectionUtils; -import org.springframework.util.StringUtils; - -import java.beans.PropertyDescriptor; -import java.lang.annotation.Annotation; -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -/** - * @author smile2coder - * @ - */ -@Slf4j -public class ReferenceAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements - MergedBeanDefinitionPostProcessor, ApplicationContextAware { - - public static final String BEAN_NAME = "referenceAnnotationBeanPostProcessor"; - - private String version = "version"; - private String group = "group"; - - private ApplicationContext applicationContext; - - private ClientTransport rpcClient; - - private final Set> annotationTypes = new LinkedHashSet<>(1); - - private final Map injectionMetadataCache = new ConcurrentHashMap<>(256); - - public ReferenceAnnotationBeanPostProcessor() { - this.annotationTypes.add(RpcReference.class); - this.rpcClient = ExtensionLoader.getExtensionLoader(ClientTransport.class).getExtension("nettyClientTransport"); - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - - @Override - public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) { - InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null); - metadata.checkConfigMembers(beanDefinition); - } - - private InjectionMetadata findAutowiringMetadata(String beanName, Class clazz, PropertyValues pvs) { - // Fall back to class name as cache key, for backwards compatibility with custom callers. - String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); - // Quick check on the concurrent map first, with minimal locking. - InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); - if (InjectionMetadata.needsRefresh(metadata, clazz)) { - synchronized (this.injectionMetadataCache) { - metadata = this.injectionMetadataCache.get(cacheKey); - if (InjectionMetadata.needsRefresh(metadata, clazz)) { - if (metadata != null) { - metadata.clear(pvs); - } - metadata = buildAutowiringMetadata(clazz); - this.injectionMetadataCache.put(cacheKey, metadata); - } - } - } - return metadata; - } - - private InjectionMetadata buildAutowiringMetadata(final Class clazz) { - - List elements = new ArrayList<>(); - Class targetClass = clazz; - - do { - final List currElements = new ArrayList<>(); - - ReflectionUtils.doWithLocalFields(targetClass, field -> { - MergedAnnotation ann = findReferenceAnnotation(field); - if (ann != null) { - if (Modifier.isStatic(field.getModifiers())) { - if (log.isInfoEnabled()) { - log.info("Autowired annotation is not supported on static fields: " + field); - } - return; - } - AnnotationAttributes annotationAttributes = (AnnotationAttributes) - ann.asMap(mergedAnnotation -> new AnnotationAttributes(mergedAnnotation.getType())); - String version = annotationAttributes.getString(this.version); - String group = annotationAttributes.getString(this.group); - currElements.add(new ReferenceFieldElement(field, version, group)); - } - }); - - elements.addAll(0, currElements); - targetClass = targetClass.getSuperclass(); - } - while (targetClass != null && targetClass != Object.class); - - return InjectionMetadata.forElements(elements, clazz); - } - - @Nullable - private MergedAnnotation findReferenceAnnotation(AccessibleObject ao) { - MergedAnnotations annotations = MergedAnnotations.from(ao); - for (Class type : this.annotationTypes) { - MergedAnnotation annotation = annotations.get(type); - if (annotation.isPresent()) { - return annotation; - } - } - return null; - } - - @Override - public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException { - InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); - try { - metadata.inject(bean, beanName, pvs); - } catch (BeanCreationException ex) { - throw ex; - } catch (Throwable ex) { - throw new BeanCreationException(beanName, "Injection of reference dependencies failed", ex); - } - return pvs; - } - - private class ReferenceFieldElement extends InjectionMetadata.InjectedElement { - - private String version; - private String group; - - protected ReferenceFieldElement(Member member, String version, String group) { - super(member, null); - this.version = version; - this.group = group; - } - - @Override - protected void inject(Object target, String requestingBeanName, PropertyValues pvs) throws Throwable { - Field field = (Field) this.member; - RpcServiceProperties rpcServiceProperties = RpcServiceProperties.builder() - .group(group).version(version).build(); - RpcClientProxy rpcClientProxy = new RpcClientProxy(rpcClient, rpcServiceProperties); - Object value = rpcClientProxy.getProxy(field.getType()); - if (value != null) { - ReflectionUtils.makeAccessible(field); - field.set(target, value); - } - } - } -} diff --git a/rpc-framework-simple/src/main/java/github/javaguide/spring/SpringBeanPostProcessor.java b/rpc-framework-simple/src/main/java/github/javaguide/spring/SpringBeanPostProcessor.java index 35fb64fbbdcb87353556f91ef7d852cfe0b30331..3add9e028de3b38709a7ca6f9df08b4fed6e72dc 100644 --- a/rpc-framework-simple/src/main/java/github/javaguide/spring/SpringBeanPostProcessor.java +++ b/rpc-framework-simple/src/main/java/github/javaguide/spring/SpringBeanPostProcessor.java @@ -1,16 +1,22 @@ package github.javaguide.spring; +import github.javaguide.annotation.RpcReference; import github.javaguide.annotation.RpcService; import github.javaguide.entity.RpcServiceProperties; +import github.javaguide.extension.ExtensionLoader; import github.javaguide.factory.SingletonFactory; import github.javaguide.provider.ServiceProvider; import github.javaguide.provider.ServiceProviderImpl; +import github.javaguide.proxy.RpcClientProxy; +import github.javaguide.remoting.transport.ClientTransport; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.stereotype.Component; +import java.lang.reflect.Field; + /** * call this method before creating the bean to see if the class is annotated * @@ -22,9 +28,11 @@ import org.springframework.stereotype.Component; public class SpringBeanPostProcessor implements BeanPostProcessor { private final ServiceProvider serviceProvider; + private final ClientTransport rpcClient; public SpringBeanPostProcessor() { - serviceProvider = SingletonFactory.getInstance(ServiceProviderImpl.class); + this.serviceProvider = SingletonFactory.getInstance(ServiceProviderImpl.class); + this.rpcClient = ExtensionLoader.getExtensionLoader(ClientTransport.class).getExtension("nettyClientTransport"); } @SneakyThrows @@ -42,4 +50,26 @@ public class SpringBeanPostProcessor implements BeanPostProcessor { return bean; } + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + Class targetClass = bean.getClass(); + Field[] declaredFields = targetClass.getDeclaredFields(); + for (Field declaredField : declaredFields) { + RpcReference rpcReference = declaredField.getAnnotation(RpcReference.class); + if (rpcReference != null) { + RpcServiceProperties rpcServiceProperties = RpcServiceProperties.builder() + .group(rpcReference.group()).version(rpcReference.version()).build(); + RpcClientProxy rpcClientProxy = new RpcClientProxy(rpcClient, rpcServiceProperties); + Object clientProxy = rpcClientProxy.getProxy(declaredField.getType()); + declaredField.setAccessible(true); + try { + declaredField.set(bean, clientProxy); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + } + return bean; + } }