Commit 26528d96 by qiuweili123

1.0.8.RELEASE

parents 6cf6964d c3cc61fa
......@@ -18,25 +18,27 @@
+-- dubbo-starter
+-- web-starter
```
重要版本说明
说明:
* common-\*:通用依赖
* \*-starter:组件依赖
版本升级须知
当前开发版本 1.0.6-DEV-SNAPSHOT
1、rocketmq-starter 兼容Apollo
2、新增rocketmq 发送/接收,消息监听
正式版本
1.0.5.RELEASE
1.0.4.RELEASE
1、增加logstater模块
2、修正多语言环境下zh的无法取到错误信息
3、增加rocketmq-starter组件
1.0.4.RELEASE
1、update spring boot to 2.1.6
1.0.3.RELEASE
1、增加monitor traceId监控模块
2、增加防灾冗余
3、优化文件结构
4、增加对controller返回null响应增强
1.0.3.RELEASE
1、增加monitor traceId监控模块
......@@ -46,6 +48,6 @@
1.0.2.RELEASE
init code
......@@ -5,7 +5,7 @@
<parent>
<artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
......@@ -44,18 +44,6 @@
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
......
......@@ -4,6 +4,7 @@ import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
......@@ -14,6 +15,7 @@ import javax.annotation.Resource;
@Aspect
@Component
@ConditionalOnProperty(value = "transaction.support.enabled",havingValue = "true")
public class AopTransaction {
@Resource
private PlatformTransactionManager transactionManager;
......
......@@ -5,7 +5,7 @@
<parent>
<artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
......
......@@ -5,7 +5,7 @@
<parent>
<artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
......@@ -19,7 +19,6 @@
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
......
......@@ -26,6 +26,8 @@ public class ApolloContextInitializer implements ApplicationContextInitializer<C
if (!StringUtils.isEmpty(appId)) {
System.setProperty("app.id", appId);
System.setProperty("apollo.cacheDir", cacheDir);
System.setProperty("apollo.bootstrap.enabled","true");
System.setProperty("apollo.bootstrap.eagerLoad.enabled","true");
}
}
......
package com.secoo.mall.dubbo.annotation;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Service
public @interface DubboService {
@AliasFor(
annotation = Service.class
)
String value() default "";
}
......@@ -5,7 +5,7 @@
<parent>
<artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
......
......@@ -5,12 +5,16 @@
<parent>
<artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>logger-starter</artifactId>
<packaging>pom</packaging>
<modules>
<module>secoo-log</module>
<module>secoo-log-starter</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<logback.version>1.2.3</logback.version>
......@@ -18,39 +22,43 @@
<janino.version>3.0.6</janino.version>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- 桥接slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- 支持logback condition表达式 -->
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
<version>${janino.version}</version>
</dependency>
<!-- 打印skywalking tid插件-->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>6.2.1-beta.RELEASE</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- 桥接slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- 支持logback condition表达式 -->
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
<version>${janino.version}</version>
</dependency>
<!-- 打印skywalking tid插件-->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>6.2.1-beta.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
\ No newline at end of file
......@@ -3,23 +3,34 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>matrix</artifactId>
<artifactId>logger-starter</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>web-starter</artifactId>
<modelVersion>4.0.0</modelVersion>
<artifactId>secoo-log-starter</artifactId>
<name>${project.artifactId}</name>
<dependencies>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>common-util</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 打印skywalking tid插件-->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.secoo.mall.logs.config;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfig;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import com.ctrip.framework.apollo.spring.boot.ApolloAutoConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Set;
/**
* @author qianglu
*/
@Configuration
@ConditionalOnClass(ApolloAutoConfiguration.class)
public class MatrixLogListenerConfiguration {
private static final Logger logger = LoggerFactory.getLogger(MatrixLogListenerConfiguration.class);
private static final String LOGGER_TAG = "matrix.loggers.";
@Resource
private LoggingSystem loggingSystem;
@ApolloConfig
private Config config;
@ApolloConfigChangeListener
private void onChange(ConfigChangeEvent changeEvent) {
refreshLoggingLevels();
}
@PostConstruct
private void refreshLoggingLevels() {
Set<String> keyNames = config.getPropertyNames();
for (String key : keyNames) {
if (containsIgnoreCase(key, LOGGER_TAG)) {
String strLevel = config.getProperty(key, "info");
LogLevel level = LogLevel.valueOf(strLevel.toUpperCase());
loggingSystem.setLogLevel(key.replace(LOGGER_TAG, ""), level);
logger.info("update class {} logger level to {}", key, strLevel);
}
}
}
private static boolean containsIgnoreCase(String str, String searchStr) {
if (StringUtils.isEmpty(str) || StringUtils.isEmpty(searchStr)) {
return false;
}
int len = searchStr.length();
int max = str.length() - len;
for (int i = 0; i <= max; i++) {
if (str.regionMatches(true, i, searchStr, 0, len)) {
return true;
}
}
return false;
}
}
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.secoo.mall.logs.config.MatrixLogListenerConfiguration
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!-- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/2002/xmlspec/dtd/2.10/xmlspec.dtd"> -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<springProperty scope="context" name="logName" source="spring.application.name" defaultValue="app"/>
<springProperty scope="context" name="logLevel" source="log.level" defaultValue="info"/>
<springProperty scope="context" name="LOG_NAME" source="spring.application.name" defaultValue="app"/>
<springProperty scope="context" name="LOG_LEVEL" source="log.level" defaultValue="info"/>
<springProperty scope="context" name="LOG_PATH" source="log.path" defaultValue="/data/logs"/>
<springProperty scope="context" name="MAX_FILE_SIZE" source="log.max_file_size" defaultValue="128MB"/>
<springProperty scope="context" name="MAX_HISTORY" source="log.max_history" defaultValue="7"/>
<springProperty scope="context" name="PATTERN" source="log.pattern"
defaultValue="-|%d{yyyy-MM-dd HH:mm:ss.SSS}|%-5level|%X{tid}|%thread|%logger{36}.%M:%L-%msg%n"/>
<springProperty scope="context" name="PATTERN" source="log.pattern" defaultValue="-|%d{yyyy-MM-dd HH:mm:ss.SSS}|%-5level|%X{tid}|%thread|%logger{36}.%M:%L-%msg%n"/>
<property name="LOG_DIR" value="${LOG_PATH}/${logName}/%d{yyyyMMdd}"/>
<property name="LOG_DIR" value="${LOG_PATH}/${LOG_NAME}/%d{yyyyMMdd}"/>
<property name="CHARSET" value="UTF-8"/>
<jmxConfigurator/>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
......@@ -32,9 +30,9 @@
<onMismatch>DENY</onMismatch>
</filter>
<!-- 定义文件的名称 -->
<file>${LOG_PATH}/${logName}/error.log</file>
<file>${LOG_PATH}/${LOG_NAME}/error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${LOG_DIR}/err_${logName}%i.log</FileNamePattern>
<FileNamePattern>${LOG_DIR}/err_${LOG_NAME}%i.log</FileNamePattern>
<MaxHistory>${MAX_HISTORY}</MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
......@@ -47,9 +45,9 @@
<appender name="APP" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 定义文件的名称 -->
<file>${LOG_PATH}/${logName}/app.log</file>
<file>${LOG_PATH}/${LOG_NAME}/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${LOG_DIR}/all_${logName}%i.log</FileNamePattern>
<FileNamePattern>${LOG_DIR}/all_${LOG_NAME}%i.log</FileNamePattern>
<MaxHistory>${MAX_HISTORY}</MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
......@@ -81,22 +79,20 @@
</appender>
<logger name="app" level="${logLevel}">
<logger name="app" level="${LOG_LEVEL}">
<appender-ref ref="ASYN_APP"/>
</logger>
<logger name="error" level="${logLevel}">
<logger name="error" level="${LOG_LEVEL}">
<appender-ref ref="ASYN_ERROR"/>
</logger>
<!-- 日志排除 -->
<logger name="org.logicalcobwebs.proxool" level="error"/>
<!--统一日志输出级别,其他appender中如果有高于此处等级设置的也会被输出 -->
<root level="${logLevel}">
<root level="${LOG_LEVEL}">
<springProfile name="test,dev,local">
<appender-ref ref="ASYN_STDOUT"/>
</springProfile>
<appender-ref ref="ASYN_APP"/>
<appender-ref ref="ASYN_ERROR"/>
</root>
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>logger-starter</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.0.8.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>secoo-log</artifactId>
<name>${project.artifactId}</name>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<!-- 桥接slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</dependency>
<!-- 打印skywalking tid插件-->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
......@@ -3,7 +3,7 @@
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property resource="log.properties"/>
<property name="LOG_PATH" value="/data/logs"/>
<property name="LOG_PATH" value="/data/logs" />
<property name="LOG_DIR" value="${LOG_PATH}/${logName}/%d{yyyyMMdd}"/>
<property name="MAX_FILE_SIZE" value="${logFileSize}"/>
<property name="MAX_HISTORY" value="${logMaxHistory}"/>
......
......@@ -5,7 +5,7 @@
<parent>
<artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
......
......@@ -5,7 +5,7 @@
<parent>
<artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
......
......@@ -5,7 +5,7 @@
<parent>
<artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
......
......@@ -5,7 +5,7 @@
<parent>
<artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
......
package com.secoo.mall.openfeign.config;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfig {
// TODO: 2019/5/8 实现enable package自动加载 实现灰度发布 client请求日志拦截
@EnableFeignClients("com.secoo.mall")
public class MatrixFeignAutoConfiguration {
}
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.secoo.mall.openfeign.config.MatrixFeignAutoConfiguration
\ No newline at end of file
......@@ -6,7 +6,7 @@
<groupId>com.secoo.mall</groupId>
<artifactId>matrix</artifactId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
<packaging>pom</packaging>
......@@ -17,13 +17,12 @@
<module>mybatis-starter</module>
<module>mongodb-starter</module>
<module>elasticsearch-starter</module>
<module>dubbo-starter</module>
<module>web-starter</module>
<module>openfeign-starter</module>
<module>rocketmq-starter</module>
<module>monitor-starter</module>
<module>config-starter</module>
<module>logger-starter</module>
<module>protocol-starter</module>
</modules>
<parent>
......@@ -35,131 +34,78 @@
<properties>
<java.version>1.8</java.version>
<dubbo.version>2.7.1</dubbo.version>
<dubbo-starter.version>2.7.1</dubbo-starter.version>
<dubbo.version>2.7.2</dubbo.version>
<matrix.version>1.0.1-DEV-SNAPSHOT</matrix.version>
</properties>
<profiles>
<profile>
<id>dev</id>
<properties>
<ver_type>-DEV-SNAPSHOT</ver_type>
<repo_id>secoo-dev</repo_id>
<repo_name>secoo-dev-repository</repo_name>
<repo_url>nexus.secoo.com:8081/nexus/content/repositories/secoo-hosted-dev/</repo_url>
</properties>
<distributionManagement>
<repository>
<id>${repo_id}</id>
<name>${repo_name}</name>
<url>http://secoo-dev:secoo-dev@${repo_url}</url>
</repository>
</distributionManagement>
</profile>
<profile>
<id>test</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<ver_type>-SNAPSHOT</ver_type>
<repo_id>secoo-test</repo_id>
<repo_name>secoo-test-repository</repo_name>
<repo_url>nexus.secoo.com:8081/nexus/content/repositories/secoo-hosted-test/</repo_url>
</properties>
<distributionManagement>
<repository>
<id>${repo_id}</id>
<name>${repo_name}</name>
<url>http://secoo-test:secoo-test@${repo_url}</url>
</repository>
</distributionManagement>
</profile>
<profile>
<id>pro</id>
<properties>
<ver_type>.RELEASE</ver_type>
<repo_id>secoo-pro</repo_id>
<repo_name>secoo-pro-repository</repo_name>
<repo_url>nexus.secoo.com:8081/nexus/content/repositories/secoo-hosted-pro/</repo_url>
</properties>
<distributionManagement>
<repository>
<id>${repo_id}</id>
<name>${repo_name}</name>
<url>http://secoo-pro:secoo-PRO@${repo_url}</url>
</repository>
</distributionManagement>
</profile>
</profiles>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>secoo-log-starter</artifactId>
<version>1.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>secoo-log</artifactId>
<version>1.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>monitor-starter</artifactId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>common-core</artifactId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>config-starter</artifactId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>common-util</artifactId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>redis-starter</artifactId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>mybatis-starter</artifactId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>mongodb-starter</artifactId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>elasticsearch-starter</artifactId>
<version>1.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>dubbo-starter</artifactId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>web-starter</artifactId>
<version>1.0.5.RELEASE</version>
<artifactId>protocol-starter</artifactId>
<version>1.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>rocketmq-starter</artifactId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>openfeign-starter</artifactId>
<version>1.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>logger-starter</artifactId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</dependency>
<dependency>
......@@ -224,11 +170,26 @@
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
<!--spring boot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Aapche Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<artifactId>dubbo-dependencies-bom</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo-starter.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
......@@ -281,11 +242,7 @@
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>swagger-dubbo</artifactId>
<version>2.0.1</version>
</dependency>
<!--spring cloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
......@@ -294,8 +251,15 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<!--appollo-->
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
......@@ -324,7 +288,20 @@
</plugin>
</plugins>
</pluginManagement>
</build>
<distributionManagement>
<snapshotRepository>
<id>secoo-dev</id>
<name>secoo-dev-repository</name>
<url>http://secoo-dev:secoo-dev@nexus.secoo.com:8081/nexus/content/repositories/secoo-hosted-dev/</url>
</snapshotRepository>
<repository>
<id>secoo-pro</id>
<name>secoo-pro-repository</name>
<url>http://secoo-pro:secoo-PRO@nexus.secoo.com:8081/nexus/content/repositories/secoo-hosted-pro/</url>
</repository>
</distributionManagement>
</project>
\ No newline at end of file
......@@ -5,16 +5,22 @@
<parent>
<artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbo-starter</artifactId>
<artifactId>protocol-starter</artifactId>
<dependencies>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>common-core</artifactId>
<artifactId>common-util</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--dubbo-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
......@@ -23,10 +29,26 @@
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<!--swagger2-->
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>swagger-dubbo</artifactId>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
</dependencies>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-core</artifactId>
<version>1.5.22</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.secoo.mall.web.config;
package com.secoo.mall.common.config;
import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI;
import com.secoo.mall.common.core.condition.ProdEnvCondition;
import com.secoo.mall.dubbo.swagger.annotations.EnableDubboSwagger;
import com.secoo.mall.web.annotation.ApiController;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
......@@ -15,11 +17,14 @@ import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
;
@Configuration
@EnableSwagger2
@EnableSwaggerBootstrapUI
@Conditional(ProdEnvCondition.class)
public class SwaggerConfig {
@EnableDubboSwagger
@ConditionalOnClass(ProdEnvCondition.class)
public class MatrixSwaggerAutoConfiguration {
@Value("${spring.application.name}")
private String appName;
......@@ -27,16 +32,27 @@ public class SwaggerConfig {
private String appVersion;
@Bean
public Docket createRestApi() {
public Docket createWebApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.groupName("SecooMall")
.groupName("web")
.select()
.apis(RequestHandlerSelectors.withClassAnnotation(ApiController.class))
.paths(PathSelectors.any())
.build();
}
public Docket createDubboApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.groupName("dubbo")
.select()
.apis(RequestHandlerSelectors.basePackage("com.deepoove.dubbo.provider.springboot"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title(appName + " RESTful APIs")
......@@ -44,4 +60,5 @@ public class SwaggerConfig {
.description("更多内容请关注:http://apims.siku.cn")
.build();
}
}
\ No newline at end of file
package com.secoo.mall.web.advice;
package com.secoo.mall.common.handler;
import com.secoo.mall.common.core.errorcode.CommonErrorCode;
import com.secoo.mall.common.core.exception.BusinessException;
......@@ -6,24 +6,14 @@ import com.secoo.mall.common.core.exception.ParameterException;
import com.secoo.mall.common.core.exception.SystemInternalException;
import com.secoo.mall.common.util.log.LoggerUtil;
import com.secoo.mall.common.util.response.ResponseUtil;
import com.secoo.mall.web.annotation.ApiController;
import com.secoo.mall.web.annotation.ApiIgnoreJson;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import javax.annotation.Resource;
@RestControllerAdvice(annotations = ApiController.class)
public class ControllerResponseAdvice implements ResponseBodyAdvice<Object> {
public class ProtocolExceptionHandler {
@Resource
private MessageSource messageSource;
......@@ -46,17 +36,11 @@ public class ControllerResponseAdvice implements ResponseBodyAdvice<Object> {
return ResponseUtil.getFailResponse(CommonErrorCode.SYSTEM_INTERNAL_EXCEPTION.getCode(), CommonErrorCode.SYSTEM_INTERNAL_EXCEPTION.getMsg());
}
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return AnnotationUtils.findAnnotation(methodParameter.getMethod(), ApiIgnoreJson.class) == null;
}
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
return ResponseUtil.getSuccessResponse(o);
}
private String getMsg(BusinessException e) {
if (messageSource == null) {
return e.getMsg();
}
return messageSource.getMessage(e.getMsg(), e.getArgs(), LocaleContextHolder.getLocale());
}
}
package com.secoo.mall.common.provider;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import springfox.documentation.spring.web.DocumentationCache;
import springfox.documentation.swagger.web.InMemorySwaggerResourcesProvider;
import springfox.documentation.swagger.web.SwaggerResource;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Primary
@Component
public class DefaultSwaggerResourcesProvider extends InMemorySwaggerResourcesProvider {
public DefaultSwaggerResourcesProvider(Environment environment, DocumentationCache documentationCache) {
super(environment, documentationCache);
}
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> swaggerResources = super.get();
swaggerResources.forEach(swaggerResource -> {
String name = swaggerResource.getName();
if (SwaggerConfigEnum.SwaggerConfigMap.containsKey(name)) {
swaggerResource.setLocation(SwaggerConfigEnum.SwaggerConfigMap.get(name).getLocation());
}
}
);
return swaggerResources;
}
private enum SwaggerConfigEnum {
DUBBO("dubbo", "/swagger-dubbo/api-docs");
private String name;
private String location;
private final static Map<String, SwaggerConfigEnum> SwaggerConfigMap = Arrays.stream(SwaggerConfigEnum.values()).collect(Collectors.toMap(SwaggerConfigEnum::getName, Function.identity()));
SwaggerConfigEnum(String name, String location) {
this.name = name;
this.location = location;
}
public String getName() {
return name;
}
public String getLocation() {
return location;
}
}
}
package com.secoo.mall.dubbo.filter;
import com.secoo.mall.common.core.exception.BusinessException;
import com.secoo.mall.common.core.exception.ParameterException;
import com.secoo.mall.common.core.exception.SystemInternalException;
import com.secoo.mall.common.handler.ProtocolExceptionHandler;
import com.secoo.mall.common.util.response.ResponseUtil;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import org.apache.dubbo.rpc.filter.ExceptionFilter;
import org.apache.dubbo.rpc.service.GenericService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.annotation.ExceptionHandlerMethodResolver;
import java.lang.reflect.Method;
@Activate(
group = {CommonConstants.PROVIDER}, order = 1000
)
public class DefaultExceptionFilter extends ExceptionFilter implements Filter {
private Logger log = LoggerFactory.getLogger(DefaultExceptionFilter.class);
public DefaultExceptionFilter() {
super.listener = new DefaultExceptionFilter.ExceptionListener();
}
static class ExceptionListener extends ProtocolExceptionHandler implements Listener {
private Logger logger = LoggerFactory.getLogger(ExceptionListener.class);
private ExceptionHandlerMethodResolver resolver;
public ExceptionListener() {
resolver = new ExceptionHandlerMethodResolver(this.getClass());
}
@Override
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
if (appResponse.hasException() && GenericService.class != invoker.getInterface()) {
Exception exception = getException(appResponse.getException());
Method method = resolver.resolveMethod(exception);
try {
Object realResult = method.invoke(this, exception);
appResponse.setValue(realResult);
} catch (Exception e) {
appResponse.setValue(ResponseUtil.getFailResponse(new SystemInternalException()));
}
appResponse.setException(null);
}
}
@Override
public void onError(Throwable e, Invoker<?> invoker, Invocation invocation) {
logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
}
private Exception getException(Throwable throwable) {
Exception exception = null;
String className = throwable.getClass().getSimpleName();
switch (className) {
case "BusinessException":
exception = (BusinessException) throwable;
break;
case "SystemInternalException":
exception = (SystemInternalException) throwable;
break;
case "ParameterException":
exception = (ParameterException) throwable;
break;
default:
exception = (Exception) throwable;
}
return exception;
}
}
}
package com.secoo.mall.dubbo.swagger.annotations;
import org.springframework.context.annotation.ComponentScan;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = {java.lang.annotation.ElementType.TYPE})
@Documented
@ComponentScan(basePackages = {"com.secoo.mall.dubbo.swagger.config",
"com.secoo.mall.dubbo.swagger.controller", "com.secoo.mall.common.provider"})
public @interface EnableDubboSwagger {
}
package com.secoo.mall.dubbo.swagger.config;
import com.secoo.mall.dubbo.swagger.http.ReferenceManager;
import io.swagger.config.SwaggerConfig;
import io.swagger.models.Contact;
import io.swagger.models.Info;
import io.swagger.models.Swagger;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.ApplicationConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.ServletContext;
import java.text.MessageFormat;
@Component
public class DubboPropertyConfig implements SwaggerConfig {
@Value("${swagger.dubbo.application.version:}")
private String version;
@Value("${swagger.dubbo.application.groupId:}")
private String groupId;
@Value("${swagger.dubbo.application.artifactId:}")
private String artifactId;
@Autowired
private ServletContext servletContext;
private static String mavenDependency = "&lt;dependency&gt;<br/>"
+ "&nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;{0}&lt;/groupId&gt;<br/>"
+ "&nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;{1}&lt;/artifactId&gt;<br/>"
+ "&nbsp;&nbsp;&nbsp;&nbsp;&lt;version&gt;{2}&lt;/version&gt;<br/>"
+ "&lt;/dependency&gt;<br/>";
@Override
public Swagger configure(Swagger swagger) {
ApplicationConfig application = ReferenceManager.getInstance().getApplication();
if (null != application) {
Info info = swagger.getInfo();
if (info == null) {
info = new Info();
swagger.setInfo(info);
}
info.setTitle(application.getName());
version = StringUtils.isNotBlank(version) ? version : application.getVersion();
if (StringUtils.isNotBlank(groupId)
&& StringUtils.isNotBlank(artifactId)
&& StringUtils.isNotBlank(version)) {
info.setDescription(MessageFormat.format(mavenDependency, groupId, artifactId, version));
}
info.setVersion(StringUtils.isNotBlank(version) ? version : "");
Contact contact = new Contact();
info.setContact(contact);
contact.setName(application.getOwner());
}
setBashPath(swagger);
return swagger;
}
private void setBashPath(Swagger swagger) {
if (StringUtils.isEmpty(swagger.getBasePath())) {
swagger.setBasePath(StringUtils.isEmpty(servletContext.getContextPath()) ? "/" : servletContext.getContextPath());
}
}
@Override
public String getFilterClass() {
return null;
}
}
package com.secoo.mall.dubbo.swagger.config;
import com.secoo.mall.dubbo.swagger.http.ReferenceManager;
import io.swagger.config.Scanner;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Set;
@Component
public class DubboServiceScanner implements Scanner {
@Override
public Set<Class<?>> classes() {
return interfaceMapRef().keySet();
}
public Map<Class<?>, Object> interfaceMapRef() {
return ReferenceManager.getInstance().getInterfaceMapRef();
}
@Override
public boolean getPrettyPrint() {
return false;
}
@Override
public void setPrettyPrint(boolean shouldPrettyPrint) {
}
}
package com.secoo.mall.dubbo.swagger.config;
import io.swagger.models.Swagger;
import org.springframework.stereotype.Component;
@Component
public class SwaggerDocCache {
private Swagger swagger;
public Swagger getSwagger() {
return swagger;
}
public void setSwagger(Swagger swagger) {
this.swagger = swagger;
}
}
package com.secoo.mall.dubbo.swagger.controller;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.secoo.mall.dubbo.swagger.http.HttpMatch;
import com.secoo.mall.dubbo.swagger.http.ReferenceManager;
import com.secoo.mall.dubbo.swagger.reader.NameDiscover;
import io.swagger.annotations.Api;
import io.swagger.util.Json;
import io.swagger.util.PrimitiveType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map.Entry;
@Controller
@RequestMapping("${swagger.dubbo.http:h}")
@Api(hidden = true)
public class DubboHttpController {
private static Logger logger = LoggerFactory.getLogger(DubboHttpController.class);
private static final String CLUSTER_RPC = "rpc";
@Value("${swagger.dubbo.enable:true}")
private boolean enable = true;
@Value("${swagger.dubbo.cluster:rpc}")
private String cluster = CLUSTER_RPC;
@RequestMapping(value = "/{interfaceClass}/{methodName}", produces = "application/json; charset=utf-8")
@ResponseBody
public ResponseEntity<String> invokeDubbo(@PathVariable("interfaceClass") String interfaceClass,
@PathVariable("methodName") String methodName, HttpServletRequest request,
HttpServletResponse response) throws Exception {
return invokeDubbo(interfaceClass, methodName, null, request, response);
}
@RequestMapping(value = "/{interfaceClass}/{methodName}/{operationId}", produces = "application/json; charset=utf-8")
@ResponseBody
public ResponseEntity<String> invokeDubbo(@PathVariable("interfaceClass") String interfaceClass,
@PathVariable("methodName") String methodName,
@PathVariable("operationId") String operationId, HttpServletRequest request,
HttpServletResponse response) throws Exception {
if (!enable) {
return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
}
Object ref = null;
Method method = null;
Object result = null;
Entry<Class<?>, Object> entry = ReferenceManager.getInstance().getRef(interfaceClass);
if (null == entry) {
logger.info("No Ref Service FOUND.");
return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
}
ref = entry.getValue();
HttpMatch httpMatch = new HttpMatch(entry.getKey(), ref.getClass());
Method[] interfaceMethods = httpMatch.findInterfaceMethods(methodName);
if (null != interfaceMethods && interfaceMethods.length > 0) {
Method[] refMethods = httpMatch.findRefMethods(interfaceMethods, operationId,
request.getMethod());
method = httpMatch.matchRefMethod(refMethods, methodName, request.getParameterMap().keySet());
}
if (null == method) {
logger.info("No Service Method FOUND.");
return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
}
String[] parameterNames = NameDiscover.parameterNameDiscover.getParameterNames(method);
logger.info("[Swagger-dubbo] Invoke by " + cluster);
if (CLUSTER_RPC.equals(cluster)) {
ref = ReferenceManager.getInstance().getProxy(interfaceClass);
if (null == ref) {
logger.info("No Ref Proxy Service FOUND.");
return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
}
method = ref.getClass().getMethod(method.getName(), method.getParameterTypes());
if (null == method) {
logger.info("No Proxy Service Method FOUND.");
return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
}
}
logger.debug("[Swagger-dubbo] Invoke dubbo service method:{},parameter:{}", method, Json.pretty(request.getParameterMap()));
if (null == parameterNames || parameterNames.length == 0) {
result = method.invoke(ref);
} else {
Object[] args = new Object[parameterNames.length];
Type[] parameterTypes = method.getGenericParameterTypes();
Class<?>[] parameterClazz = method.getParameterTypes();
for (int i = 0; i < parameterNames.length; i++) {
Object suggestPrameterValue = suggestPrameterValue(parameterTypes[i],
parameterClazz[i], request.getParameter(parameterNames[i]));
args[i] = suggestPrameterValue;
}
result = method.invoke(ref, args);
}
return ResponseEntity.ok(Json.mapper().writeValueAsString(result));
}
private Object suggestPrameterValue(Type type, Class<?> cls, String parameter)
throws JsonParseException, JsonMappingException, IOException {
PrimitiveType fromType = PrimitiveType.fromType(type);
if (null != fromType) {
DefaultConversionService service = new DefaultConversionService();
boolean actual = service.canConvert(String.class, cls);
if (actual) {
return service.convert(parameter, cls);
}
} else {
if (null == parameter) return null;
try {
return Json.mapper().readValue(parameter, cls);
} catch (Exception e) {
throw new IllegalArgumentException("The parameter value [" + parameter + "] should be json of [" + cls.getName() + "] Type.", e);
}
}
try {
return Class.forName(cls.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
package com.secoo.mall.dubbo.swagger.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.secoo.mall.dubbo.swagger.config.DubboPropertyConfig;
import com.secoo.mall.dubbo.swagger.config.DubboServiceScanner;
import com.secoo.mall.dubbo.swagger.config.SwaggerDocCache;
import com.secoo.mall.dubbo.swagger.reader.Reader;
import io.swagger.annotations.Api;
import io.swagger.config.SwaggerConfig;
import io.swagger.models.Swagger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import springfox.documentation.spring.web.json.Json;
import java.util.Map;
@Controller
@RequestMapping("${swagger.dubbo.doc:swagger-dubbo}")
@Api(hidden = true)
public class SwaggerDubboController {
public static final String DEFAULT_URL = "/api-docs";
private static final String HAL_MEDIA_TYPE = "application/hal+json";
@Autowired
private DubboServiceScanner dubboServiceScanner;
@Autowired
private DubboPropertyConfig dubboPropertyConfig;
@Autowired
private SwaggerDocCache swaggerDocCache;
@Value("${swagger.dubbo.http:h}")
private String httpContext;
@Value("${swagger.dubbo.enable:true}")
private boolean enable = true;
@RequestMapping(value = DEFAULT_URL,
method = RequestMethod.GET,
produces = {"application/json; charset=utf-8", HAL_MEDIA_TYPE})
@ResponseBody
public ResponseEntity<Json> getApiList() throws JsonProcessingException {
if (!enable) {
return new ResponseEntity<Json>(HttpStatus.NOT_FOUND);
}
Swagger swagger = swaggerDocCache.getSwagger();
if (null != swagger) {
return new ResponseEntity<Json>(new Json(io.swagger.util.Json.mapper().writeValueAsString(swagger)), HttpStatus.OK);
} else {
swagger = new Swagger();
}
final SwaggerConfig configurator = dubboPropertyConfig;
if (configurator != null) {
configurator.configure(swagger);
}
Map<Class<?>, Object> interfaceMapRef = dubboServiceScanner.interfaceMapRef();
if (null != interfaceMapRef) {
Reader.read(swagger, interfaceMapRef, httpContext);
}
swaggerDocCache.setSwagger(swagger);
return new ResponseEntity<Json>(new Json(io.swagger.util.Json.mapper().writeValueAsString(swagger)), HttpStatus.OK);
}
}
package com.secoo.mall.dubbo.swagger.http;
import com.secoo.mall.dubbo.swagger.reader.NameDiscover;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.HttpMethod;
import io.swagger.util.ReflectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.util.*;
public class HttpMatch {
private static Logger logger = LoggerFactory.getLogger(HttpMatch.class);
private Class<?> interfaceClass;
private Class<?> refClass;
public HttpMatch(Class<?> interfaceClass, Class<?> refClass) {
this.interfaceClass = interfaceClass;
this.refClass = refClass;
}
public Method[] findInterfaceMethods(String methodName) {
Method[] methods = interfaceClass.getMethods();
List<Method> ret = new ArrayList<Method>();
for (Method method : methods) {
if (method.getName().equals(methodName)) ret.add(method);
}
return ret.toArray(new Method[]{});
}
public Method[] findRefMethods(Method[] interfaceMethods, String operationId,
String requestMethod) {
List<Method> ret = new ArrayList<Method>();
for (Method method : interfaceMethods) {
Method m;
try {
m = refClass.getMethod(method.getName(), method.getParameterTypes());
final ApiOperation apiOperation = ReflectionUtils.getAnnotation(m,
ApiOperation.class);
String nickname = null == apiOperation ? null : apiOperation.nickname();
if (operationId != null) {
if (!operationId.equals(nickname)) continue;
} else {
if (StringUtils.isNotBlank(nickname)) continue;
}
if (requestMethod != null) {
String httpMethod = null == apiOperation ? null : apiOperation.httpMethod();
if (StringUtils.isNotBlank(httpMethod) && !requestMethod.equals(httpMethod))
continue;
if (StringUtils.isBlank(httpMethod)
&& !requestMethod.equalsIgnoreCase(HttpMethod.POST.name()))
continue;
}
ret.add(m);
} catch (NoSuchMethodException e) {
logger.error("NoSuchMethodException", e);
} catch (SecurityException e) {
logger.error("SecurityException", e);
}
}
return ret.toArray(new Method[]{});
}
public Method matchRefMethod(Method[] refMethods, String methodName, Set<String> keySet) {
if (refMethods.length == 0) {
return null;
}
if (refMethods.length == 1) {
return refMethods[0];
}
List<RateMethod> rateMethods = new ArrayList<RateMethod>();
for (Method method : refMethods) {
String[] parameterNames = NameDiscover.parameterNameDiscover
.getParameterNames(method);
if (parameterNames == null) return method;
float correctRate = 0.0f;
int hit = 0;
int error = 0;
for (String paramName : parameterNames) {
if (keySet.contains(paramName)) hit++;
else error++;
}
correctRate = error / (float) hit;
rateMethods.add(new RateMethod(method, (int) correctRate * 100));
}
if (rateMethods.isEmpty()) return null;
Collections.sort(rateMethods, new Comparator<RateMethod>() {
@Override
public int compare(RateMethod o1, RateMethod o2) {
return o2.getRate() - o1.getRate();
}
});
return rateMethods.get(0).getMethod();
}
class RateMethod {
private Method method;
private int rate;
public RateMethod(Method method, int rate) {
this.method = method;
this.rate = rate;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public int getRate() {
return rate;
}
public void setRate(int rate) {
this.rate = rate;
}
}
}
package com.secoo.mall.dubbo.swagger.http;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.spring.ServiceBean;
import org.apache.dubbo.config.spring.extension.SpringExtensionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class ReferenceManager {
private static Logger logger = LoggerFactory.getLogger(ReferenceManager.class);
@SuppressWarnings("rawtypes")
private static Collection<ServiceBean> services;
private static Map<Class<?>, Object> interfaceMapProxy = new ConcurrentHashMap<Class<?>, Object>();
private static Map<Class<?>, Object> interfaceMapRef = new ConcurrentHashMap<Class<?>, Object>();
private static ReferenceManager instance;
private static ApplicationConfig application;
private ReferenceManager() {
}
@SuppressWarnings({"rawtypes", "unchecked"})
public synchronized static ReferenceManager getInstance() {
if (null != instance) return instance;
instance = new ReferenceManager();
services = new HashSet<ServiceBean>();
try {
/* Field field = SpringExtensionFactory.class.getDeclaredField("contexts");
field.setAccessible(true);*/
Set<ApplicationContext> contexts = SpringExtensionFactory.getContexts();
for (ApplicationContext context : contexts) {
services.addAll(context.getBeansOfType(ServiceBean.class).values());
}
} catch (Exception e) {
logger.error("Get All Dubbo Service Error", e);
return instance;
}
for (ServiceBean<?> bean : services) {
interfaceMapRef.putIfAbsent(bean.getInterfaceClass(), bean.getRef());
}
//
if (!services.isEmpty()) {
ServiceBean<?> bean = services.toArray(new ServiceBean[]{})[0];
application = bean.getApplication();
}
return instance;
}
public Object getProxy(String interfaceClass) {
Set<Entry<Class<?>, Object>> entrySet = interfaceMapProxy.entrySet();
for (Entry<Class<?>, Object> entry : entrySet) {
if (entry.getKey().getName().equals(interfaceClass)) {
return entry.getValue();
}
}
for (ServiceBean<?> service : services) {
if (interfaceClass.equals(service.getInterfaceClass().getName())) {
ReferenceConfig<Object> reference = new ReferenceConfig<Object>();
reference.setApplication(service.getApplication());
reference.setRegistry(service.getRegistry());
reference.setRegistries(service.getRegistries());
reference.setInterface(service.getInterfaceClass());
reference.setVersion(service.getVersion());
interfaceMapProxy.put(service.getInterfaceClass(), reference.get());
return reference.get();
}
}
return null;
}
public Entry<Class<?>, Object> getRef(String interfaceClass) {
Set<Entry<Class<?>, Object>> entrySet = interfaceMapRef.entrySet();
for (Entry<Class<?>, Object> entry : entrySet) {
if (entry.getKey().getName().equals(interfaceClass)) {
return entry;
}
}
return null;
}
@SuppressWarnings("rawtypes")
public Collection<ServiceBean> getServices() {
return services;
}
public ApplicationConfig getApplication() {
return application;
}
public Map<Class<?>, Object> getInterfaceMapRef() {
return interfaceMapRef;
}
}
package com.secoo.mall.dubbo.swagger.reader;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.PrioritizedParameterNameDiscoverer;
import org.springframework.core.StandardReflectionParameterNameDiscoverer;
public final class NameDiscover {
public static final ParameterNameDiscoverer parameterNameDiscover;
static {
parameterNameDiscover = new PrioritizedParameterNameDiscoverer();
((PrioritizedParameterNameDiscoverer) parameterNameDiscover)
.addDiscoverer(new LocalVariableTableParameterNameDiscoverer());
((PrioritizedParameterNameDiscoverer) parameterNameDiscover)
.addDiscoverer(new StandardReflectionParameterNameDiscoverer());
}
}
package com.secoo.mall.dubbo.swagger.reader;
import io.swagger.models.Swagger;
import io.swagger.models.parameters.Parameter;
import java.util.List;
/**
* The <code>ReaderContext</code> class is wrapper for the <code>Reader</code>
* parameters.
*/
public class ReaderContext {
private Swagger swagger;
private Class<?> refCls;
private Class<?> interfaceCls;
private String parentPath;
private String parentHttpMethod;
private boolean readHidden;
private List<String> parentConsumes;
private List<String> parentProduces;
private List<String> parentTags;
private List<Parameter> parentParameters;
public ReaderContext(Swagger swagger, Class<?> refCls, Class<?> interfaceCls, String parentPath,
String parentHttpMethod, boolean readHidden, List<String> parentConsumes,
List<String> parentProduces, List<String> parentTags,
List<Parameter> parentParameters) {
setSwagger(swagger);
setRefCls(refCls);
setInterfaceCls(interfaceCls);
setParentPath(parentPath);
setParentHttpMethod(parentHttpMethod);
setReadHidden(readHidden);
setParentConsumes(parentConsumes);
setParentProduces(parentProduces);
setParentTags(parentTags);
setParentParameters(parentParameters);
}
public Swagger getSwagger() {
return swagger;
}
public void setSwagger(Swagger swagger) {
this.swagger = swagger;
}
public Class<?> getRefCls() {
return refCls;
}
public void setRefCls(Class<?> cls) {
this.refCls = cls;
}
public Class<?> getInterfaceCls() {
return interfaceCls;
}
public Class<?> getCls() {
return refCls;
}
public void setInterfaceCls(Class<?> interfaceCls) {
this.interfaceCls = interfaceCls;
}
public String getParentPath() {
return parentPath;
}
public void setParentPath(String parentPath) {
this.parentPath = parentPath;
}
public String getParentHttpMethod() {
return parentHttpMethod;
}
public void setParentHttpMethod(String parentHttpMethod) {
this.parentHttpMethod = parentHttpMethod;
}
public boolean isReadHidden() {
return readHidden;
}
public void setReadHidden(boolean readHidden) {
this.readHidden = readHidden;
}
public List<String> getParentConsumes() {
return parentConsumes;
}
public void setParentConsumes(List<String> parentConsumes) {
this.parentConsumes = parentConsumes;
}
public List<String> getParentProduces() {
return parentProduces;
}
public void setParentProduces(List<String> parentProduces) {
this.parentProduces = parentProduces;
}
public List<String> getParentTags() {
return parentTags;
}
public void setParentTags(List<String> parentTags) {
this.parentTags = parentTags;
}
public List<Parameter> getParentParameters() {
return parentParameters;
}
public void setParentParameters(List<Parameter> parentParameters) {
this.parentParameters = parentParameters;
}
}
package com.secoo.mall.dubbo.swagger.reader;
import io.swagger.models.Operation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
/**
* The <code>ReaderExtension</code> interface defines methods for scans resources for Swagger.
*/
public interface ReaderExtension {
/**
* Returns this extension's priority.
* Note: Extension will be executed first with lowest priority.
*
* @return this extension's priority
*/
int getPriority();
/**
* Checks that a resource should be scanned.
*
* @param context is the resource context
* @return true if the resource needs to be scanned, otherwise false
*/
boolean isReadable(ReaderContext context);
/**
* Reads the consumes from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applyConsumes(ReaderContext context, Operation operation, Method method);
/**
* Reads the produces from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applyProduces(ReaderContext context, Operation operation, Method method);
/**
* Returns http method.
*
* @param context is the resource context
* @param method is the method for reading annotations
* @return http method
*/
String getHttpMethod(ReaderContext context, Method method);
/**
* Returns operation's path.
*
* @param context is the resource context
* @param method is the method for reading annotations
* @return operation's path
*/
String getPath(ReaderContext context, Method method);
/**
* Reads the operation id from the method's annotations and applies it to the operation.
*
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applyOperationId(Operation operation, Method method);
/**
* Reads the summary from the method's annotations and applies it to the operation.
*
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applySummary(Operation operation, Method method);
/**
* Reads the description from the method's annotations and applies it to the operation.
*
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applyDescription(Operation operation, Method method);
/**
* Reads the schemes from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applySchemes(ReaderContext context, Operation operation, Method method);
/**
* Sets the deprecated flag to the operation.
*
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void setDeprecated(Operation operation, Method method);
/**
* Reads the security requirement from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applySecurityRequirements(ReaderContext context, Operation operation, Method method);
/**
* Reads the tags from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applyTags(ReaderContext context, Operation operation, Method method);
/**
* Reads the responses from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applyResponses(ReaderContext context, Operation operation, Method method);
/**
* Reads the parameters from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param type is the type of parameter
* @param annotations are the method's annotations
*/
void applyParameters(ReaderContext context, Operation operation, Type type, Annotation[] annotations);
/**
* Reads the implicit parameters from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applyImplicitParameters(ReaderContext context, Operation operation, Method method);
/**
* Reads the extensions from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applyExtensions(ReaderContext context, Operation operation, Method method);
void applyParameters(ReaderContext context, Operation operation, Method method,
Method interfaceMethod);
}
package com.secoo.mall.web.advice;
import com.secoo.mall.common.handler.ProtocolExceptionHandler;
import com.secoo.mall.common.util.response.ResponseUtil;
import com.secoo.mall.web.annotation.ApiController;
import com.secoo.mall.web.annotation.ApiIgnoreJson;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@RestControllerAdvice(annotations = ApiController.class)
public class ControllerResponseAdvice extends ProtocolExceptionHandler implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return AnnotationUtils.findAnnotation(methodParameter.getMethod(), ApiIgnoreJson.class) == null;
}
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
return ResponseUtil.getSuccessResponse(o);
}
}
exception=com.secoo.mall.dubbo.filter.DefaultExceptionFilter
\ No newline at end of file
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.secoo.mall.common.config.MatrixSwaggerAutoConfiguration
\ No newline at end of file
......@@ -5,24 +5,30 @@
<parent>
<artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>redis-starter</artifactId>
<dependencies>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>common-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.secoo.mall.redis.config;
import com.secoo.mall.redis.utils.MatrixRedisClusterUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* Created by QIANG
*
* @author QIANG
*/
@Configuration
public class MatrixeRedisAutoConfiguration {
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisSerializer stringSerializer = new StringRedisSerializer();
RedisTemplate<String, String> redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setHashValueSerializer(stringSerializer);
return redisTemplate;
}
@Bean
@ConditionalOnMissingBean(MatrixRedisClusterUtils.class)
public MatrixRedisClusterUtils jedisClusterUtils() {
return new MatrixRedisClusterUtils();
}
}
package com.secoo.mall.redis.utils;
import com.alibaba.fastjson.JSON;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* @author QIANG
*/
public class MatrixRedisClusterUtils {
private static MatrixRedisClusterUtils cacheUtils;
@Resource
private RedisTemplate<String, String> redisTemplate;
public static RedisTemplate<String, String> getRedisTemplate() {
return cacheUtils.redisTemplate;
}
public static ValueOperations<String, String> opsForValue() {
return cacheUtils.redisTemplate.opsForValue();
}
public static String getAndSet(String key, String value) {
return cacheUtils.redisTemplate.opsForValue().getAndSet(key, value);
}
public static void set(String key, String val, long timeout, TimeUnit unit) {
cacheUtils.redisTemplate.opsForValue().set(key, val, timeout, unit);
}
public static ListOperations<String, String> opsForList() {
return cacheUtils.redisTemplate.opsForList();
}
public static ZSetOperations<String, String> opsForZSet() {
return cacheUtils.redisTemplate.opsForZSet();
}
public static HashOperations<String, Object, Object> opsForHash() {
return cacheUtils.redisTemplate.opsForHash();
}
public static ClusterOperations<String, String> opsForCluster() {
return cacheUtils.redisTemplate.opsForCluster();
}
public static GeoOperations<String, String> opsForGeo() {
return cacheUtils.redisTemplate.opsForGeo();
}
public static HyperLogLogOperations<String, String> opsForHyperLogLog() {
return cacheUtils.redisTemplate.opsForHyperLogLog();
}
public static SetOperations<String, String> opsForSet() {
return cacheUtils.redisTemplate.opsForSet();
}
/**
* 设置超时时间
*
* @param key
*/
public static boolean expire(String key, long timeout, TimeUnit unit) {
return cacheUtils.redisTemplate.expire(key, timeout, unit);
}
/**
* 将数据存入缓存
*
* @param key
* @param val
* @return
*/
public static void set(String key, String val) {
cacheUtils.redisTemplate.opsForValue().set(key, val);
}
/**
* setNx
*
* @param key
* @param val
* @return
*/
public static boolean setIfAbsent(String key, String val) {
return cacheUtils.redisTemplate.opsForValue().setIfAbsent(key, val);
}
/**
* 保存复杂类型数据到缓存
*
* @param key
* @param obj
* @return
*/
public static void set(String key, Object obj) {
cacheUtils.redisTemplate.opsForValue().set(key, JSON.toJSONString(obj));
}
/**
* @param key 缓存Key
* @return keyValue
*/
public static String opsForSet(String key) {
return cacheUtils.redisTemplate.opsForSet().pop(key);
}
/**
* 将数据存入缓存的集合中
*
* @param key
* @param val
* @return
*/
public static void add(String key, String val) {
cacheUtils.redisTemplate.opsForSet().add(key, val);
}
public static RedisConnectionFactory getConnectionFactory() {
return cacheUtils.redisTemplate.getConnectionFactory();
}
/**
* 保存到hash集合中
*
* @param hName 集合名
* @param key
*/
public static void put(String hName, String key, String value) {
cacheUtils.redisTemplate.opsForHash().put(hName, key, value);
}
/**
* 存储多维数据
*
* @param key
* @param data
*/
public static void putAll(String key, Map<String, String> data) {
cacheUtils.redisTemplate.opsForHash().putAll(key, data);
}
/**
* 为哈希表 key 中的域 field 的值加上增量 increment
*
* @param hName
* @param key
* @param value
*/
public static Long increment(String hName, String key, long value) {
return cacheUtils.redisTemplate.opsForHash().increment(hName, key, value);
}
/**
* 根据key获取所以值
*
* @param key
* @return
*/
public static Map<Object, Object> entries(String key) {
return cacheUtils.redisTemplate.opsForHash().entries(key);
}
/**
* 从缓存中取得字符串数据
*
* @param key
* @return 数据
*/
public static String get(String key) {
return cacheUtils.redisTemplate.opsForValue().get(key);
}
/**
* 获取set集合交集opsForSet
*
* @param key
* @param skey
* @return
*/
public static Set<String> intersect(String key, String skey) {
return cacheUtils.redisTemplate.opsForSet().intersect(key, skey);
}
/**
* 获取集合元素数量
*
* @return
*/
public static Long scard(String key) {
return cacheUtils.redisTemplate.opsForSet().size(key);
}
/**
* 返回集合 key 中的所有成员
* opsForSet().members(key)
* @param key set名
*/
public static Set<String> members(String key) {
return cacheUtils.redisTemplate.opsForSet().members(key);
}
/**
* 移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略。
* opsForSet().remove(key,member)
*/
public static Long srem(String key, String... member) {
return cacheUtils.redisTemplate.opsForSet().remove(key,member);
}
@PostConstruct
public void init() {
cacheUtils = this;
cacheUtils.redisTemplate = redisTemplate;
}
}
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.secoo.mall.redis.config.MatrixeRedisAutoConfiguration
\ No newline at end of file
......@@ -5,7 +5,7 @@
<parent>
<artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.0.5.RELEASE</version>
<version>1.0.8.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
......
package com.secoo.mall.mq.config;
import com.secoo.mall.mq.hook.MatrixConsumeHook;
import org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author qianglu
*/
@Configuration
public class MatrixListenerContainerConfiguration implements BeanPostProcessor {
private final static Logger log = LoggerFactory.getLogger(MatrixListenerContainerConfiguration.class);
@Bean
MatrixConsumeHook matrixConsumeHook(){
return new MatrixConsumeHook();
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof DefaultRocketMQListenerContainer){
DefaultRocketMQListenerContainer container = (DefaultRocketMQListenerContainer)bean;
container.getConsumer().getDefaultMQPushConsumerImpl().registerConsumeMessageHook(matrixConsumeHook());
}
return bean;
}
}
package com.secoo.mall.mq.hook;
import org.apache.rocketmq.client.hook.ConsumeMessageContext;
import org.apache.rocketmq.client.hook.ConsumeMessageHook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author qianglu
*/
public class MatrixConsumeHook implements ConsumeMessageHook {
private final static Logger log = LoggerFactory.getLogger(MatrixConsumeHook.class);
@Override
public String hookName() {
return "MatrixConsumeHook";
}
@Override
public void consumeMessageBefore(ConsumeMessageContext context) {
}
@Override
public void consumeMessageAfter(ConsumeMessageContext context) {
try {
log.info("consumeMessageAfter,Succ:{} Topic:{},TraceContext:{},ConsumerGroup:{}",context.isSuccess(),context.getMq().getTopic(),context.getMqTraceContext(),context.getConsumerGroup());
} catch (Exception e) {//防灾冗余
}
}
}
package com.secoo.mall.mq.hook;
import org.apache.rocketmq.client.hook.SendMessageContext;
import org.apache.rocketmq.client.hook.SendMessageHook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author qianglu
*/
public class MatrixProducerHook implements SendMessageHook {
private final static Logger log = LoggerFactory.getLogger(MatrixProducerHook.class);
@Override
public String hookName() {
return "MatrixProducerHook";
}
@Override
public void sendMessageBefore(SendMessageContext context) {
}
@Override
public void sendMessageAfter(SendMessageContext context) {
try {
log.info("sendMessageAfter,Mid:{},Mode:{},Topic:{},Targs:{},ProducerGroup:{},BrokerAddr:{},Namespace:{},Exception:{}", context.getMessage().getProperties().get("id"), context.getCommunicationMode().name(), context.getMessage().getTopic(), context.getMessage().getTags(), context.getProducerGroup(), context.getBrokerAddr(), context.getNamespace(), context.getException()==null?null:context.getException().getMessage());
} catch (Exception e) {//防灾冗余}
}
}
}
\ No newline at end of file
package com.secoo.mall.mq.producer;
import org.apache.rocketmq.client.hook.SendMessageHook;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.remoting.RPCHook;
/**
* @author qianglu
*/
public class MartixProducer extends DefaultMQProducer {
public MartixProducer(final String producerGroup, RPCHook rpcHook, boolean enableMsgTrace,
final String customizedTraceTopic, SendMessageHook messageHook) {
super(producerGroup, rpcHook, enableMsgTrace, customizedTraceTopic);
this.defaultMQProducerImpl.registerSendMessageHook(messageHook);
}
public MartixProducer(final String producerGroup, boolean enableMsgTrace, final String customizedTraceTopic, SendMessageHook messageHook) {
super(producerGroup, enableMsgTrace, customizedTraceTopic);
this.defaultMQProducerImpl.registerSendMessageHook(messageHook);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment