龙岩网站推广,h5响应式网站源码下载,网站悬浮窗口,软件外包什么意思一微服务架构概述1.1 微服务特性以及优点每个服务可以独立运行在自己的进程里一系列独立运行的微服务(goods,order,pay,user,search…)共同构建了整个系统每个服务为独立的业务开发#xff0c;一个微服务只关注某个特定的功能#xff0c;例如用户管理#xff0c;商品管理微服…一微服务架构概述1.1 微服务特性以及优点每个服务可以独立运行在自己的进程里一系列独立运行的微服务(goods,order,pay,user,search…)共同构建了整个系统每个服务为独立的业务开发一个微服务只关注某个特定的功能例如用户管理商品管理微服务微服务之间通过一些轻量级的通信机制进行通讯例如通过Restful API进行调用技术栈不受限:可以使用不同的开发语言和数据存储技术全自动的部署机制按需伸缩:根据需求和应用场景实现细粒度的水平扩展1.2 微服务带来的挑战运维要求较高分布式的复杂性接口调整成本较高1.3 微服务设计原则单一职责原则服务自治原则轻量级通讯机制微服务粒度1.4 微服务开发框架SpringCloud:众多组件构造完善的分布式系统Dubbo/Dubbox:关注服务治理Dropwizard:关注单个微服务开发二 SpringCloud概述与开发环境2.1 SpringCloud概述SpringCloud是基于SpringBoot之上的用来快速构建微服务系统的工具集拥有功能完善的轻量级微服务组件例如服务治理(Eureka),声明式REST调用(Feign),客户端负载均衡(Ribbon),服务容错(Hystrix),服务网关(Zuul)以及服务配置(Spring Cloud Config),服务跟踪(Sleuth)等等。官网链接:http://projects.spring.io/spring-cloud/ 目前主流的版本为SpringBoot1.4.5.RELEAE和SpringCloudCamden.SR7, Maven pom配置如下parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion1.4.5.RELEASE/version
/parent
dependencyManagementdependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-dependencies/artifactIdversionCamden.SR7/versiontypepom/typescopeimport/scope/dependency/dependencies
/dependencyManagement
dependenciesdependencygroupId/groupIdartifactIdspring-cloud-starter-config/artifactId/dependencydependencygroupId/groupIdartifactIdspring-cloud-starter-eureka/artifactId/dependency
/dependencies12345678910111213141516171819202122232425262.2 开发环境MacOS10.12JDK8u131IntelliJ IDEA2017.1.4Tomcat8.5Maven3.3.9Git2.12Firefox54Spring4.3.9.RELEASESpringBoot1.4.5.RELEASESpringCloud Camden.SR7三 工程机器模块说明3.1 工程说明工程首先自定义了Maven父工程,其中定义如下的公共组件:?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersion!-- 自定义工程的maven坐标--groupIdcom.ekeyfund.springcloud/groupIdartifactIdspringcloud-parent/artifactIdversion2.0.0-SNAPSHOT/versionpackagingpom/packaging!-- 基于SpringBoot 1.4.5.RELEASE--parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion1.4.5.RELEASE/versionrelativePath//parent!-- 定义引用类库版本 --propertiesproject.build.sourceEncodingUTF-8/project.build.sourceEncodingproject.reporting.outputEncodingUTF-8/project.reporting.outputEncodingjava.version1.8/java.versionspring-cloud.versionCamden.SR7/spring-cloud.versionspringcloud-parent.version2.0.0-SNAPSHOT/springcloud-parent.versiondruid.version1.0.31/druid.versionjackson.version2.8.8/jackson.versioncommons-lang3.version3.5/commons-lang3.versionehcache.version3.1.4/ehcache.versionhibernate.version5.0.12.Final/hibernate.versionservlet-api.version3.1.0/servlet-api.versioncommons-collection4.version4.1/commons-collection4.versionspringframework.oxm.version4.3.9.RELEASE/springframework.oxm.version/properties!-- 引入SpringCloud微服务常用组件--modulesmodulespringcloud-eureka-server/modulemodulespringcloud-eureka-server-ha/modulemodulespringcloud-provider-user-service/modulemodulespringcloud-consumer-h5-ribbon-hystrix/modulemodulespringcloud-consumer-h5-feign/modulemodulespringcloud-api-gateway/modulemodulespringcloud-consumer-h5/modulemodulespringcloud-config-server/module/modulesdependencies!-- 服务发现组件--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-eureka-server/artifactId/dependency!-- 应用监控--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependency!-- 应用测试--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdscoperuntime/scope/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion${druid.version}/version/dependencydependencygroupIdjavax.servlet/groupIdartifactIdjavax.servlet-api/artifactIdversion${servlet-api.version}/version/dependencydependencygroupIdcom.fasterxml.jackson.core/groupIdartifactIdjackson-annotations/artifactIdversion${jackson.version}/version/dependencydependencygroupIdorg.apache.commons/groupIdartifactIdcommons-lang3/artifactIdversion${commons-lang3.version}/version/dependencydependencygroupIdorg.apache.commons/groupIdartifactIdcommons-collections4/artifactIdversion${commons-collection4.version}/version/dependencydependencygroupIdorg.hibernate/groupIdartifactIdhibernate-ehcache/artifactIdversion${hibernate.version}/version/dependencydependencygroupIdorg.ehcache/groupIdartifactIdehcache/artifactIdversion${ehcache.version}/version/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-oxm/artifactIdversion${springframework.oxm.version}/version/dependency/dependenciesdependencyManagementdependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-dependencies/artifactIdversion${spring-cloud.version}/versiontypepom/typescopeimport/scope/dependency/dependencies/dependencyManagement
/project1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431443.2 模块说明模块则借助IntelliJ IDEA结合Spring Initializer自动生成工程结构,主要模块和说明如下:模块名称模块说明访问地址springcloud-eureka-server分布式服务注册中心(单点)http://127.0.0.1:9999springcloud-eureka-server-ha分布式服务注册中心(高可用版本)http://127.0.0.1:9998 http://127.0.0.1:9997springcloud-provider-user-service用户服务提供者http://127.0.0.1:9996/list http://127.0.0.1:9995/listspringcloud-consumer-h5用户服务调用者,采用原始的RestTemplate调用http://127.0.0.1:9991/user/get/4springcloud-consumer-h5-ribbon-hystrix用户服务调用者采用ribbon做客户端负载均衡http://127.0.0.1:9994/springcloud-provider-user-servicespringcloud-consumer-h5-feignfeign声明式服务调用者http://127.0.0.1:9993/listspringcloud-gateway网关服务http://127.0.0.1:9992/api-a/listspringcloud-config-server配置中心待定四 使用SpringBoot实现服务提供者所属maven模块:springcloud-provider-user-service 基于SpringBoot的Web和JPA模块实现Restful API的常用方法4.1 entity主要包含User,Role,Department三个实体Role.javapackage com.ekeyfund.springcloud.entity;import javax.persistence.*;
import java.io.Serializable;/*** Role Entity** author Liuguanglei liuguangleiekeyfund.com* create 2017-06-下午2:36*/
Entity
Table(name springboot_role)
public class Role implements Serializable{IdGeneratedValue(strategy GenerationType.IDENTITY)Column(name role_id)private Long id;Column(name role_name)private String name;public Long getId() {return id;}public void setId(Long id) {this.id id;}public String getName() {return name;}public void setName(String name) {this.name name;}Overridepublic String toString() {return new org.apache.commons.lang3.builder.ToStringBuilder(this).append(id, id).append(name, name).toString();}
}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051Department.javapackage com.ekeyfund.springcloud.entity;import org.apache.commons.lang3.builder.ToStringBuilder;
import org.hibernate.annotations.CacheConcurrencyStrategy;import javax.persistence.*;
import java.io.Serializable;/*** Department Entity** author Liuguanglei liuguangleiekeyfund.com* create 2017-06-下午2:31*/
Entity
Table(name springboot_department)
org.hibernate.annotations.Cache(usage CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Department implements Serializable {IdGeneratedValue(strategy GenerationType.IDENTITY)Column(name department_id)private Long id;Column(name department_name)private String name;public Long getId() {return id;}public void setId(Long id) {this.id id;}public String getName() {return name;}public void setName(String name) {this.name name;}Overridepublic String toString() {return new ToStringBuilder(this).append(id, id).append(name, name).toString();}
}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556User.javapackage com.ekeyfund.springcloud.entity;import com.fasterxml.jackson.annotation.JsonBackReference;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.format.annotation.DateTimeFormat;import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
import java.util.List;/*** User Entity** author Liuguanglei liuguangleiekeyfund.com* create 2017-06-下午2:32*/
Entity
Table(name springboot_user)
public class User implements Serializable{IdColumn(name user_id)GeneratedValue(strategy GenerationType.IDENTITY)private Long id;Column(name user_name)private String name;Column(name user_password)private String password;Column(name user_create_date)DateTimeFormat(pattern yyyy-MM-dd HH:mm:ss)private Date createDate;ManyToOneJoinColumn(name department_id)JsonBackReferenceprivate Department department;ManyToMany(cascade {},fetch FetchType.EAGER)JoinTable(name springboot_user_role,joinColumns {JoinColumn(nameuser_id)},inverseJoinColumns {JoinColumn(name role_id)})private ListRole roleList;public Long getId() {return id;}public void setId(Long id) {this.id id;}public String getName() {return name;}public void setName(String name) {this.name name;}public String getPassword() {return password;}public void setPassword(String password) {this.password password;}public Date getCreateDate() {return createDate;}public void setCreateDate(Date createDate) {this.createDate createDate;}public Department getDepartment() {return department;}public void setDepartment(Department department) {this.department department;}public ListRole getRoleList() {return roleList;}public void setRoleList(ListRole roleList) {this.roleList roleList;}Overridepublic String toString() {return new ToStringBuilder(this).append(id, id).append(name, name).append(password, password).append(createDate, createDate).append(department, department).append(roleList, roleList).toString();}
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121134.2 数据访问Repository主要包含UserRepository和DepartmentRepositoryDepartmentRepository.javapackage com.ekeyfund.springcloud.repository;import com.ekeyfund.springcloud.entity.Department;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;/*** Created by tony on 2017/6/19.*/
Repository
public interface DepartmentRepository extends JpaRepositoryDepartment,Long {
}1234567891011121314UserRepoistory.javapackage com.ekeyfund.springcloud.repository;import com.ekeyfund.springcloud.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;import java.util.Collection;
import java.util.Date;
import java.util.List;/*** User Repository** author Liuguanglei liuguangleiekeyfund.com* create 2017-06-下午2:54*/
Repository
public interface UserRepository extends JpaRepositoryUser,Long{/*** and* param id* param name* return*/User findByIdAndName(Long id, String name);User findByNameAndPassword(String name, String password);/*** or* param id* param name* return*/User findByIdOrName(Long id, String name);/*** between* param start* param end* return*/ListUser findByCreateDateBetween(Date start, Date end);/*** lessThan* param start* return*/ListUser getByCreateDateLessThan(Date start);/*** Greater Than* param start* return*/ListUser findByCreateDateGreaterThan(Date start);/*** is null* return*/ListUser findByNameIsNull();/*** in* param nameList* return*/ListUser findByNameIn(CollectionString nameList);}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778794.3 业务逻辑Service主要包含UserService,DepartmentService及其实现UserService.javapackage com.ekeyfund.springcloud.service;import com.ekeyfund.springcloud.entity.User;import java.util.List;/*** Created by tony on 2017/6/19.*/
public interface UserService {/*** 登录* param name* param password* return*/public User login(String name, String password);/*** 注册* param user* return*/public User register(User user);/*** 注销* param user* return*/void writeOff(User user);/*** 当前用户是否已经存在* param user* return*/boolean isExists(User user);ListUser getAllUser();User getUserById(Long id);}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950UserServiceImpl.javapackage com.ekeyfund.springcloud.service.impl;import com.ekeyfund.springcloud.entity.User;
import com.ekeyfund.springcloud.repository.UserRepository;
import com.ekeyfund.springcloud.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import javax.transaction.Transactional;
import java.util.List;/*** User Service Impl** author Liuguanglei liuguangleiekeyfund.com* create 2017-06-下午3:34*/
Service
Transactional
public class UserServiceImpl implements UserService {Autowiredprivate UserRepository userRepository;Overridepublic User login(String name, String password) {return userRepository.findByNameAndPassword(name,password);}Overridepublic User register(User user) {return userRepository.save(user);}Overridepublic void writeOff(User user) {userRepository.delete(user);}Overridepublic boolean isExists(User user) {return userRepository.findOne(user.getId())!null?true:false;}Overridepublic ListUser getAllUser() {return userRepository.findAll();}Overridepublic User getUserById(Long id) {return userRepository.findOne(id);}
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859DepartmentService.javapackage com.ekeyfund.springcloud.service;import com.ekeyfund.springcloud.entity.Department;/*** Created by tony on 2017/6/19.*/
public interface DepartmentService {Department saveDepartment(Department department);Department getDepartmentById(Long id);
}
123456789101112131415DepartmentServiceImpl.javapackage com.ekeyfund.springcloud.service.impl;import com.ekeyfund.springcloud.entity.Department;
import com.ekeyfund.springcloud.repository.DepartmentRepository;
import com.ekeyfund.springcloud.service.DepartmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import javax.transaction.Transactional;/*** Department Impl** author Liuguanglei liuguangleiekeyfund.com* create 2017-06-下午3:12*/
Transactional
Service
public class DepartmentImpl implements DepartmentService {Autowiredprivate DepartmentRepository departmentRepository;Overridepublic Department saveDepartment(Department department) {return departmentRepository.save(department);}Overridepublic Department getDepartmentById(Long id) {return departmentRepository.findOne(id);}
}12345678910111213141516171819202122232425262728293031323334353637384.4 Controller层主要包含提供User完整的Restful API 的UserControllerUserController.javapackage com.ekeyfund.springcloud.controller;import com.ekeyfund.springcloud.entity.User;
import com.ekeyfund.springcloud.service.UserService;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;import java.util.Date;
import java.util.List;/*** UserController* Restful API* author Liuguanglei liuguangleiekeyfund.com* create 2017-06-下午11:24*/
RestController
public class UserController {private static final org.slf4j.Logger LOGGER LoggerFactory.getLogger(UserController.class);Autowiredprivate DiscoveryClient discoveryClient;Autowiredprivate UserService userService;GetMapping(value /list)public ListUser list(){ServiceInstance instancediscoveryClient.getLocalServiceInstance();LOGGER.info(call user/list service host is instance.getHost()service_id is instance.getServiceId());return userService.getAllUser();}GetMapping(value /login)public User login( RequestParam String name,RequestParam String password){User useruserService.login(name,password);return user;}PostMapping(/register)public String register(ModelAttribute User user){User result userService.register(user);return result!null?success:fail;}GetMapping(/get/{id})public User get(PathVariable Long id){return userService.getUserById(id);}PutMapping(/update/{id})public String update(PathVariable Long id,ModelAttribute User user){User updatedUser userService.getUserById(id);updatedUser.setName(user.getName());updatedUser.setPassword(user.getPassword());updatedUser.setCreateDate(new Date());User result userService.register(updatedUser);return result!null?success:fail;}DeleteMapping(/delete/{id})public String delete(PathVariable Long id){User user new User();user.setId(id);userService.writeOff(user);return success;}}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788894.5 Configuration主要包含数据源Druid和JPA的配置DruidConfiguation.javapackage com.ekeyfund.springcloud.configuration;import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;/*** Druid Configuration** author Liuguanglei liuguangleiekeyfund.com* create 2017-06-下午5:48*/
public class DruidConfiguration {Beanpublic ServletRegistrationBean statViewServle(){ServletRegistrationBean servletRegistrationBean new ServletRegistrationBean(new StatViewServlet(),/druid/*);//白名单servletRegistrationBean.addInitParameter(allow,192.168.1.218,127.0.0.1);//IP黑名单 (存在共同时deny优先于allow) : 如果满足deny的即提示:Sorry, you are not permitted to view this page.servletRegistrationBean.addInitParameter(deny,192.168.1.100);//登录查看信息的账号密码.servletRegistrationBean.addInitParameter(loginUsername,druid);servletRegistrationBean.addInitParameter(loginPassword,12345678);//是否能够重置数据.servletRegistrationBean.addInitParameter(resetEnable,false);return servletRegistrationBean;}Beanpublic FilterRegistrationBean statFilter(){FilterRegistrationBean filterRegistrationBean new FilterRegistrationBean(new WebStatFilter());//添加过滤规则.filterRegistrationBean.addUrlPatterns(/*);//添加不需要忽略的格式信息.filterRegistrationBean.addInitParameter(exclusions,*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*);return filterRegistrationBean;}
}
1234567891011121314151617181920212223242526272829303132333435363738394041JPAPersistenceConfigurationpackage com.ekeyfund.springcloud.configuration;import com.alibaba.druid.pool.DruidDataSource;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Properties;/*** JPA Persistence Configuration** author Liuguanglei liuguangleiekeyfund.com* create 2017-06-上午11:26*/
Order(Ordered.HIGHEST_PRECEDENCE)
Configuration
EnableTransactionManagement(proxyTargetClass true) //启用JPA的事务管理
EnableJpaRepositories(basePackages com.ekeyfund.springcloud.repository )//启用JPA资源库并指定资源库接口位置
EntityScan(basePackages com.ekeyfund.springcloud.entity)//指定实体的位置
public class JPAPersistenceConfiguration {private static final org.slf4j.Logger LOGGER LoggerFactory.getLogger(JPAPersistenceConfiguration.class);/*******************数据库和连接池配置信息,读取application.properties文件的属性值****************************/Value(${spring.datasource.driver-class-name})private String driverClass;Value(${spring.datasource.username})private String userName;Value(${spring.datasource.password})private String password;Value(${spring.datasource.url})private String url;Value(${spring.datasource.initialSize})private int initialSize;Value(${spring.datasource.minIdle})private int minIdle;Value(${spring.datasource.maxActive})private int maxActive;Value(${spring.datasource.maxWait})private long maxWait;Value(${spring.datasource.timeBetweenEvictionRunsMillis})private long timeBetweenEvictionRunsMillis;Value(${spring.datasource.minEvictableIdleTimeMillis})private long minEvictableIdleTimeMillis;Value(${spring.datasource.filters})private String filters;Value(${spring.datasource.connectionProperties})private String connectionProperties;Bean(name druidDataSource,initMethod init,destroyMethod close)public DataSource dataSource(){DruidDataSource druidDataSource new DruidDataSource();druidDataSource.setDriverClassName(driverClass);druidDataSource.setUsername(userName);druidDataSource.setPassword(password);druidDataSource.setUrl(url);druidDataSource.setInitialSize(initialSize);druidDataSource.setMinIdle(minIdle);druidDataSource.setMaxActive(maxActive);druidDataSource.setMaxWait(maxWait);druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);druidDataSource.setConnectionProperties(connectionProperties);try {druidDataSource.setFilters(filters);} catch (SQLException e) {LOGGER.error(build datasoure exception ,e.getMessage());}return druidDataSource;}Bean(name entityManagerFactory)public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource druidDataSource){LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean new LocalContainerEntityManagerFactoryBean();localContainerEntityManagerFactoryBean.setDataSource(druidDataSource);localContainerEntityManagerFactoryBean.setPackagesToScan(com.ekeyfund.springcloud.entity);localContainerEntityManagerFactoryBean.setJpaProperties(buildHibernateProperties());localContainerEntityManagerFactoryBean.setJpaDialect(new HibernateJpaDialect());localContainerEntityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter(){{setDatabase(org.springframework.orm.jpa.vendor.Database.MYSQL);setDatabasePlatform(org.hibernate.dialect.MySQL5Dialect);}});return localContainerEntityManagerFactoryBean;}Beanpublic PlatformTransactionManager transactionManager(DataSource druidDataSource, EntityManagerFactory entityManagerFactory){JpaTransactionManager jpaTransactionManagernew JpaTransactionManager();jpaTransactionManager.setDataSource(druidDataSource);jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);return jpaTransactionManager;}BeanPersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor(){return new PersistenceExceptionTranslationPostProcessor();}protected Properties buildHibernateProperties(){Properties hibernateProperties new Properties();hibernateProperties.setProperty(hibernate.dialect, org.hibernate.dialect.MySQL5Dialect);hibernateProperties.setProperty(hibernate.hbm2ddl.auto,update);hibernateProperties.setProperty(hibernate.show_sql, false);hibernateProperties.setProperty(hibernate.use_sql_comments, false);hibernateProperties.setProperty(hibernate.format_sql, true);hibernateProperties.setProperty(hibernate.generate_statistics, false);hibernateProperties.setProperty(javax.persistence.validation.mode, none);//Audit History flagshibernateProperties.setProperty(org.hibernate.envers.store_data_at_delete, true);hibernateProperties.setProperty(org.hibernate.envers.global_with_modified_flag, true);hibernateProperties.setProperty(hibernate.cache.use_second_level_cache, true);hibernateProperties.setProperty(hibernate.cache.region.factory_class, org.hibernate.cache.ehcache.EhCacheRegionFactory);hibernateProperties.setProperty(hibernate.cache.use_query_cache, true);return hibernateProperties;}}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621634.6 应用配置主要包含springboot的application.properties,logback的logback-spring.xml以及缓存框架的ehcache.xmlapplication.propeties
##DataSource Config
##\u6570\u636e\u5e93\u8fde\u63a5\u6c60\u4fe1\u606f\u914d\u7f6e
spring.datasource.typecom.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-namecom.mysql.jdbc.Driver
spring.datasource.urljdbc:mysql://127.0.0.1:3306/springboot?characterEncodingutf-8
spring.datasource.usernameroot
spring.datasource.passwordguanglei
# \u4e0b\u9762\u4e3a\u8fde\u63a5\u6c60\u7684\u8865\u5145\u8bbe\u7f6e\uff0c\u5e94\u7528\u5230\u4e0a\u9762\u6240\u6709\u6570\u636e\u6e90\u4e2d
# \u521d\u59cb\u5316\u5927\u5c0f\uff0c\u6700\u5c0f\uff0c\u6700\u5927
spring.datasource.initialSize5
spring.datasource.minIdle5
spring.datasource.maxActive20
# \u914d\u7f6e\u83b7\u53d6\u8fde\u63a5\u7b49\u5f85\u8d85\u65f6\u7684\u65f6\u95f4
spring.datasource.maxWait60000
# \u914d\u7f6e\u95f4\u9694\u591a\u4e45\u624d\u8fdb\u884c\u4e00\u6b21\u68c0\u6d4b\uff0c\u68c0\u6d4b\u9700\u8981\u5173\u95ed\u7684\u7a7a\u95f2\u8fde\u63a5\uff0c\u5355\u4f4d\u662f\u6beb\u79d2
spring.datasource.timeBetweenEvictionRunsMillis60000
# \u914d\u7f6e\u4e00\u4e2a\u8fde\u63a5\u5728\u6c60\u4e2d\u6700\u5c0f\u751f\u5b58\u7684\u65f6\u95f4\uff0c\u5355\u4f4d\u662f\u6beb\u79d2
spring.datasource.minEvictableIdleTimeMillis300000
spring.datasource.validationQuerySELECT 1 FROM DUAL
spring.datasource.testWhileIdletrue
spring.datasource.testOnBorrowfalse
spring.datasource.testOnReturnfalse
# \u6253\u5f00PSCache\uff0c\u5e76\u4e14\u6307\u5b9a\u6bcf\u4e2a\u8fde\u63a5\u4e0aPSCache\u7684\u5927\u5c0f
spring.datasource.poolPreparedStatementstrue
spring.datasource.maxPoolPreparedStatementPerConnectionSize20
# \u914d\u7f6e\u76d1\u63a7\u7edf\u8ba1\u62e6\u622a\u7684filters\uff0c\u53bb\u6389\u540e\u76d1\u63a7\u754c\u9762sql\u65e0\u6cd5\u7edf\u8ba1\uff0cwall\u7528\u4e8e\u9632\u706b\u5899
spring.datasource.filtersstat,wall,log4j
# \u901a\u8fc7connectProperties\u5c5e\u6027\u6765\u6253\u5f00mergeSql\u529f\u80fd\uff1b\u6162SQL\u8bb0\u5f55
spring.datasource.connectionPropertiesdruid.stat.mergeSqltrue;druid.stat.slowSqlMillis5000# \u5408\u5e76\u591a\u4e2aDruidDataSource\u7684\u76d1\u63a7\u6570\u636e
#spring.datasource.useGlobalDataSourceStattrue# druid \u8bbf\u95ee\u5730\u5740 http://host:port/druid/index.html##Log Config
logging.configclasspath:logback-spring.xml## SpringData JPA Config
spring.jpa.databasemysql
spring.jpa.show-sqltrue
spring.jpa.hibernate.ddl-autoupdate
spring.jpa.generate-ddltrueserver.port999612345678910111213141516171819202122232425262728293031323334353637383940414243444546ehcache.xmlehcache!-- Sets the path to the directory where cache .data files are created.If the path is a Java System Property it is replaced byits value in the running VM.The following properties are translated:user.home - Users home directoryuser.dir - Users current working directoryjava.io.tmpdir - Default temp file path --!--指定一个目录当 EHCache 把数据写到硬盘上时, 将把数据写到这个目录下.--diskStore pathtempDirectory/!--Default Cache configuration. These will applied to caches programmatically created throughthe CacheManager.The following attributes are required for defaultCache:maxInMemory - Sets the maximum number of objects that will be created in memoryeternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the elementis never expired.timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only usedif the element is not eternal. Idle time is now - last accessed timetimeToLiveSeconds - Sets the time to live for an element before it expires. Is only usedif the element is not eternal. TTL is now - creation timeoverflowToDisk - Sets whether elements can overflow to disk when the in-memory cachehas reached the maxInMemory limit.--!--设置缓存的默认数据过期策略--defaultCachemaxElementsInMemory10000eternalfalsetimeToIdleSeconds120timeToLiveSeconds120overflowToDisktrue/!--设定具体的命名缓存的数据过期策略。每个命名缓存代表一个缓存区域缓存区域(region)一个具有名称的缓存块可以给每一个缓存块设置不同的缓存策略。如果没有设置任何的缓存区域则所有被缓存的对象都将使用默认的缓存策略。即defaultCache.../Hibernate 在不同的缓存区域保存不同的类/集合。对于类而言区域的名称是类名。如:com.ekeyfund.springboot.jpa.entity.User对于集合而言区域的名称是类名加属性名。如com.ekeyfund.springboot.jpa.entity.User.roleList--!--name: 设置缓存的名字,它的取值为类的全限定名或类的集合的名字maxElementsInMemory: 设置基于内存的缓存中可存放的对象最大数目eternal: 设置对象是否为永久的, true表示永不过期,此时将忽略timeToIdleSeconds 和 timeToLiveSeconds属性; 默认值是falsetimeToIdleSeconds:设置对象空闲最长时间,以秒为单位, 超过这个时间,对象过期。当对象过期时,EHCache会把它从缓存中清除。如果此值为0,表示对象可以无限期地处于空闲状态。timeToLiveSeconds:设置对象生存最长时间,超过这个时间,对象过期。如果此值为0,表示对象可以无限期地存在于缓存中. 该属性值必须大于或等于 timeToIdleSeconds 属性值overflowToDisk:设置基于内存的缓存中的对象数目达到上限后,是否把溢出的对象写到基于硬盘的缓存中--cache namecom.ekeyfund.springcloud.entity.DepartmentmaxElementsInMemory1eternalfalsetimeToIdleSeconds300timeToLiveSeconds600overflowToDisktrue/cache namecom.ekeyfund.springcloud.entity.UsermaxElementsInMemory1000eternaltruetimeToIdleSeconds0timeToLiveSeconds0overflowToDiskfalse/cache namecom.ekeyfund.springcloud.entity.RolemaxElementsInMemory1000eternaltruetimeToIdleSeconds0timeToLiveSeconds0overflowToDiskfalse//ehcache123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990logback.xml?xml version1.0 encodingUTF-8?
configuration!--include resourceorg/springframework/boot/logging/logback/base.xml/--!-- 项目的appid --property nameAPP_ID valueSpringCloud-Provider-User-Service/property nameLOG_PATH valuelogs/propertyappender nameSTDOUT classch.qos.logback.core.ConsoleAppenderencoderpattern%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg %n/pattern/encoder/appenderappender nameFILE_LOGclassch.qos.logback.core.rolling.RollingFileAppenderfilter classch.qos.logback.classic.filter.LevelFilterlevelDEBUG/level/filterfile${LOG_PATH}/${APP_ID}/access.log/filerollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicyfileNamePattern${LOG_PATH}/${APP_ID}/access.log.%d{yyyy-MM-dd}.zip/fileNamePatternmaxHistory10/maxHistory/rollingPolicyencoderpattern%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n/pattern/encoder/appenderappender nameFILE_DEBUGclassch.qos.logback.core.rolling.RollingFileAppenderfilter classch.qos.logback.classic.filter.LevelFilterlevelDEBUG/levelonMatchACCEPT/onMatchonMismatchDENY/onMismatch/filterfile${LOG_PATH}/${APP_ID}/access_debug.log/filerollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicyfileNamePattern${LOG_PATH}/${APP_ID}/access_debug.log.%d{yyyy-MM-dd}.zip/fileNamePatternmaxHistory10/maxHistory/rollingPolicyencoderpattern%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n/pattern/encoder/appenderappender nameFILE_INFOclassch.qos.logback.core.rolling.RollingFileAppenderfilter classch.qos.logback.classic.filter.LevelFilterlevelINFO/levelonMatchACCEPT/onMatchonMismatchDENY/onMismatch/filterfile${LOG_PATH}/${APP_ID}/access_info.log/filerollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicyfileNamePattern${LOG_PATH}/${APP_ID}/access_info.log.%d{yyyy-MM-dd}.zip/fileNamePatternmaxHistory10/maxHistory/rollingPolicyencoderpattern%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n/pattern/encoder/appenderappender nameFILE_WARNclassch.qos.logback.core.rolling.RollingFileAppenderfilter classch.qos.logback.classic.filter.LevelFilterlevelWARN/levelonMatchACCEPT/onMatchonMismatchDENY/onMismatch/filterfile${LOG_PATH}/${APP_ID}/access_warn.log/filerollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicyfileNamePattern${LOG_PATH}/${APP_ID}/access_warn.log.%d{yyyy-MM-dd}.zip/fileNamePatternmaxHistory10/maxHistory/rollingPolicyencoderpattern%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n/pattern/encoder/appenderappender nameFILE_ERRORclassch.qos.logback.core.rolling.RollingFileAppenderfilter classch.qos.logback.classic.filter.LevelFilterlevelERROR/levelonMatchACCEPT/onMatchonMismatchDENY/onMismatch/filterfile${LOG_PATH}/${APP_ID}/access_error.log/filerollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicyfileNamePattern${LOG_PATH}/${APP_ID}/access_error.log.%d{yyyy-MM-dd}.zip/fileNamePatternmaxHistory10/maxHistory/rollingPolicyencoderpattern%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n/pattern/encoder/appenderappender nameASYNC_LOG classch.qos.logback.classic.AsyncAppender!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --discardingThreshold0/discardingThreshold!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --queueSize512/queueSizeappender-ref refFILE_LOG//appenderappender nameASYNC_LOG classch.qos.logback.classic.AsyncAppender!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --discardingThreshold0/discardingThreshold!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --queueSize512/queueSizeappender-ref refFILE_LOG//appenderappender nameASYNC_LOG_DEBUG classch.qos.logback.classic.AsyncAppender!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --discardingThreshold0/discardingThreshold!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --queueSize512/queueSizeappender-ref refFILE_DEBUG//appenderappender nameASYNC_LOG_INFO classch.qos.logback.classic.AsyncAppender!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --discardingThreshold0/discardingThreshold!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --queueSize512/queueSizeappender-ref refFILE_INFO//appenderappender nameASYNC_LOG_WARN classch.qos.logback.classic.AsyncAppender!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --discardingThreshold0/discardingThreshold!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --queueSize512/queueSizeappender-ref refFILE_WARN//appenderappender nameASYNC_LOG_ERROR classch.qos.logback.classic.AsyncAppender!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --discardingThreshold0/discardingThreshold!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --queueSize512/queueSizeappender-ref refFILE_ERROR//appenderroot levelINFO!-- appender referenced after it is defined --appender-ref refSTDOUT/appender-ref refASYNC_LOG/appender-ref refASYNC_LOG_DEBUG/appender-ref refASYNC_LOG_INFO/appender-ref refASYNC_LOG_WARN/appender-ref refASYNC_LOG_ERROR//rootlogger nameorg.springframework levelINFO/
/configuration1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521534.7 pom.xml
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionartifactIdspringcloud-provider-user-service/artifactIdpackagingjar/packagingnamespringcloud-user-service/namedescriptionSpringCloud User Service Application/descriptionparentgroupIdcom.ekeyfund.springcloud/groupIdartifactIdspringcloud-parent/artifactIdversion2.0.0-SNAPSHOT/versionrelativePath../pom.xml/relativePath/parentpropertiesstart-classcom.ekeyfund.springcloud.SpringcloudUserServiceMasterApplication/start-class/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-jpa/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdconfigurationmainClass${start-class}/mainClasslayoutZIP/layout/configurationexecutionsexecutiongoalsgoalrepackage/goal/goals/execution/executions/plugin/plugins/build
/project
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859604.8 启动类package com.ekeyfund.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;//EnableDiscoveryClient//激活Eureka中的DiscoveryClient实现(自动化配置,创建DiscoveryClient接口针对Eureka客户端的EurekaDiscoveryClient实例)
SpringBootApplication
public class SpringcloudUserServiceMasterApplication {public static void main(String[] args) {SpringApplication.run(SpringcloudUserServiceMasterApplication.class, args);}
}123456789101112131415164.9 测试用例package com.ekeyfund.springcloud;import com.ekeyfund.springcloud.entity.Department;
import com.ekeyfund.springcloud.entity.User;
import com.ekeyfund.springcloud.service.DepartmentService;
import com.ekeyfund.springcloud.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.junit4.SpringRunner;import java.util.Date;RunWith(SpringRunner.class)
SpringBootTest
ComponentScan(com.ekeyfund.springcloud)
public class SpringcloudUserServiceApplicationTests {private static final org.slf4j.Logger LOGGER LoggerFactory.getLogger(SpringcloudUserServiceApplicationTests.class);Testpublic void contextLoads() {}Autowiredprivate DepartmentService departmentService;Autowiredprivate UserService userService;Testpublic void testDepartmentService(){Department departmentnew Department();department.setName(dev);Department result departmentService.saveDepartment(department);LOGGER.info(add result result);Long id 1L;result departmentService.getDepartmentById(id);LOGGER.info(get department result);}Testpublic void testUserRegister()throws Exception{User user new User();user.setName(tony);user.setPassword(666666);user.setCreateDate(new Date());Department departmentdepartmentService.getDepartmentById(1L);user.setDepartment(department);User result userService.register(user);LOGGER.info(register result result);}Testpublic void testWriteOff()throws Exception{User user new User();user.setName(tony);user.setPassword(666666);userService.writeOff(user);}Testpublic void testUserLogin()throws Exception{User user new User();user.setName(tony);user.setPassword(666666);User result userService.login(user.getName(),user.getPassword());LOGGER.info(login result);}Testpublic void testUserIsExist()throws Exception{User user new User();user.setId(4L);boolean result userService.isExists(user);LOGGER.info(isExist result);}}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102五 使用SpringBoot实现服务消费者所属maven模块:springcloud-consumer-h55.1 entity主要包含User,Department,Role Role.javapackage com.ekeyfund.springcloud.entity;/*** Role Entity** author Liuguanglei liuguangleiekeyfund.com* create 2017-06-下午2:36*/public class Role {private Long id;private String name;public Long getId() {return id;}public void setId(Long id) {this.id id;}public String getName() {return name;}public void setName(String name) {this.name name;}Overridepublic String toString() {return new org.apache.commons.lang3.builder.ToStringBuilder(this).append(id, id).append(name, name).toString();}
}
12345678910111213141516171819202122232425262728293031323334353637383940414243Department.javapackage com.ekeyfund.springcloud.entity;import org.apache.commons.lang3.builder.ToStringBuilder;/*** Department Entity** author Liuguanglei liuguangleiekeyfund.com* create 2017-06-下午2:31*/public class Department {private Long id;private String name;public Long getId() {return id;}public void setId(Long id) {this.id id;}public String getName() {return name;}public void setName(String name) {this.name name;}Overridepublic String toString() {return new ToStringBuilder(this).append(id, id).append(name, name).toString();}
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546User.javapackage com.ekeyfund.springcloud.entity;import com.fasterxml.jackson.annotation.JsonBackReference;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.format.annotation.DateTimeFormat;import java.util.Date;
import java.util.List;/*** User Entity** author Liuguanglei liuguangleiekeyfund.com* create 2017-06-下午2:32*/public class User {private Long id;private String name;private String password;DateTimeFormat(pattern yyyy-MM-dd HH:mm:ss)private Date createDate;JsonBackReferenceprivate Department department;private ListRole roleList;public Long getId() {return id;}public void setId(Long id) {this.id id;}public String getName() {return name;}public void setName(String name) {this.name name;}public String getPassword() {return password;}public void setPassword(String password) {this.password password;}public Date getCreateDate() {return createDate;}public void setCreateDate(Date createDate) {this.createDate createDate;}public Department getDepartment() {return department;}public void setDepartment(Department department) {this.department department;}public ListRole getRoleList() {return roleList;}public void setRoleList(ListRole roleList) {this.roleList roleList;}Overridepublic String toString() {return new ToStringBuilder(this).append(id, id).append(name, name).append(password, password).append(createDate, createDate).append(department, department).append(roleList, roleList).toString();}
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001015.2 Configuraiton主要包含Spring MVC相关配置MVCConfiguration.javapackage com.ekeyfund.springcloud.configuration;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;import java.util.ArrayList;
import java.util.List;Configuration
EnableWebMvc
public class MVCConfiguration extends WebMvcConfigurerAdapter{/*** * return*/Beanpublic RequestMappingHandlerAdapter requestMappingHandlerAdapter(){RequestMappingHandlerAdapter requestMappingHandlerAdapternew RequestMappingHandlerAdapter();ListHttpMessageConverter? messageConverters new ArrayList();messageConverters.add(mappingJackson2HttpMessageConverter());requestMappingHandlerAdapter.setMessageConverters(messageConverters);return requestMappingHandlerAdapter;}//Beanpublic MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter new MappingJackson2HttpMessageConverter();ListMediaType supportedMediaTypes new ArrayList();supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);mappingJackson2HttpMessageConverter.setSupportedMediaTypes(supportedMediaTypes);return mappingJackson2HttpMessageConverter;}Beanpublic RestTemplate restTemplate(){RestTemplate restTemplate new RestTemplate();return restTemplate;}}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585.3 Controller主要包含UserControllerUserController.javapackage com.ekeyfund.springcloud.controller;import com.ekeyfund.springcloud.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;/*** UserController** author tony 18601767221163.com* create 2017-06-27-下午11:42* see* since JDK1.8u133*/
RestController
public class UserController {Autowiredprivate RestTemplate restTemplate;GetMapping(user/get/{id})public User get(PathVariable Long id){return this.restTemplate.getForObject(http://127.0.0.1:9996/get/{1},User.class,id);}}
12345678910111213141516171819202122232425262728293031325.4 应用配置主要包含springboot的application.propertiesapplication.propertiesserver.port9991
server.tomcat.uri-encodingUTF-8
1235.5 启动类package com.ekeyfund.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplication
public class SpringcloudConsumerH5Application {public static void main(String[] args) {SpringApplication.run(SpringcloudConsumerH5Application.class, args);}
}12345678910111213145.6 测试服务调用9991端口的服务消费者会调用9996端口的服务提供者接口。 通常在实际的开发中会遇到类似的情景:例如PC/H5/Android/IOS会去调用User模块的登录服务。弊端:因为程序调用的IP和端口采用了硬编码而IP和端口可能变更,因此难以维护。 而当服务提供者宕机后服务会不可用后面会在系统中引入服务注册、发现组件该组件主要是维护了一个服务注册表服务提供者和消费者将服务注册到该注册表中而服务注册和发现组件会通过发送心跳来判断服务是否可用。六 使用Eureka实现服务发现组件所属maven模块:springcloud-eureka-server1 pom.xml?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.ekeyfund.springcloud/groupIdartifactIdspringcloud-eureka-server/artifactIdpackagingjar/packagingnamespringcloud-eureka-server/namedescriptionSpringCloud Eureka Server /descriptionparentgroupIdcom.ekeyfund.springcloud/groupIdartifactIdspringcloud-parent/artifactIdversion2.0.0-SNAPSHOT/versionrelativePath../pom.xml/relativePath/parentpropertiesstart-classcom.ekeyfund.springcloud.SpringcloudEurekaServerApplication/start-class/properties/project
1234567891011121314151617181920212223242526272829302 编写启动类在启动类上添加EnableEurekaServer注解声明这是一个Eureka Serverpackage com.ekeyfund.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;/*** 单点eureka server*/
EnableEurekaServer //启用Eureka Server
SpringBootApplication
public class SpringcloudEurekaServerApplication {public static void main(String[] args) {SpringApplication.run(SpringcloudEurekaServerApplication.class, args);}
}123456789101112131415161718193 在应用配置文件application.properties添加如下内容:spring.application.namespringcloud-cureka-server
server.port9999
eureka.instance.hostname127.0.0.1
#定义注册中心的地址
eureka.client.serviceUrl.defaultZonehttp://${eureka.instance.hostname}:${server.port}/eureka/#不向注册中心注册自己
eureka.client.register-with-eurekafalse
#注册中心的职责就是去维护服务实例不需要去检索服务
eureka.client.fetch-registryfalseeureka.instance.prefer-ip-addresstrue1234567891011124 测试访问Eureka Server运行SpringcloudEurekaServerApplication,在浏览器输入 http://127.0.0.1:9999即可以访问Eureka Server七 服务注册所属maven模块 springcloud-provider-user-service1 pom.xml?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionartifactIdspringcloud-provider-user-service/artifactIdpackagingjar/packagingnamespringcloud-user-service/namedescriptionSpringCloud User Service Application/descriptionparentgroupIdcom.ekeyfund.springcloud/groupIdartifactIdspringcloud-parent/artifactIdversion2.0.0-SNAPSHOT/versionrelativePath../pom.xml/relativePath/parentpropertiesstart-classcom.ekeyfund.springcloud.SpringcloudUserServiceMasterApplication/start-class/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-jpa/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!-- eureka client--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-eureka/artifactId/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdconfigurationmainClass${start-class}/mainClasslayoutZIP/layout/configurationexecutionsexecutiongoalsgoalrepackage/goal/goals/execution/executions/plugin/plugins/build
/project
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263642 在application.properties文件中添加以下配置:#####Eureka Client Config########设置服务名称
spring.application.namespringcloud-provider-user-service
#eureka 单实例配置
#eureka.client.service-url.defaultZonehttp://127.0.0.1:9999/eureka
eureka.instance.prefer-ip-addresstrue1234567其中spring.application.name是指定注册到Eureka Server上的应用名称 eureka.instance.prefer-ip-address表示将自己的IP注册到Eureka Server3 编写启动类在启动类上添加EnableDiscoveryClient注解声明这是一个Eureka Clientpackage com.ekeyfund.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;EnableDiscoveryClient//激活Eureka中的DiscoveryClient实现(自动化配置,创建DiscoveryClient接口针对Eureka客户端的EurekaDiscoveryClient实例)
SpringBootApplication
public class SpringcloudUserServiceApplication {public static void main(String[] args) {SpringApplication.run(SpringcloudUserServiceMasterApplication.class, args);}
}
1234567891011121314154 测试服务注册 首先运行SpringcloudEurekaServerApplication启动Eureka Server,然后启动SpringcloudUserServiceApplication,启动Eureka Client。 访问Eureka Server,效果如下图: 八 Eureka Server 高可用实现在生产环境中如果Eureka Server所在的机器发生宕机那么服务发现组件将会变得不可用因此需要实现高可用。Eureka Server可以通过运行多个实例并相互注册的方式实现高可用部署实例之间会彼此增量同步信息从而保持所有节点的数据一致。所属maven模块springcloud-eureka-server-ha该模块使用了springboot的多环境配置特性来激活两个Eureka Server,因此准备了application.properties,application-master.properties和application-slave.properties三个配置文件application.propertiesspring.profiles.activemaster
##使用ip地址的形式定义注册中心的地址
eureka.instance.prefer-ip-addresstrue
#禁用自我保护模式
#eureka.server.enable-self-preservationfalse###eureka server 启用安全验证
#security.user.nametony
#security.user.password666666
#security.basic.enabledtrue##服务续约任务的调用间隔时间默认为30s
#eureka.instance.lease-renewal-interval-in-seconds3
###定义服务失效的时间默认是90s
#eureka.instance.lease-expiration-duration-in-seconds540
12345678910111213141516application-master.propertiesspring.application.namespringcloud-eureka-server-ha
server.port9998eureka.instance.hostname127.0.0.1
eureka.client.serviceUrl.defaultZonehttp://${eureka.instance.hostname}:9997/eureka/12345application-slave.propertiesspring.application.namespringcloud-eureka-server-ha
server.port9997eureka.instance.hostname127.0.0.1
eureka.client.serviceUrl.defaultZonehttp://${eureka.instance.hostname}:9998/eureka/12345同时准备两个启动类用来启动两个Eureka ServerSpringcloudEurekaMasterServerApplication.javapackage com.ekeyfund.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;EnableEurekaServer
SpringBootApplication
public class SpringcloudEurekaMasterServerApplication {public static void main(String[] args) {SpringApplication.run(SpringcloudEurekaMasterServerApplication.class, args);}
}
123456789101112131415SpringcloudEurekaSlaveServiceApplication.javapackage com.ekeyfund.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;EnableEurekaServer
SpringBootApplication
public class SpringcloudEurekaSlaveServiceApplication {public static void main(String[] args) {SpringApplication.run(SpringcloudEurekaSlaveServiceApplication.class, args);}
}
123456789101112131415分别运行SpringcloudEurekaMasterServerApplication和SpringcloudEurekaSlaveServiceApplication后会发现两个注册中心已经完成相互注册9998端口的Eureka Server 9997端口的Eureka Server 所属maven模块 springcloud-provider-user-service服务提供者的服务注册只需要改变application.properties的注册地址即可#####Eureka Client Config########设置服务名称
spring.application.namespringcloud-provider-user-service
#指定服务注册中心的地址 ###高可用改造后可以加上多个注册中心的地址
eureka.client.service-url.defaultZonehttp://127.0.0.1:9998/eureka/,http://127.0.0.1:9997/eureka/eureka.instance.prefer-ip-addresstrue#####Eureka Client Config########指定服务提供者的端口
server.port999612345678910111213刷新Eureka Server,查看高可用的Eureka Serveruser服务同时注册在两个Eureka Server九 Eureka Server实现安全验证默认情况下Eureka Server允许匿名访问这里创建一个需要登录后才能访问Eureka Server在pom.xml中添加安全依赖dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-security/artifactId/dependency1234然后在application.properties中添加http basic验证配置##eureka server 启用安全验证
security.user.nametony
security.user.password666666
security.basic.enabledtrue1234运行SpringcloudEurekaMasterServerApplication或者SpringcloudEurekaSlaveServerApplication后访问Eureka Server需要提供用户名和密码才能访问 将服务注册到需要认证的Eureka Server,只需要将eureka.client.serviceUrl.defaultZone配置为http://user:password127.0.0.1:9998/eureka/,http://user:password127.0.0.1:9997/eureka/即可例如 高可用Eureka Server的注册地址变更为masterspring.application.namespringcloud-eureka-server-ha
server.port9998eureka.instance.hostname127.0.0.1
eureka.client.serviceUrl.defaultZonehttp://tony:666666${eureka.instance.hostname}:9997/eureka/12345slavespring.application.namespringcloud-eureka-server-ha
server.port9997eureka.instance.hostname127.0.0.1
eureka.client.serviceUrl.defaultZonehttp://tony:666666${eureka.instance.hostname}:9998/eureka/12345十 使用Ribbon实现客户端负载均衡所属maven模块:springcloud-consumer-h5-ribbon-hystrixRibbon是Netflix发布的负载均衡器,有助于控制HTTP和TCP客户端的行为为Ribbon配置服务提供者地址列表后Ribbon可以基于负载均衡算法(例如轮询、随机)自动的帮助消费者去请求。 在SpringCloud中,当Ribbon与Eureka配合使用时Ribbon可自动从Eureka Server获取服务提供者地址列表并基于负载均衡算法请求其中一个服务提供者实例。10.1 为服务消费者整合Ribbonpom.xml?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.ekeyfund.springcloud/groupIdartifactIdspringcloud-consumer-h5-ribbon-hystrix/artifactIdpackagingjar/packagingnamespringcloud-consumer-h5-ribbon-hystrix/namedescriptionSpring Cloud H5 Appliaction/descriptionparentgroupIdcom.ekeyfund.springcloud/groupIdartifactIdspringcloud-parent/artifactIdversion2.0.0-SNAPSHOT/versionrelativePath../pom.xml/relativePath/parentpropertiesstart-classcom.ekeyfund.springcloud.SpringcloudH5RibbonHystrixApplication/start-class/propertiesdependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-ribbon/artifactId/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-hystrix/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-eureka/artifactId/dependencydependencygroupIdcom.fasterxml.jackson.core/groupIdartifactIdjackson-databind/artifactIdversion2.8.8/version/dependency/dependenciesdependencyManagementdependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-dependencies/artifactIdversion${spring-cloud.version}/versiontypepom/typescopeimport/scope/dependency/dependencies/dependencyManagementbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdconfigurationmainClass${start-class}/mainClasslayoutZIP/layout/configurationexecutionsexecutiongoalsgoalrepackage/goal/goals/execution/executions/plugin/plugins/build/project
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293MVCConfiguration.javapackage com.ekeyfund.springcloud.configuration;import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;import java.util.ArrayList;
import java.util.List;/*** MVCConfiguration** author Liuguanglei 18601767221163.com* create 2017-06-下午1:01*/
Configuration
EnableWebMvc
public class MVCConfiguration extends WebMvcConfigurerAdapter{Beanpublic MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){return new MappingJackson2HttpMessageConverter();}Beanpublic RequestMappingHandlerAdapter requestMappingHandlerAdapter(MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter){RequestMappingHandlerAdapter requestMappingHandlerAdapternew RequestMappingHandlerAdapter();ListHttpMessageConverter? messageConvertersnew ArrayList();messageConverters.add(mappingJackson2HttpMessageConverter);requestMappingHandlerAdapter.setMessageConverters(messageConverters);return requestMappingHandlerAdapter;}BeanLoadBalanced//开启客户端负载均衡public RestTemplate restTemplate(){return new RestTemplate();}
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253相比之前的配置主要是在RestTemplate中添加了LoadBalanced注解即可整合Ribbon实现客户端的负载均衡。UserController.javapackage com.ekeyfund.springcloud.controller;import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.ekeyfund.springcloud.entity.User;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;/*** User Controller** author Liuguanglei 18601767221163.com* create 2017-06-上午12:55*/
RestController
public class UserController {private static final org.slf4j.Logger LOGGER LoggerFactory.getLogger(UserController.class);Autowiredprivate RestTemplate restTemplate;Autowiredprivate LoadBalancerClient loadBalancerClient;GetMapping(/login)public User login(RequestParam String name, RequestParam String password){LOGGER.info(call user service login method);ResponseEntityUser responseEntity this.restTemplate.getForEntity(http://SPRINGCLOUD-PROVIDER-USER-SERVICE/login?name{1},password{2},User.class,name,password);return responseEntity.getBody();}GetMapping(/list)public ListUser list(){User[] usersthis.restTemplate.getForObject(http://SPRINGCLOUD-PROVIDER-USER-SERVICE/list,User[].class);ListUser userList Arrays.asList(users);return userList;}GetMapping(user/get/{id})public User get(PathVariable Long id){return this.restTemplate.getForObject(http://SPRINGCLOUD-PROVIDER-USER-SERVICE/get/id{1},User.class,id);}/*** ribbon负载均衡测试方法*/GetMapping(/log-user-service-instance)public void logUserServiceInstance(){ServiceInstance serviceInstancethis.loadBalancerClient.choose(springcloud-provider-user-service);LOGGER.info(serviceInstance info --- serviceId is serviceInstance.getServiceId() host is serviceInstance.getHost()port is serviceInstance.getPort() );}}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182从UserController中的login,get和list方法可以看出我们将请求地址变更为http://SPRINGCLOUD-PROVIDER-USER-SERVICE,而SPRINGCLOUD-PROVIDER-USER-SERVICE是用户微服务的虚拟主机名当Ribbon和Eureka配合使用时会自动将虚拟主机名映射城微服务的网络地址。在新增的logUserServiceInstance方法中可以通过LoadBalancerClient的API更加直观的获取当前选择的用户微服务节点。启动如下服务 访问地址:http://127.0.0.1:9994/log-user-service-instance观察控制台输出:2017-06-29 11:26:39.112 INFO 13474 — [nio-9994-exec-7] c.e.s.controller.UserController : serviceInstance info — serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9996 2017-06-29 11:26:41.000 INFO 13474 — [nio-9994-exec-8] c.e.s.controller.UserController : serviceInstance info — serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9995 2017-06-29 11:26:42.126 INFO 13474 — [nio-9994-exec-1] c.e.s.controller.UserController : serviceInstance info — serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9996 2017-06-29 11:26:48.926 INFO 13474 — [nio-9994-exec-4] c.e.s.controller.UserController : serviceInstance info — serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9995可以看到此时请求会均匀分布到两个不同用户微服务节点上说明已经实现了负载均衡。application.propertiesspring.application.namespringcloud-consumer-h5-ribbon-hystrix
server.port9994eureka.client.service-url.defaultZonehttp://tony:666666127.0.0.1:9998/eureka/,http://tony:666666127.0.0.1:9997/eureka/
#eureka.instance.prefer-ip-addresstrue##修改服务负载均衡规则为随机
springcloud-provier-user-service.ribbon.NFLoadBalanceRuleClassNamecom.netflix.loadbalancer.RandomRule
123456789十一 使用Feign实现声明式REST调用Feign是Netflix公司开发的声明式、模板化的HTTP客户端其主要用途是更加便捷、优雅的调用HTTP API,Spring Cloud在原有基础上使Feign支持SpringMVC注解并且整合了Ribbon和Eureka。所属maven模块 springcloud-consumer-h5-feign之前的maven模块springcloud-consumer-h5-ribbon-hystrix是使用RestTemplate(负载均衡是使用ribbon实现)调用RESTful API。 如下的登录方法: GetMapping(/login)public User login(RequestParam String name, RequestParam String password){LOGGER.info(call user service login method);ResponseEntityUser responseEntity this.restTemplate.getForEntity(http://SPRINGCLOUD-PROVIDER-USER-SERVICE/login?name{1},password{2},User.class,name,password);return responseEntity.getBody();}12345678由代码可知通过拼接字符串的方式构造URL,而在其他业务场景中可能还会有更多的参数如果还以这种方式构造URL,那么就会变得更低效难以维护。引入Netflix公司开发的Feign实现声明式的RESTful API 调用pom.xml?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.ekeyfund.springcloud/groupIdartifactIdspringcloud-consumer-h5-feign/artifactIdpackagingjar/packagingnamespringcloud-consumer-h5-feign/namedescriptionSpringCloud Feign H5 Application/descriptionparentgroupIdcom.ekeyfund.springcloud/groupIdartifactIdspringcloud-parent/artifactIdversion2.0.0-SNAPSHOT/versionrelativePath../pom.xml/relativePath/parentpropertiesstart-classcom.ekeyfund.springcloud.SpringcloudFeignH5Application/start-class/propertiesdependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-feign/artifactId/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdconfigurationmainClass${start-class}/mainClasslayoutZIP/layout/configurationexecutionsexecutiongoalsgoalrepackage/goal/goals/execution/executions/plugin/plugins/build/project
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758创建一个Feign接口,并添加FeignClient注解package com.ekeyfund.springcloud.feign;import com.ekeyfund.springcloud.entity.User;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;import java.util.List;/*** User Feign Client** author tony 18601767221163.com* create 2017-06-29-下午2:44* see* since JDK1.8u133*/
FeignClient(value springcloud-provider-user-service) //
public interface UserFeignClient {RequestMapping(value /list,method RequestMethod.GET)ListUser list();RequestMapping(value /login,method RequestMethod.GET)User login(RequestParam(name) String name, RequestParam(password) String password);}
1234567891011121314151617181920212223242526272829FeignClient注解中的springcloud-provider-user-service是一个任意的客户端名称用于创建Ribbon负载均衡器。修改Controller,让其调用Feign接口package com.ekeyfund.springcloud.controller;import com.ekeyfund.springcloud.entity.User;
import com.ekeyfund.springcloud.feign.UserFeignClient;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** User Feign Controller** author Liuguanglei 18601767221163.com* create 2017-06-下午1:50*/
RestController
public class UserFeignController {private static final org.slf4j.Logger LOGGER LoggerFactory.getLogger(UserFeignController.class);AutowiredUserFeignClient userFeignClient;Autowiredprivate LoadBalancerClient loadBalancerClient;GetMapping(value /list)public ListUser list(){return userFeignClient.list();}GetMapping(/login)public User login(RequestParam String name,RequestParam String password){return userFeignClient.login(name,password);}/*** ribbon负载均衡测试方法* springcloud 将feign和ribbon以及eureka进行了集成*/GetMapping(/log-user-service-instance)public void loguserserviceinstance(){ServiceInstance serviceInstancethis.loadBalancerClient.choose(springcloud-provider-user-service);LOGGER.info(serviceInstance info --- serviceId is serviceInstance.getServiceId() host is serviceInstance.getHost()port is serviceInstance.getPort() );}}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556启动类package com.ekeyfund.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;EnableDiscoveryClient
EnableFeignClients //开启SpringCloud Feign的支持功能
SpringBootApplication
public class SpringcloudFeignH5Application {public static void main(String[] args) {SpringApplication.run(SpringcloudFeignH5Application.class, args);}
}
1234567891011121314151617启动如下服务: 访问地址:http://127.0.0.1:9993/login?nametonypassword666666调用login接口返回的结果 访问http://127.0.0.1:9993/log-user-service-instance查看控制台日志输出 2017-06-29 14:56:56.341 INFO 16173 — [nio-9993-exec-4] c.e.s.controller.UserFeignController : serviceInstance info — serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9995 2017-06-29 14:56:58.055 INFO 16173 — [nio-9993-exec-5] c.e.s.controller.UserFeignController : serviceInstance info — serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9996 2017-06-29 14:56:59.310 INFO 16173 — [nio-9993-exec-6] c.e.s.controller.UserFeignController : serviceInstance info — serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9995 2017-06-29 14:57:05.287 INFO 16173 — [nio-9993-exec-7] c.e.s.controller.UserFeignController : serviceInstance info — serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9996 2017-06-29 14:57:06.340 INFO 16173 — [nio-9993-exec-8] c.e.s.controller.UserFeignController : serviceInstance info — serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9995以上结果说明不仅实现了声明式的Restful API调用还实现了客户端的负载均衡十二 使用Hystrix实现微服务的容错处理pom.xml?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.ekeyfund.springcloud/groupIdartifactIdspringcloud-consumer-h5-ribbon-hystrix/artifactIdpackagingjar/packagingnamespringcloud-consumer-h5-ribbon-hystrix/namedescriptionSpring Cloud H5 Appliaction/descriptionparentgroupIdcom.ekeyfund.springcloud/groupIdartifactIdspringcloud-parent/artifactIdversion2.0.0-SNAPSHOT/versionrelativePath../pom.xml/relativePath/parentpropertiesstart-classcom.ekeyfund.springcloud.SpringcloudH5RibbonHystrixApplication/start-class/propertiesdependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-ribbon/artifactId/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-hystrix/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-eureka/artifactId/dependencydependencygroupIdcom.fasterxml.jackson.core/groupIdartifactIdjackson-databind/artifactIdversion2.8.8/version/dependency/dependenciesdependencyManagementdependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-dependencies/artifactIdversion${spring-cloud.version}/versiontypepom/typescopeimport/scope/dependency/dependencies/dependencyManagementbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdconfigurationmainClass${start-class}/mainClasslayoutZIP/layout/configurationexecutionsexecutiongoalsgoalrepackage/goal/goals/execution/executions/plugin/plugins/build/project
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495启动类:添加EnableCircuitBreaker为项目启动断路器支持package com.ekeyfund.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;EnableCircuitBreaker //启动断路器支持
EnableDiscoveryClient
SpringBootApplication
public class SpringcloudH5RibbonHystrixApplication {public static void main(String[] args) {SpringApplication.run(SpringcloudH5RibbonHystrixApplication.class, args);}
}
1234567891011121314151617181920修改UserController让其中的list方法具备容错能力package com.ekeyfund.springcloud.controller;import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.ekeyfund.springcloud.entity.User;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;/*** User Controller** author Liuguanglei 18601767221163.com* create 2017-06-上午12:55*/
RestController
public class UserController {private static final org.slf4j.Logger LOGGER LoggerFactory.getLogger(UserController.class);Autowiredprivate RestTemplate restTemplate;Autowiredprivate LoadBalancerClient loadBalancerClient;GetMapping(/login)public User login(RequestParam String name, RequestParam String password){LOGGER.info(call user service login method);ResponseEntityUser responseEntity this.restTemplate.getForEntity(http://SPRINGCLOUD-PROVIDER-USER-SERVICE/login?name{1},password{2},User.class,name,password);return responseEntity.getBody();}HystrixCommand(fallbackMethod listFallback,commandProperties {HystrixProperty(nameexecution.isolation.thread.timeoutInMilliseconds,value 50000),HystrixProperty(name metrics.rollingStats.timeInMilliseconds,value 10000)},threadPoolProperties {HystrixProperty(name coreSize,value 1),HystrixProperty(namemaxQueueSize,value 20)})GetMapping(/list)public ListUser list(){User[] usersthis.restTemplate.getForObject(http://SPRINGCLOUD-PROVIDER-USER-SERVICE/list,User[].class);ListUser userList Arrays.asList(users);return userList;}/*** 当list方法所在的服务不可用时,会调用此方法* return*/public ListUser listFallback(){User user new User();user.setName(admin);ListUser userListnew ArrayList();userList.add(user);return userList;}GetMapping(user/get/{id})public User get(PathVariable Long id){return this.restTemplate.getForObject(http://SPRINGCLOUD-PROVIDER-USER-SERVICE/get/id{1},User.class,id);}/*** ribbon负载均衡测试方法*/GetMapping(/log-user-service-instance)public void loguserserviceinstance(){ServiceInstance serviceInstancethis.loadBalancerClient.choose(springcloud-provider-user-service);LOGGER.info(serviceInstance info --- serviceId is serviceInstance.getServiceId() host is serviceInstance.getHost()port is serviceInstance.getPort() );}}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101由代码可知为list方法添加一个回退方法listFallback,该方法与list方法具有相同的参数和返回值类型。在list方法上使用注解HystrixCommand的fallBackMethod属性,指定回退方法是listFallback。启动如下服务: 访问地址:http://127.0.0.1:9994/list 当服务状态可用时的返回结果 关掉两个springcloud-provider-user-service进程后 再次访问http://127.0.0.1:9994/list 返回默认用户信息