Skip to content
Open
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
4 changes: 4 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
Copy link
Author

Choose a reason for hiding this comment

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

看看哪里用到了

</dependencies>


Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/com/szy/core/eunm/SzyExceptionEnum.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
public enum SzyExceptionEnum {

CONFIG_CENTER_METHOD_SIGNATURE_ERROR(100001, "方法签名错误,方法必须无参并且有返回值"),

CONFIG_CENTER_ANNOTATION_NOT_FOUND(100002, "接口上使用@SConfigCenter, 返回值为基础类型的方法必须使用@SValue注解"),

HTTP_CENTER_HTTPMETHOD_NOT_FOUND(200001, "请求方式必须设置"),

HTTP_CENTER_HTTPSUBPATH_NOT_FOUND(200002, "请求子路径必须设置")
;


Expand Down
143 changes: 143 additions & 0 deletions core/src/main/java/com/szy/core/httpcenter/HttpCenterFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package com.szy.core.httpcenter;

import com.szy.core.eunm.SzyExceptionEnum;
import com.szy.core.httpcenter.annotation.*;
import com.szy.core.util.GenericBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.cglib.proxy.CallbackHelper;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.cglib.proxy.NoOp;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;

@Component
@Slf4j
public class HttpCenterFactory<T> implements FactoryBean<T> {

private Class<T> interfaceType;

@Resource
SzyHttpClientFactory szyHttpClientFactory;

SzyHttpClient szyHttpClient;
private final InvocationHandler invocationHandler = (o, method1, objects) -> {

SzyExceptionEnum.HTTP_CENTER_HTTPSUBPATH_NOT_FOUND
.throwsIf(!method1.isAnnotationPresent(SHttpSubPath.class));

SzyExceptionEnum.HTTP_CENTER_HTTPMETHOD_NOT_FOUND
.throwsIf(!method1.isAnnotationPresent(SHttpMethod.class));
Copy link
Author

Choose a reason for hiding this comment

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

参考processor接口,参数校验全写在preCheck里


szyHttpClient = szyHttpClientFactory.getClient();

String url = method1.getAnnotation(SHttpSubPath.class).value();

Annotation[][] parameterAnnotations = method1.getParameterAnnotations();
Copy link
Author

Choose a reason for hiding this comment

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

  1. 查点所有元信息
  2. 处理元信息
  3. 执行

Copy link
Author

Choose a reason for hiding this comment

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

  1. 加上注释


String[] pathVars = new String[parameterAnnotations.length];
int pathVarIndex = 0;
for(int i = 0; i < parameterAnnotations.length; i ++){
if(parameterAnnotations[i][0].annotationType() == SPathVar.class){
pathVars[pathVarIndex ++] = objects[i].toString();
}

}
if(pathVarIndex > 0){
url = MessageFormat.format(url, pathVars);
}

String httpMethod = method1.getAnnotation(SHttpMethod.class).value();
szyHttpClient.setHttpMethod(httpMethod);

if(interfaceType.isAnnotationPresent(SHttpPath.class)){
url = interfaceType.getAnnotation(SHttpPath.class).value() + url;
}


if (method1.isAnnotationPresent(SHttpHeaders.class)) {
SHttpHeader[] annotationsByType = method1.getAnnotationsByType(SHttpHeader.class);
log.info("annotationsByType:" + annotationsByType);
for (SHttpHeader annotation : annotationsByType) {
szyHttpClient.setHeader(annotation.key(), annotation.value());
}
}

HashMap<String, Object> requestParammap = new HashMap<>();
for(int i = 0; i < parameterAnnotations.length; i ++){
if(parameterAnnotations[i][0] instanceof SRequestParam){
requestParammap.put(((SRequestParam) parameterAnnotations[i][0]).value(), objects[i]);
}
}
if(requestParammap.size() > 0){
url = url + "?";
for(Map.Entry<String, Object> entry : requestParammap.entrySet()){
Copy link
Author

Choose a reason for hiding this comment

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

  1. 硬编码改成变量,提前一点
  2. 尝试join替代循环,如果原生join不好用,可以自己写一个JoinUtils

url = url + entry.getKey() + "=" + entry.getValue() + "&";
}
}
szyHttpClient.setUrl(url);


int bodyIndex = -1;
for(int i = 0; i < parameterAnnotations.length; i ++){
if(parameterAnnotations[i][0].annotationType() == SHttpBody.class){
bodyIndex = i;
}
}
Copy link
Author

Choose a reason for hiding this comment

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

一个循环分拣出所有参数
判断分拣出来的是否为空

if(bodyIndex != -1){
szyHttpClient.setBody(objects[bodyIndex]);
}

Type type = method1.getGenericReturnType();

return szyHttpClient.excute(type);

};

/**
* 由 beanDefinition 注入
*/
public HttpCenterFactory(Class<T> interfaceType) {
this.interfaceType = interfaceType;
}

@Override
public T getObject() {
CallbackHelper callbackHelper = new CallbackHelper(Object.class, new Class[]{interfaceType}) {
@Override
protected Object getCallback(Method method) {
return method.isDefault()
? NoOp.INSTANCE
: invocationHandler;
}
};

Enhancer enhancer = GenericBuilder.of(Enhancer::new)
.with(Enhancer::setSuperclass, Object.class)
.with(Enhancer::setInterfaces, new Class[] {interfaceType})
.with(Enhancer::setCallbackFilter, callbackHelper)
.with(Enhancer::setCallbackTypes, callbackHelper.getCallbackTypes())
.with(Enhancer::setCallbacks, callbackHelper.getCallbacks())
.build();

return (T) enhancer.create();
}

@Override
public Class<?> getObjectType() {
return interfaceType;
}

@Override
public boolean isSingleton() {
return true;
}
}
109 changes: 109 additions & 0 deletions core/src/main/java/com/szy/core/httpcenter/HttpCenterProcessor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.szy.core.httpcenter;
Copy link
Author

Choose a reason for hiding this comment

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

这个类去实现通用的模版方法


import com.szy.core.httpcenter.annotation.HttpCenterScan;
import com.szy.core.httpcenter.annotation.SHttpCenter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.LinkedHashSet;
import java.util.Set;

@Component
@Slf4j
public class HttpCenterProcessor implements
ImportBeanDefinitionRegistrar,
ResourceLoaderAware,
EnvironmentAware {

private static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";

private MetadataReaderFactory metadataReaderFactory;

private ResourcePatternResolver resourcePatternResolver;

private Environment environment;

@SneakyThrows
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
ImportBeanDefinitionRegistrar.super.registerBeanDefinitions(importingClassMetadata, registry);
AnnotationAttributes httpScanAttr = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(HttpCenterScan.class.getName()));
String basePackageName = httpScanAttr.getString("value");
Set<Class<?>> beanClazzs = scannerPackages(basePackageName);
for (Class beanClazz : beanClazzs) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClazz);
GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();

definition.getConstructorArgumentValues().addGenericArgumentValue(beanClazz);
definition.setBeanClass(HttpCenterFactory.class);

//这里采用的是byType方式注入,类似的还有byName等
definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
registry.registerBeanDefinition(beanClazz.getSimpleName(), definition);
}
}

/**
* 根据包路径获取包及子包下的所有类
*
* @param basePackage basePackage
*/
private Set<Class<?>> scannerPackages(String basePackage) throws ClassNotFoundException, IOException {
Set<Class<?>> set = new LinkedHashSet<>();
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + DEFAULT_RESOURCE_PATTERN;
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
for (Resource resource : resources) {
if (!resource.isReadable()) {
continue;
}
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
String className = metadataReader.getClassMetadata().getClassName();
Class<?> clazz;
clazz = Class.forName(className);
Annotation annotation = clazz.getAnnotation(SHttpCenter.class);
if (annotation == null) {
continue;
}
set.add(clazz);
}
return set;
}

protected String resolveBasePackage(String basePackage) {
return ClassUtils.convertClassNameToResourcePath(this.environment.resolveRequiredPlaceholders(basePackage));
}

@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
}


@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
21 changes: 21 additions & 0 deletions core/src/main/java/com/szy/core/httpcenter/SzyHttpClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.szy.core.httpcenter;

import org.springframework.stereotype.Component;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;


/**
* @author zzsnowy
*/
@Component
public interface SzyHttpClient {

SzyHttpClient setUrl(String url);
SzyHttpClient setHttpMethod(String methodName);
SzyHttpClient setHeader(String key, String value);
<T> SzyHttpClient setBody(T t);
<R> R excute(Type type);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.szy.core.httpcenter;


import org.springframework.stereotype.Component;

/**
* @author zzsnowy
*/
@Component
public interface SzyHttpClientFactory {

SzyHttpClient getClient();

}
12 changes: 12 additions & 0 deletions core/src/main/java/com/szy/core/httpcenter/SzyHttpMethod.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.szy.core.httpcenter;

public interface SzyHttpMethod {
String POST = "POST";
String GET = "GET";
String HEAD = "HEAD";
String PUT = "PUT";
String PATCH = "PATCH";
String DELETE = "DELETE";
String OPTIONS = "OPTIONS";
String TRACE = "TRACE";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.szy.core.httpcenter.annotation;

import com.szy.core.httpcenter.HttpCenterProcessor;
import com.szy.core.httpcenter.impl.DefaultSzyHttpClientFactory;
import org.springframework.context.annotation.Import;

import java.lang.annotation.*;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({HttpCenterProcessor.class, DefaultSzyHttpClientFactory.class})
public @interface HttpCenterScan {
String value();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.szy.core.httpcenter.annotation;

import java.lang.annotation.*;

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SHttpBody {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.szy.core.httpcenter.annotation;

import java.lang.annotation.*;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SHttpCenter {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.szy.core.httpcenter.annotation;

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(SHttpHeaders.class)
public @interface SHttpHeader {
String key();
String value();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.szy.core.httpcenter.annotation;

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SHttpHeaders {
SHttpHeader[] value();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.szy.core.httpcenter.annotation;

import java.lang.annotation.*;

@Target({ ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SHttpMethod {
String value();
}
Loading