Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

使用注解进行服务消费 #10

Merged
merged 1 commit into from
Sep 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions example-client/src/main/java/github/javaguide/HelloController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package github.javaguide;

import github.javaguide.annotation.RpcReference;
import org.springframework.stereotype.Component;

/**
* @author smile2coder
*/
@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")));
}
}
}
21 changes: 9 additions & 12 deletions example-client/src/main/java/github/javaguide/NettyClientMain.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
package github.javaguide;

import github.javaguide.annotation.RpcScan;
import github.javaguide.entity.RpcServiceProperties;
import github.javaguide.proxy.RpcClientProxy;
import github.javaguide.remoting.transport.ClientTransport;
import github.javaguide.remoting.transport.netty.client.NettyClientTransport;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
* @author shuang.kou
* @createTime 2020年05月10日 07:25:00
*/
@RpcScan(basePackage = {"github.javaguide"})
public class NettyClientMain {
public static void main(String[] args) throws InterruptedException {
ClientTransport rpcClient = new NettyClientTransport();
RpcServiceProperties rpcServiceProperties = RpcServiceProperties.builder()
.group("test1").version("version1").build();
RpcClientProxy rpcClientProxy = new RpcClientProxy(rpcClient, rpcServiceProperties);
HelloService helloService = rpcClientProxy.getProxy(HelloService.class);
String hello = 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++) {
helloService.hello(new Hello("111", "222"));
}
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(NettyClientMain.class);
HelloController helloController = (HelloController) applicationContext.getBean("helloController");

helloController.test();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package github.javaguide.annotation;


import github.javaguide.spring.ReferenceAnnotationBeanPostProcessor;
import org.springframework.stereotype.Component;

import java.lang.annotation.*;

/**
* RPC reference annotation, autowire the service implementation class
* @author smile2coder
* @see ReferenceAnnotationBeanPostProcessor
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@Inherited
@Component
public @interface RpcReference {

/**
* Service version, default value is empty string
*/
String version() default "";

/**
* Service group, default value is empty string
*/
String group() default "";

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package github.javaguide.remoting.transport;

import github.javaguide.extension.SPI;
import github.javaguide.remoting.dto.RpcRequest;

/**
Expand All @@ -8,6 +9,7 @@
* @author shuang.kou
* @createTime 2020年05月29日 13:26:00
*/
@SPI
public interface ClientTransport {
/**
* send rpc request to server and get result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@
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;
Expand Down Expand Up @@ -54,6 +59,9 @@ public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanD
log.info("springBeanScanner扫描的数量 [{}]", springBeanAmount);
int scanCount = rpcServiceScanner.scan(rpcScanBasePackages);
log.info("rpcServiceScanner扫描的数量 [{}]", scanCount);

beanDefinitionRegistry.registerBeanDefinition(ReferenceAnnotationBeanPostProcessor.BEAN_NAME,
new RootBeanDefinition(ReferenceAnnotationBeanPostProcessor.class));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
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);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
nettyClientTransport=github.javaguide.remoting.transport.netty.client.NettyClientTransport
socketRpcClient=github.javaguide.remoting.transport.socket.SocketRpcClient