1、使用sleuth+zipkin 实现链路追踪服务(前提)
Pom.xml
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.adou.usermanage.zipkin</groupId>
<artifactId>usermanage-zipkin</artifactId>
<version>1.0.0</version>
<!-- spring boot配置 -->
<parent>
<groupId>com.adou.usermange</groupId>
<artifactId>usermange-parent</artifactId>
<version>1.0.0</version>
</parent>
<dependencies>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
application.yml
server:
port: 9411
spring:
application:
name: usermanage-zipkin
cloud:
consul:
host: localhost
port: 8500
discovery:
instance-id: ${spring.application.name}:${spring.cloud.client.ipAddress}:${spring.application.instance_id:${server.port}}
service-name: usermanage-zipkin
主类注解添加
@SpringBootApplication
@EnableZipkinServer
public class ZipkinApplication {
public static void main(String[] args) {
SpringApplication.run(ZipkinApplication.class, args);
}
}
(*)其他服务中调用
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
修改配置文件,bootstrap.yml
spring:
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
percentage: 1.0
启动服务,访问zipkin的控制台http://localhost:9411
2、嵌入式 SDK 来注册和发现服务
a、新建父工程usermange-parent
Pom.xml(pom)
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.adou.usermange</groupId>
<artifactId>usermange-parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<parent>
<env>beta</env>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath />
</parent>
<properties>
<mybatis-spring-boot-starter.version>1.1.1</mybatis-spring-boot-starter.version>
<pagehelper.version>4.2.1</pagehelper.version>
<springfox.version>2.5.0</springfox.version>
<cglib.version>2.2</cglib.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot-starter.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>${pagehelper.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox.version}</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>${cglib.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>usermanage-provider</module>
<module>usermanage-api</module>
<module>usermanage-web</module>
</modules>
</project>
b、新建服务提供者客户端usermanage-api
Pom.xml
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.adou.usermange</groupId>
<artifactId>usermange-parent</artifactId>
<version>1.0.0</version>
</parent>
<groupId>com.adou.usermange.api</groupId>
<artifactId>usermanage-api</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
</dependency>
</dependencies>
</project>
UserDto.java
public class UserDto implements Serializable {
private static final long serialVersionUID = 1L;
private Long userId;
private String userName;
public UserDto() {
}
public UserDto(Long userId, String userName) {
this.userId = userId;
this.userName = userName;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Override
public String toString() {
return "UserDto [userId=" + userId + ", userName=" + userName + "]";
}
}
UserService2.java
@FeignClient(name = "usermanage-provider"/*, path = "microservice-user-provider", fallback = UserServiceFallback.class*/)
public interface UserService2 {
@RequestMapping(value = "/user", method = RequestMethod.POST)
public UserDto insert(@RequestBody UserDto userDto);
@RequestMapping(value = "/user/{userId}", method = RequestMethod.DELETE)
public Integer deleteById(@PathVariable("userId") Long userId);
@RequestMapping(value = "/user", method = RequestMethod.PUT)
public Integer update(@RequestBody UserDto userDto);
@RequestMapping(value = "/user/{userId}", method = RequestMethod.GET)
public UserDto queryById(@PathVariable("userId") Long userId);
@RequestMapping(value = "/user/list", method = RequestMethod.GET)
public List<UserDto> queryForList();
@RequestMapping(value = "/user/page", method = RequestMethod.GET)
PageInfo queryForPage();
// @RequestMapping(value = "/user/item/list/{userId}", method = RequestMethod.GET)
// public List<ItemDto> queryForItemListByUserId(@PathVariable("userId") Long userId);
}
c、新建服务提供者usermanage-provider
Pom.xml
4.0.0
com.adou.usermange
usermange-parent
1.0.0
com.adou.usermanage.provider
usermanage-provider
<properties>
<env>beta</env>
</properties>
<dependencies>
<dependency>
<groupId>com.adou.usermange.api</groupId>
<artifactId>usermanage-api</artifactId>
<version>1.0.0</version>
</dependency>
<!-- springboot start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- start by external tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- springboot end -->
<!-- springcloud start -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<!-- springcloud end -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/conf/${env}</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
application.yml
endpoints:
shutdown:
sensitive: false
enabled: true
restart:
enabled: true
sensitive: false
health:
sensitive: false
server:
port: 9000
#context-path: /${spring.application.name}
spring:
application:
name: usermanage-provider
cloud:
consul:
host: localhost
port: 8500
discovery:
serviceName: ${spring.application.name}
instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}}
preferIpAddress: true
healthCheckPath: ${server.context-path:}/health
healthCheckInterval: 10s
healthCheckCriticalTimeout: 1m
tags: test
zipkin:
base-url: http://localhost:9411/
# 自定义配置
mybatis:
typeAliasesPackage: com.adou.usermanage.provider.vo
##configLocation: classpath:mybatis-config.xml
mapperLocations: classpath:/mapper/*Mapper.xml
整合mybatis
db.sql
SET FOREIGN_KEY_CHECKS=0;
DROP TABLE IF EXISTS item;
CREATE TABLE item (
item_id bigint(20) NOT NULL AUTO_INCREMENT,
item_name varchar(255) NOT NULL,
price decimal(10,3) NOT NULL,
user_id bigint(20) NOT NULL,
PRIMARY KEY (item_id)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS usr;
CREATE TABLE usr (
usr_onlyid bigint(20) NOT NULL AUTO_INCREMENT,
usr_name_cn varchar(255) NOT NULL,
PRIMARY KEY (usr_onlyid)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
jdbc2.properties
jdbc.cloudtest-master.url=jdbc:mysql://localhost:3306/microservice?autoReconnect=true&autoReconnectForPools=true&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc.cloudtest-master.username=root
jdbc.cloudtest-master.password=root
jdbc.cloudtest-master.initialSize=5
jdbc.cloudtest-master.maxActive=10
jdbc.cloudtest-master.maxIdle=5
jdbc.cloudtest-master.minIdle=1
jdbc.cloudtest-master.maxWait=6000
jdbc.cloudtest-master.validationQuery=SELECT 1 FROM DUAL
Hikari连接池配置数据源
/**
* Hikari连接池
*
* @author zhoudoujun01
* @date 2019年9月16日09:47:25
*/
@Configuration
@PropertySource(value = "classpath:jdbc2.properties")
@EnableTransactionManagement
public class HikariDataSourceConf {
@Value("${jdbc.cloudtest-master.url}")
private String url;
@Value("${jdbc.cloudtest-master.username}")
private String username;
@Value("${jdbc.cloudtest-master.password}")
private String password;
@Value("${jdbc.cloudtest-master.initialSize}")
private String initialSize;
@Value("${jdbc.cloudtest-master.maxActive}")
private Integer maxActive;
@Value("${jdbc.cloudtest-master.maxIdle}")
private Integer maxIdle;
@Value("${jdbc.cloudtest-master.minIdle}")
private Integer minIdle;
@Value("${jdbc.cloudtest-master.maxWait}")
private Long maxWait;
@Value("${jdbc.cloudtest-master.validationQuery}")
private String validationQuery;
/**
* 设置数据源
*
* @return
*/
@Bean("dataSource")
public DataSource getDataSource() {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl(url);
hikariConfig.setUsername(username);
hikariConfig.setPassword(password);
// initialSize未使用
hikariConfig.setMaximumPoolSize(maxActive);
// maxIdle未使用
hikariConfig.setMinimumIdle(minIdle);
hikariConfig.setMaxLifetime(maxWait);
hikariConfig.setConnectionTestQuery(validationQuery);
return new HikariDataSource(hikariConfig);
}
}
myBatis配置
/**
* myBatis配置
*
* @author zhoudoujun01
* @date 2019年9月16日10:09:25
*/
@Configuration
@EnableTransactionManagement
@MapperScan(basePackages = { "com.adou.usermanage.provider.dao" })
public class MyBatisMapperScannerConf {
private Logger logger = LoggerFactory.getLogger(MyBatisMapperScannerConf.class);
@Resource(name = "dataSource")
private DataSource dataSource;
@Value("${mybatis.typeAliasesPackage}")
private String typeAliasesPackage;
@Value("${mybatis.mapperLocations}")
private String mapperLocations;
@Value("NULL")
private String jdbcTypeForNull;
/**
* 设置事物工厂
* @return
*/
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory() {
try {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
// dataSource = SpringBeanUtil.getBean(DataSource.class);
sessionFactory.setDataSource(dataSource);
sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
sessionFactory
.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources(mapperLocations));
return sessionFactory.getObject();
} catch (Exception e) {
logger.error("Could not confiure mybatis session factory"+e.getMessage(),e);
return null;
}
}
/**
* 设置获取SqlSessionTemplate
*
* @param sqlSessionFactory
* @return
*/
@Bean
public SqlSessionTemplate sqlSessionTemplate(
SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
/**
* 设置获取注解事物管理
* @return
*/
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new DataSourceTransactionManager(dataSource);
}
/**
* 设置事物管理定义
*
* @return
*/
@Bean
@ConditionalOnMissingBean
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource);
}
/**
* 分页插件
*/
@Bean
public PageHelper pageHelper(DataSource dataSource) {
PageHelper pageHelper = new PageHelper();
Properties p = new Properties();
p.setProperty("offsetAsPageNum", "true");
p.setProperty("rowBoundsWithCount", "true");
p.setProperty("reasonable", "true");
pageHelper.setProperties(p);
return pageHelper;
}
}
业务开发
UserServiceController2.java
@RestController
@Api("用户服务")
public class UserServiceController2 implements UserService2 {
@Autowired
private UserDao2 userDao;
private static BeanCopier dto2EntityCopier = BeanCopier.create(UserDto.class, User.class, false);
private static BeanCopier entity2DtoCopier = BeanCopier.create(User.class, UserDto.class, false);
// @Autowired
// public ItemService itemService;
@Override
@ApiOperation(value = "新增用户")
@RequestMapping(value = "/user", method = RequestMethod.POST)
public UserDto insert(@RequestBody UserDto userDto) {
User user = new User();
dto2EntityCopier.copy(userDto, user, null);
userDao.generator_insert(user);
entity2DtoCopier.copy(user, userDto, null);
return userDto;
}
@Override
@ApiOperation(value = "删除用户", notes = "根据用户ID删除用户")
@RequestMapping(value = "/user/{userId}", method = RequestMethod.DELETE)
public Integer deleteById(@PathVariable("userId") Long userId) {
return userDao.generator_deleteByPK(userId);
}
@Override
@ApiOperation(value = "更新用户")
@RequestMapping(value = "/user", method = RequestMethod.PUT)
public Integer update(@RequestBody UserDto userDto) {
User user = new User();
dto2EntityCopier.copy(userDto, user, null);
return userDao.generator_updateByPK(user);
}
@Override
@ApiOperation(value = "查询用户", notes = "根据用户ID查询用户")
@RequestMapping(value = "/user/{userId}", method = RequestMethod.GET)
public UserDto queryById(@PathVariable("userId") Long userId) {
User user = userDao.generator_findByPK(userId);
if (user == null) {
return null;
}
UserDto userDto = new UserDto();
entity2DtoCopier.copy(user, userDto, null);
return userDto;
}
@Override
@ApiOperation(value = "查询用户列表")
@RequestMapping(value = "/user/list", method = RequestMethod.GET)
public List<UserDto> queryForList() {
List<User> list = userDao.generator_findByExample(null);
return entity2DtoCopier(list);
}
@Override
@ApiOperation(value = "分页查询用户列表")
@RequestMapping(value = "/user/page", method = RequestMethod.GET)
public PageInfo queryForPage() {
PageHelper.startPage(1, 1);
List<User> list = userDao.generator_findByExample(null);
PageInfo pageInfo=new PageInfo(list);
return pageInfo;
}
// @Override
// @ApiOperation(value = "查询用户商品列表", notes = "根据用户ID查询用户拥有商品列表")
// @RequestMapping(value = "/user/item/list/{userId}", method = RequestMethod.GET)
// public List<ItemDto> queryForItemListByUserId(@PathVariable("userId") Long userId) {
// return itemService.queryForListByUserId(userId);
// }
private List<UserDto> entity2DtoCopier(List<User> list) {
if (list == null || list.isEmpty()) {
return null;
}
List<UserDto> newList = new ArrayList<UserDto>();
UserDto userDto = null;
for (User o : list) {
userDto = new UserDto();
entity2DtoCopier.copy(o, userDto, null);
newList.add(userDto);
}
return newList;
}
}
UserDao2.java
public interface UserDao2 {
/**
* 插入
* @param user
*/
void generator_insert(User user);
/**
* 根据主键删除
* @param userId
*/
Integer generator_deleteByPK(Long userId);
/**
* 根据条件删除
*
* @param user
* @return
*/
Integer generator_deleteByExample(User user);
/**
* 根据主键更新
* @param user
* @return
*/
Integer generator_updateByPK(User user);
/**
* 根据主键查找
* @param userId
* @return
*/
User generator_findByPK(Long userId);
/**
* 根据条件 查找
* @param user
* @return
*/
List<User> generator_findByExample(User user);
}
User.java
/**
* 实体类:对应数据库USR表
*
* @author baiyang
*
*/
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Long userId;
private String userName;
public User() {
}
public User(Long userId, String userName) {
this.userId = userId;
this.userName = userName;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Override
public String toString() {
return "User [userId=" + userId + ", userName=" + userName + "]";
}
}
UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.adou.usermanage.provider.dao.UserDao2">
<insert id="generator_insert" parameterType="User" useGeneratedKeys="true" keyProperty="userId">
INSERT INTO USR(USR_ONLYID, USR_NAME_CN)
VALUES(#{userId}, #{userName})
</insert>
<delete id="generator_deleteByPK" parameterType="Long">
DELETE FROM USR WHERE USR_ONLYID = #{userId}
</delete>
<delete id="generator_deleteByExample" parameterType="User">
DELETE FROM USR WHERE
<trim prefixOverrides="AND">
<if test="userId != null"> AND USR_ONLYID = #{userId}</if>
<if test="userName != null"> AND USR_NAME_CN = #{userName}</if>
</trim>
</delete>
<update id="generator_updateByPK" parameterType="User">
UPDATE USR
<set>
<if test="userName != null"> USR_NAME_CN = #{userName}, </if>
</set>
WHERE USR_ONLYID = #{userId}
</update>
<select id="generator_findByPK" parameterType="Long" resultType="User">
SELECT USR_ONLYID userId, USR_NAME_CN userName
FROM USR WHERE USR_ONLYID = #{userId}
</select>
<select id="generator_findByExample" resultType="User">
SELECT USR_ONLYID userId, USR_NAME_CN userName
FROM USR
<where>
<if test="userId != null"> AND USR_ONLYID = #{userId}</if>
<if test="userName != null"> AND USR_NAME_CN = #{userName}</if>
</where>
</select>
</mapper>
启动项UserServiceApp.java
@EnableSwagger2
@EnableFeignClients
@EnableDiscoveryClient
@EnableConfigurationProperties
@SpringBootApplication
public class UserServiceApp extends SpringBootServletInitializer {
public static void main(String[] args) throws Exception {
SpringApplication.run(UserServiceApp.class, args);
}
/**
* start by external tomcat
*/
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(this.getClass());
}
@Bean
public Docket createRestApi() {
Contact contact = new Contact("zdj", "", "zdj@126.com");
ApiInfo apiInfo = new ApiInfoBuilder()
.title("微服务测试-用户服务")
.description("服务提供者[usermanage-provider]")
.contact(contact)
.version("1.0.0")
.build();
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo)
.select()
.apis(RequestHandlerSelectors.basePackage("com.adou.usermanage.provider"))
.paths(PathSelectors.any())
.build();
}
}
3、项目演示
1、启动consul:http://localhost:8500/ui/dc1/services
2、启动usermanage-zipkin-zipkin:http://localhost:9411/
3、启动usermanage-provider http://localhost:9000/swagger-ui.html