afredlyj / mynote

idea and note
1 stars 0 forks source link

零散知识收集 #1

Open afredlyj opened 8 years ago

afredlyj commented 8 years ago
  1. 一致性哈希算法原理与实现
  2. redis单线程和持久化
  3. socket编程
  4. 自己实现quartz
  5. dubbo 作者实现的简易RPC http://javatar.iteye.com/blog/1123915
  6. Redis Sentinel 机制 http://redis.io/topics/sentinel
  7. 发现一个比较好的技术博客 http://javarevisited.blogspot.jp/2011/07/java-multi-threading-interview.html
afredlyj commented 8 years ago

一致性哈希

可以参考Jedis,利用TreeMap实现,哈希算法采用MurmurHash。 每个Shard都有权重,权重越大,分配的虚拟节点越多,命中的概率也就越大。

ShardedJedis并没有实现节点动态新增和移除,参考文档如下:

  1. ShardedJedis#downside
  2. Dynamic sharding implementation
afredlyj commented 8 years ago

ProxoolDataSource 未配置alias导致初始化失败

项目在新增业务功能之后,数据源一直初始化失败,异常日志如下:


### Cause: java.lang.IllegalArgumentException: For logger [org.logicalcobwebs.proxool] child name [org.logicalcobwebs.proxool.${mysql passed as parameter, may not include '.' after index27
    at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:23)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:104)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:95)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:354)
    ... 12 more
Caused by: java.lang.IllegalArgumentException: For logger [org.logicalcobwebs.proxool] child name [org.logicalcobwebs.proxool.${mysql passed as parameter, may not include '.' after index27
    at ch.qos.logback.classic.Logger.createChildByName(Logger.java:357)
    at ch.qos.logback.classic.LoggerContext.getLogger(LoggerContext.java:143)
    at ch.qos.logback.classic.LoggerContext.getLogger(LoggerContext.java:45)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:277)
    at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:156)
    at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:704)
    at org.logicalcobwebs.proxool.ConnectionPool.<init>(ConnectionPool.java:113)
    at org.logicalcobwebs.proxool.ConnectionPoolManager.createConnectionPool(ConnectionPoolManager.java:93)
    at org.logicalcobwebs.proxool.ProxoolFacade.registerConnectionPool(ProxoolFacade.java:109)
    at org.logicalcobwebs.proxool.ProxoolDataSource.registerPool(ProxoolDataSource.java:140)
    at org.logicalcobwebs.proxool.ProxoolDataSource.getConnection(ProxoolDataSource.java:94)
    at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)
    at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)
    at org.mybatis.spring.transaction.SpringManagedTransaction.openConnection(SpringManagedTransaction.java:80)
    at org.mybatis.spring.transaction.SpringManagedTransaction.getConnection(SpringManagedTransaction.java:66)
    at org.apache.ibatis.executor.BaseExecutor.getConnection(BaseExecutor.java:279)
    at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:69)
    at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:56)
    at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:267)
    at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:141)
    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:105)
    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:81)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:101)
    ... 18 more

直觉是配置文件有问题,对比线上和线下配置,线上缺少配置节点mysql.name,而dataSource配置文件需要该数据:

<property name="alias" value="${mysql.name}"></property>

生成线程dump文件,用VisualVM打开,通过OQL控制台查询

select x from org.logicalcobwebs.proxool.ProxoolDataSource x

找到alias属性,发现值为${mysql.name},也就是说未读取到配置文件的数据,验证了之前的猜想。

新增功能没有改动数据库这块的代码,为什么会有影响?

查看代码提交记录,发现间接引用了两个日志相关的包log4j-over-slf4jjcl-over-slf4j,尝试将这两个包排除,服务启动正常。所以解决办法有两个:

  1. 配置文件中增加节点mysql.name
  2. 排除log4j-over-slf4jjcl-over-slf4j两个依赖。
afredlyj commented 8 years ago

Java 动态代理

JDK (通过实现接口)

运用JDK的动态代理,如果要创建某个对象(该对象的类是RealSubject)的代理对象,JDK会做如下工作:

使用JDK动态代理时,需要关注两个类:

// InvocationHandler.java
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

其中proxy为生成的代理类对象,method为代理类实现的接口方法,args为调用该方法的参数。另外还有:

// Proxy.java
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

其中,loader为加载代理类的ClassLoader,interfaces为该代理类要实现的接口,对代理对象的所有方法调用最终都被转到h中。

如果想看将代理类的Class对象保存到磁盘,可以使用sun.misc.ProxyGenerator.generateProxyClass(String proxyName,class[] interfaces),需要注意的是,Proxy类是被public final修饰的,包括类和方法。

CGLIB (通过继承,Code Generation Library)

与JDK提供的动态代理方案相比,CGLIB不需要实现接口。在JDK的方案中,某个类必须有实现的接口,并且生成的代理类直接实现接口的方法,如果RealSubject中有自己的方法,在动态代理中是无法使用的。

关于以上两种动态代理,这里说得清楚,也是我借鉴的文章。

简易rpc框架

afredlyj commented 8 years ago

类初始化

类初始化包括三个步骤:

  1. 加载 由类加载器执行,查找字节码,并创建Class对象;
  2. 链接 包括验证、准备和解析三个步骤;
  3. 初始化

根据java虚拟机规范,所有java虚拟机实现必须在每个类或接口被java程序首次主动使用时才初始化。 主动使用有以下6种:

类与接口的初始化不同,如果一个类被初始化,则其父类或父接口也会被初始化,但如果一个接口初始化,则不会引起其父接口的初始化。

参考文档:http://www.cnblogs.com/zhguang/p/3154584.html

afredlyj commented 8 years ago

http://hot66hot.iteye.com/blog/2155036

afredlyj commented 8 years ago

异常

http://normanmaurer.me/blog/2013/11/09/The-hidden-performance-costs-of-instantiating-Throwables/