提交 f467b64a 编写于 作者: G guide

[refractor]RpcReference annotation

上级 8c7273f1
......@@ -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
......@@ -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);
```
## 相关问题
......
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)
......
......@@ -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));
}
}
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<Class<? extends Annotation>> annotationTypes = new LinkedHashSet<>(1);
private final Map<String, InjectionMetadata> 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<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> 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<? extends Annotation> 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);
}
}
}
}
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;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册