基于spring4.0配置分布式ehcache,以及相关使用
说明:本文是基于RMI手动同步的方式,使用程序动态注入配置缓存,抛弃传统的ehcache.xml配置方式
1,注入cacheManager管理所有缓存,添加各个缓存名及相关参数配置:
思路大致是:
在项目的主配置类中,通过@Bean注入cacheManager,统一管理所有cache,传统的用xml方式配置太累赘,其实只需要更该chacheName,其他参数变化不是很大,考虑用程序封装做到最大程度的代码重用所以采取拼接JSON串的形式,配置缓存名,及所有相关需要设置好的参数。然后通过解析JSON,拼接成带主机IP的RmiUrl,以manual手动rmi同步的方式配置peerDiscovery成员发现,再通过配置cacheManagerPeerListenerFactory这个类启动本机监听程序,来发现其他主机发来的同步请求。最后再用@EnableCaching注解开启spring支持对ehcache注解使用
下面是项目配置好的详细代码:
package com.cshtong.tower.web.init; import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties; import javax.annotation.Resource; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.interceptor.SimpleKeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cshtong.tower.service.UserService;
import com.cshtong.tower.util.StringUtil; import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.config.DiskStoreConfiguration;
import net.sf.ehcache.config.FactoryConfiguration;
import net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory;
import net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory;
import net.sf.ehcache.distribution.RMICacheReplicatorFactory;
import net.sf.ehcache.store.MemoryStoreEvictionPolicy; @EnableCaching
@Configuration
@EnableTransactionManagement
public class EhcacheConfig extends RMICacheReplicatorFactory{ private static Logger logger = LoggerFactory.getLogger(EhcacheConfig.class);
private static final String EHCACHE_PROPERTIES = "ehcache.properties"; /** 最大缓存数量 0 = no limit. **/
private static final Integer MAX_CACHE = 0;
/** 缓存失效时间间隔/秒 **/
private static final Integer TIME_TOLIVE_SECONDS = 24*60*60;
/** 缓存闲置多少秒后自动销毁 **/
private static final Integer TIME_TOIDLE_SECONDS = 60*60;
/** 磁盘失效线程运行时间间隔/秒。 **/
private static final Integer DISK_EXPIRY_Thread_INTERVAL_SENCONDS = 100; @Resource
UserService userService; /** 注入cacheManager **/
@Bean
public org.springframework.cache.CacheManager cacheManager() {
org.springframework.cache.CacheManager cm = new EhCacheCacheManager(putCache());
return cm;
} @Bean
public KeyGenerator keyGenerator() {
return new SimpleKeyGenerator();
} @Bean
public CacheManager putCache(){ String rmiUrls = initRmiURLs(); net.sf.ehcache.config.Configuration cf = new net.sf.ehcache.config.Configuration();
Properties pro = initRmiUrlsProperties();
if (null!=rmiUrls) {
/** 临时文件目录 **/
cf.diskStore(new DiskStoreConfiguration().path("java.io.tmpdir"))
/**成员发现 peerDiscovery 方式:manual:手动,rmiUrls:主机名+端口号+缓存名,用来接受或者发送信息的接口,不同的缓存或者机器用“|”隔开 **/
.cacheManagerPeerProviderFactory(new FactoryConfiguration<FactoryConfiguration<?>>()
.className(RMICacheManagerPeerProviderFactory.class.getName())
.properties("peerDiscovery=manual,rmiUrls=" + rmiUrls)
);
/** 本机监听程序,来发现其他主机发来的同步请求 hostName=192.168.1.112 这里默认是本机可以不配置 **/
cf.cacheManagerPeerListenerFactory(new FactoryConfiguration<FactoryConfiguration<?>>()
.className(RMICacheManagerPeerListenerFactory.class.getName())
.properties("port="+ pro.getProperty("rmiPortNumber") +",socketTimeoutMillis=2000")
);
}else{
logger.debug("The rmiUrls is null!!");
} CacheManager cm = null; try {
cm = CacheManager.create(cf);
} catch (UncheckedIOException e) {
logger.debug("Fail to load config. message:{}", e.getMessage());
} List<Cache> array = null;
try {
array = cacheCollection();
} catch (CacheException e) {
logger.error("collect cache Failed");
} for (Cache list:array) {
cm.addCache(list);
} return cm;
} public static List<Cache> cacheCollection(){
String listParameters = cacheParametersCollection();
return cacheConf(listParameters);
} /**
* 添加缓存的参数
* 相关属性:
name : "缓存名称,cache的唯一标识(ehcache会把这个cache放到HashMap里)
maxElementsInMemory : 缓存最大个数,0没有限制。
eternal="false" : 对象是否永久有效,一但设置了,timeout将不起作用。 (必须设置)
maxEntriesLocalHeap="1000" : 堆内存中最大缓存对象数,0没有限制(必须设置)
maxEntriesLocalDisk= "1000" : 硬盘最大缓存个数。
overflowToDisk="false" : 当缓存达到maxElementsInMemory值是,是否允许溢出到磁盘(必须设设置)(内存不足时,是否启用磁盘缓存。)
diskSpoolBufferSizeMB : 这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
diskPersistent="false" : 磁盘缓存在JVM重新启动时是否保持(默认为false)硬盘持久化
timeToIdleSeconds="0" : 导致元素过期的访问间隔(秒为单位),即当缓存闲置n秒后销毁。 当eternal为false时,这个属性才有效,0表示可以永远空闲,默认为0
timeToLiveSeconds="0" : 元素在缓存里存在的时间(秒为单位),即当缓存存活n秒后销毁. 0 表示永远存在不过期
memoryStoreEvictionPolicy="LFU" : 当达到maxElementsInMemory时,如何强制进行驱逐默认使用"最近使用(LRU)"策略,其它还有先入先出FIFO,最少使用LFU,较少使用LRU
diskExpiryThreadIntervalSeconds :磁盘失效线程运行时间间隔,默认是120秒。
clearOnFlush : 内存数量最大时是否清除。 cacheEventListenerFactory : 给缓存添加监听
replicateAsynchronously=true : 异步的方式
replicatePuts=true,replicateUpdates=true,replicateUpdatesViaCopy=true,replicateRemovals= true : 在put,update,copy,remove操作是否复制
cationIntervalMillis=1000 : 同步时间1s
bootstrapCacheLoaderFactory 启动是指一启动就同步数据
* @return
*/
public static String cacheParametersCollection(){ String listParameters = "[" ; /** 排班:列表详情 **/
listParameters += "{'cacheName':'schedule_listPatrol','maxEntriesLocalHeap':'0'}"; /** APP:用户当月的排班 **/
listParameters += "{'cacheName':'owner_schedule','maxEntriesLocalHeap':'0'}"; /**考勤统计 :echarts图表相关数据**/
listParameters += "{'cacheName':'attendance_findByOrgIds','maxEntriesLocalHeap':'0'}";
/**考勤统计 :主界面表格相关的数据**/
listParameters += "{'cacheName':'attendance_findByOrgIdsAndPage','maxEntriesLocalHeap':'0','timeToIdleSeconds':'0'}"; /** 机构 **/
listParameters += "{'cacheName':'org_findAll','maxEntriesLocalHeap':'0'}"; /** 用户信息 key=userId **/
listParameters += "{'cacheName':'list_userInfo','maxEntriesLocalHeap':'0'}"; /** APP 勤务圈 **/
listParameters += "{'cacheName':'app_message','maxElementsInMemory':'0','maxEntriesLocalHeap':'0'}"; /** 报警,最近1km内的用户 **/
listParameters += "{'cacheName':'rescue_users','maxElementsInMemory':'0','maxEntriesLocalHeap':'0'}"; /** 报警,最近1km内的用户 **/
listParameters += "{'cacheName':'app_message_typeName','maxElementsInMemory':'0','maxEntriesLocalHeap':'0'}"; listParameters += "]"; return listParameters;
} /**
* 添加成员发现: //主机ip+端口号/
* @return
*/
public static List<String> cacheManagerPeerProviderCollection(){
Properties pro = initRmiUrlsProperties(); List<String> ip = new ArrayList<>();
try {
ip.add(pro.get("machine1").toString());
ip.add(pro.get("machine2").toString());
} catch (Exception e) {
logger.error("Fail to provider cacheManagerPeer. config file [{}], message:{}", EHCACHE_PROPERTIES, e.getMessage());
} InetAddress ia;
try {
ia = InetAddress.getLocalHost();
String localip = ia.getHostAddress();
for (int i = 0; i < ip.size(); i++) {
/** 过滤本机ip **/
if (localip.equalsIgnoreCase(ip.get(i))) {
ip.remove(i);
}
}
} catch (UnknownHostException Host) {
Host.printStackTrace();
logger.error("Unknown to host Address. config file [{}], message:{}", EHCACHE_PROPERTIES, Host.getMessage());
} List<String> peer = new ArrayList<>();
for (int j = 0; j < ip.size(); j++) {
peer.add("//" + ip.get(j) + ":" + pro.getProperty("rmiPortNumber").toString());
} return peer;
} public static String initRmiURLs(){
String rmiUrls = "";
String listParameters = cacheParametersCollection();
JSONArray array = initCacheParameters(listParameters);
for (Iterator<Object> iterator = array.iterator(); iterator.hasNext();) {
JSONObject obj = (JSONObject)iterator.next();
String cacheName = obj.get("cacheName").toString();
List<String> peer = cacheManagerPeerProviderCollection();
for (String list:peer) {
rmiUrls += list + cacheName + "|";
}
}
if (!"".equals(rmiUrls)) {
rmiUrls = rmiUrls.substring(0,rmiUrls.length()-1);
}
return rmiUrls;
} public static JSONArray initCacheParameters(String listParameters){
JSONArray array = null;
try {
array = JSONArray.parseArray(listParameters);
} catch (Exception e) {
logger.error("Fail to init The cache parameters. message:{}", e.getMessage());
}
return array;
} public static Properties initRmiUrlsProperties(){
InputStream resourcesStream = EhcacheConfig.class.getClassLoader().getResourceAsStream(EHCACHE_PROPERTIES);
Properties pro = new Properties();
try {
pro.load(resourcesStream);
} catch (IOException e) {
logger.error("Fail to load config. config file [{}], message:{}", EHCACHE_PROPERTIES, e.getMessage());
}
return pro;
} /**
* @param listPatrolParameters 缓存参数JSON数组
* @return 缓存的集合
*/
@SuppressWarnings("deprecation")
public static List<Cache> cacheConf(String listParameters){ List<Cache> listCache = new ArrayList<>();
JSONArray array = initCacheParameters(listParameters);
for (Iterator<Object> iterator = array.iterator(); iterator.hasNext();) {
JSONObject obj = (JSONObject)iterator.next(); String cacheName = obj.get("cacheName").toString();
String maxElementsInMemory = obj.getString("maxElementsInMemory");
String maxEntriesLocalHeap = obj.getString("maxEntriesLocalHeap");
String timeToLiveSeconds = obj.getString("timeToLiveSeconds");
String timeToIdleSeconds = obj.getString("timeToIdleSeconds"); RMICacheReplicatorFactory rmi = new RMICacheReplicatorFactory();
Properties pro = initRmiUrlsProperties();
rmi.createCacheEventListener(pro); CacheConfiguration cacheConfiguration = new CacheConfiguration(cacheName,StringUtil.isNull(maxEntriesLocalHeap)?MAX_CACHE:Integer.parseInt(maxEntriesLocalHeap))
.memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LFU)
.maxElementsInMemory(StringUtil.isNull(maxElementsInMemory)?MAX_CACHE:Integer.parseInt(maxElementsInMemory))
.overflowToDisk(true)
.eternal(false)
.timeToLiveSeconds(StringUtil.isNull(timeToLiveSeconds)?TIME_TOLIVE_SECONDS:Integer.parseInt(timeToLiveSeconds))
.timeToIdleSeconds(StringUtil.isNull(timeToIdleSeconds)?TIME_TOIDLE_SECONDS:Integer.parseInt(timeToIdleSeconds))
.diskPersistent(false)
.diskExpiryThreadIntervalSeconds(DISK_EXPIRY_Thread_INTERVAL_SENCONDS)
.clearOnFlush(true)
.cacheEventListenerFactory(new CacheConfiguration.CacheEventListenerFactoryConfiguration().className(RMICacheReplicatorFactory.class.getName()));
Cache cache = new Cache(cacheConfiguration); listCache.add(cache);
} return listCache;
}
}
properties文件:
#RMICacheReplicatorFactory properties
replicateAsynchronously=true
replicatePuts=true
replicatePutsViaCopy=false
replicateUpdates=true
replicateUpdatesViaCopy=false
replicateRemovals=true
asynchronousReplicationIntervalMillis=1000
asynchronousReplicationMaximumBatchSize=1000 #RMI URLs
machine1=//主机ip+端口号/ #RMI port
rmiPortNumber=8010
到这里就注入好了缓存名为listParameters里面cacheName的所有缓存,如果后续添加或修改缓存,只需更改listParameters的相关属性,如果在集群环境,也只需在porperties文件中添加machine..配置即可。
2,基于注解方式的缓存使用:
1,为方便重用所有缓存建议在service层使用,当方法第一次执行时将返回值以key-value对象写进缓存,之后在执行该方法时,如果缓存的condition满足则直接取缓存返回,实际上方法都不会进!
2,在修改或添加方法使用@CachePut,查询方法使用@Cacheable,删除方法使用@CacheEvict,注意:缓存一定要配合使用,例如一个list方法将相应值缓存起来,如果有针对该值CUD操作时,一定要将新的返回值@CachePut,否则会出现数据脏读的情况!如果更新或修改方法的返回值与list不相同即该缓存@CacheEvict,否则会报数据映射错误!
3,注解说明:
@Cacheable (value="缓存值/SpEL/不填默认返回值", key="缓存key/SpEL") : 应用到读取数据的方法上,即可缓存的方法,如查找方法:先从缓存中读取,如果没有再调用方法获取数据,然后把数据添加到缓存中。如图:
@CachePut 应用到写数据的方法上,如新增/修改方法,调用方法时会自动把相应的数据放入缓存: 如图:
@CacheEvict: 移除数据,如图:
@Caching 组合多个Cache注解使用,如图:
注解参数说明:
value:必须指定,其表示当前方法的返回值是会被缓存在哪个Cache上的,对应Cache的名称, listparamentes中的cacheName
key:通过Spring的EL表达式来指定我们的key。这里的EL表达式可以使用方法参数及它们对应的属性。使用方法参数时我们可以直接使用“#参数名”或者“#p参数index。我们统一采用方法的参数做唯一key,没有参数不写!
condition:有的时候我们可能并不希望缓存一个方法所有的返回结果,condition属性默认为空,表示将缓存所有的调用情形。其值是通过SpringEL表达式来指定的,当为true时表示进行缓存处理;当为false时表示不进行缓存处理,即每次调用该方法时该方法都会执行一次。如下示例表示只有当user的id为偶数时才会进行缓存
@Cacheable(value="users",key="#user.id",condition="#user.id%2==0")
public User find(User user) {
System.out.println("find user by user " + user);
return user;
}
3,基于程序代码方式的缓存相关使用:
当注解不能完全满足需求,或需要在程序代码中实现动态操作时,就需要对ehcache实现相关封装,从而现对缓存手动进行增删改。可以考虑写成util,我这里是以service的形式现实的封装及相关调用,仅供参考。
package com.cshtong.tower.service; import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.List; import javax.annotation.Resource; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import com.alibaba.fastjson.JSONObject;
import com.cshtong.tower.model.MessageType;
import com.cshtong.tower.model.User;
import com.cshtong.tower.repository.MessageTypeRepository; import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element; @Service
public class EhcacheServiceImpl implements EhcacheService{ private static Logger logger = LoggerFactory.getLogger(EhcacheServiceImpl.class); @Resource
private UserService userSerivce; @Resource
private MessageTypeRepository messageTypeRepository; public static CacheManager cacheManager(){ CacheManager cm = null;
try {
cm = CacheManager.newInstance();
} catch (UncheckedIOException e) {
logger.error("Fail to load config, message:{}", e.getMessage());
}
return cm;
} /**
* key可以为空
*/
@SuppressWarnings({"deprecation" })
@Override
public com.cshtong.tower.model.Ehcache findCache(String cacheName, String key) {
com.cshtong.tower.model.Ehcache eh = null;
if (null == key) {
Ehcache cache = cacheManager().getEhcache(cacheName);
eh = new com.cshtong.tower.model.Ehcache();
eh.setCacheName(cache.getName());
List<String> listKey = new ArrayList<>();
for (int j = 0; j < cache.getKeys().size(); j++) {
listKey.add(cache.getKeys().get(j).toString());
}
eh.setKeys(listKey);
eh.setSize(cache.getSize());
/*eh.setHitrate(cache.getStatistics().cacheHitRatio());*/
eh.setDiskStoreSize(cache.getDiskStoreSize());
eh.setMemoryStoreSize(cache.getMemoryStoreSize());
eh.setStatus(cache.getStatus().toString());
}else{
Element el = cacheManager().getEhcache(cacheName).get(key);
if (el == null) {
el = cacheManager().getEhcache(cacheName).get(Integer.parseInt(key));
}
eh = new com.cshtong.tower.model.Ehcache();
eh.setKeyHit(el.getHitCount());
eh.setLastUpdateTime(el.getLastUpdateTime());
eh.setValues(el.getValue());
}
return eh;
} @SuppressWarnings("deprecation")
@Override
public List<com.cshtong.tower.model.Ehcache> listAllEhcahce() {
List<com.cshtong.tower.model.Ehcache> list = new ArrayList<>();
String[] cache = cacheManager().getCacheNames();
List<Ehcache> cachelist = new ArrayList<>();
for (int i = 0; i < cache.length; i++) {
Ehcache c = cacheManager().getEhcache(cache[i]);
cachelist.add(c);
}
for (int i = 0; i < cachelist.size(); i++) {
com.cshtong.tower.model.Ehcache eh = new com.cshtong.tower.model.Ehcache();
eh.setCacheName(cachelist.get(i).getName());
List<String> listKey = new ArrayList<>();
for (int j = 0; j < cachelist.get(i).getKeys().size(); j++) {
listKey.add(cachelist.get(i).getKeys().get(j).toString());
}
eh.setKeys(listKey);
eh.setSize(cachelist.get(i).getSize());
eh.setStatus(cachelist.get(i).getStatus().toString());
eh.setMemoryStoreSize(cachelist.get(i).getMemoryStoreSize());
eh.setDiskStoreSize(cachelist.get(i).getDiskStoreSize());
list.add(eh);
}
return list;
} /**
* 获取缓存
* @param cacheName
* @param key
* @return json字符串
*/
@Override
public String getCache(String cacheName, Object key) {
logger.debug("Getting Cache that name is " + cacheName + "and key is" + key);
Element el = cacheManager().getCache(cacheName).get(key);
return JSONObject.toJSONString(el.getObjectValue());
} @Override
public Cache getCache(String name) {
logger.debug("Getting Cache that name is " + name);
return cacheManager().getCache(name);
} /**
* 获取所有的缓存
* @param names
* @return
*/
@Override
public String[] getCacheNames() {
logger.debug("All of the Cache is " + cacheManager().getCacheNames());
return cacheManager().getCacheNames();
} @Override
public void update(String cacheName, Object key, Object value) {
try {
remove(cacheName, key);
put(cacheName, key, value);
} catch (Exception e) {
logger.debug("Fail to update the Cache,which is " + cacheManager().getCacheNames());
}
} @Override
public void put(String cacheName, Object key, Object value) {
logger.debug("add Cache is " + cacheManager().getCacheNames() + ",and key is " + key + ",and value is" + value);
Element el = new Element(key, value);
cacheManager().getCache(cacheName).put(el);
} @Override
public boolean ishasCache(String cacheName, Object key) {
boolean rs = false;
Element value = cacheManager().getCache(cacheName).get(key);
if (null != value) {
rs = true;
}
return rs;
} /**
* 根据缓存名清除缓存key value
* @param name
*/
@Override
public void evictName(String name) {
logger.debug("delete Cache that name is " + name);
cacheManager().getCache(name).removeAll();
} /**
* 根据缓存名对应的key清除缓存
*/
@Override
public void remove(String cacheName, Object key) {
logger.debug("Delete Cache that Name is "+ cacheName +"and key is " + key );
Cache cache = cacheManager().getCache(cacheName);
cache.remove(key);
} /**
* 清除当前cacheManager的所有缓存
*/
@Override
public void clear() {
logger.debug("clear all cache!!");
cacheManager().clearAll();
} }
以上愚见,只是个人的理解,仅供参考。如有不对的地方,欢迎指正批评....
基于spring4.0配置分布式ehcache,以及相关使用的更多相关文章
- Spring4.0编程式定时任务配置
看过很多定时调度的配置,大多使用XML配置,觉得比较麻烦,也比较老套.这里介绍一种基于spring4.0注解编程式配置定时任务,简单清晰,使用方便.. 至于引入spring相关jar这里不多说,直接切 ...
- Hibernate二级缓存简述及基于Spring4,Hibernate5,Ehcache3的二级缓存配置
Hibernate L2缓存 缓存的分类 L2缓存工作原理 放入二级缓存的数据 Ehcache 依赖 ehcache.xml 常用的memoryStoreEvictionPolicy(缓存算法) eh ...
- 基于Hadoop2.2.0版本号分布式云盘的设计与实现
基于Hadoop2.2.0版本号分布式云盘的设计与实现 一.前言 在学习了hadoop2.2一个月以来,我重点是在学习hadoop2.2的HDFS.即是hadoop的分布式系统,看了非常久的源代码看的 ...
- Spring4.0支持Groovy配置
介绍 前一段时间观注了一下Spring4.0的一些特性,当中就有对Groovy配置的支持.因为临时还没有很深入的研究.所以举个小样例来说明一下怎样支持Groovy配置. package shuai.s ...
- OLE DB访问接口“MICROSOFT.JET.OLEDB.4.0”配置为在单线程单位模式下运行,所以该访问接口无法用于分布式
OLE DB访问接口"MICROSOFT.JET.OLEDB.4.0"配置为在单线程单位模式下运行,所以该访问接口无法用于分布式 数据库操作excel时遇到的以上问题的解决方法 解 ...
- [转]Struts2.3.16.1+Hibernate4.3.4+Spring4.0.2 框架整合
原文地址:http://blog.csdn.net/ycb1689/article/details/22928519 最新版Struts2+Hibernate+Spring整合 目前为止三大框架最新版 ...
- SSM框架整合环境构建——基于Spring4和Mybatis3
目录 环境 配置说明 所需jar包 配置db.properties 配置log4j.properties 配置spring.xml 配置mybatis-spring.xml 配置springmvc.x ...
- 分享 : 警惕MySQL运维陷阱:基于MyCat的伪分布式架构
分布式数据库已经进入了全面快速发展阶段.这种发展是与时俱进的,与人的需求分不开,因为现在信息时代的高速发展,导致数据量和交易量越来越大.这种现象首先导致的就是存储瓶颈,因为MySQL数据库实质上还是一 ...
- .NET 跨平台RPC框架DotNettyRPC Web后台快速开发框架(.NET Core) EasyWcf------无需配置,无需引用,动态绑定,轻松使用 C# .NET 0配置使用Wcf(半成品) C# .NET Socket 简单实用框架 C# .NET 0命令行安装Windows服务程序
.NET 跨平台RPC框架DotNettyRPC DotNettyRPC 1.简介 DotNettyRPC是一个基于DotNetty的跨平台RPC框架,支持.NET45以及.NET Standar ...
随机推荐
- (二)js下拉菜单
默认的select标签比较难看,UI比较漂亮,如果想要实现UI上的下拉样式,好像必须用js写select,从网上拷贝而且修改了一个下拉框,为了方便以后引用所以记录下来. /* diy_select * ...
- Linux 利器- Python 脚本编程入门(一)
导读 众所周知,系统管理员需要精通一门脚本语言,而且招聘机构列出的职位需求上也会这么写.大多数人会认为 Bash (或者其他的 shell 语言)用起来很方便,但一些强大的语言(比如 Python)会 ...
- python 数据结构 初学时没太注意却发现很有用的点点滴滴
1. list.extend(L) 将指定列表中的所有元素附加到另一个列表的末尾:相当于a[len(a):] = L. 2. list.pop([i]) 删除列表中指定位置的元素并返回它.如果未指定索 ...
- Error: failed to fetch platform android
在使用ionic创建项目后,需要添加平台,运行如下命令添加Android平台时: ionic platform add android 1 出现错误: Error: failed to fetch p ...
- OpenCV图像的二值化
图像的二值化: 与边缘检测相比,轮廓检测有时能更好的反映图像的内容.而要对图像进行轮廓检测,则必须要先对图像进行二值化,图像的二值化就是将图像上的像素点的灰度值设置为0或255,这样将使整个图像呈现出 ...
- #Deep Learning回顾#之基于深度学习的目标检测(阅读小结)
原文链接:https://www.52ml.net/20287.html 这篇博文主要讲了深度学习在目标检测中的发展. 博文首先介绍了传统的目标检测算法过程: 传统的目标检测一般使用滑动窗口的框架,主 ...
- java.lang.NoClassDefFoundError: [Lorg/hibernate/engine/FilterDefinition
解决办法: 原先:<bean id="sessionFactory"class="org.springframework.orm.hibernate3.annota ...
- 烂泥:php5.6源码安装及php-fpm配置
LNMP环境的搭建中,现在只有php没有源码安装过.这篇文章就把这个介绍下. 注意本篇文章使用的centos 6.5 64bit. 登陆centos下载php5.6的安装包.php的软件包可以去国内的 ...
- HTML——meta标签
<meta> 元素可提供有关页面的元信息(meta-information),比如针对搜索引擎和更新频度的描述和关键词. <meta> 标签位于文档的头部,不包含任何内容.&l ...
- Factor Combinations
Factor Combinations Problem: Numbers can be regarded as product of its factors. For example, 8 = 2 x ...