Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

零散知识收集 #1

Open
afredlyj opened this issue Dec 24, 2015 · 6 comments
Open

零散知识收集 #1

afredlyj opened this issue Dec 24, 2015 · 6 comments

Comments

@afredlyj
Copy link
Owner

  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 afredlyj closed this as completed Jan 1, 2016
@afredlyj afredlyj changed the title 面试题 todo Jan 1, 2016
@afredlyj afredlyj reopened this Jan 1, 2016
@afredlyj
Copy link
Owner Author

afredlyj commented Jan 1, 2016

一致性哈希

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

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

  1. ShardedJedis#downside
  2. Dynamic sharding implementation

@afredlyj afredlyj changed the title todo 零散知识收集 Jan 1, 2016
@afredlyj
Copy link
Owner Author

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
Copy link
Owner Author

afredlyj commented Mar 3, 2016

Java 动态代理

JDK (通过实现接口)

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

  • 获取RealSubject上的接口列表;
  • 确定要生成的代理类的类名,一般是com.sun.proxy.$ProxyXXXX ;
  • 根据需要实现的接口信息,在代码中动态创建该Proxy类的字节码;
  • 将对应的字节码转换成对应的class对象;
  • 创建InvocationHandler实例,用来处理所有的Proxy方法调用,也就是说,对于Proxy对象的任意方法调用,都会转到InvocationHandler实例中来;
  • Proxy的class对象以创建的InvocationHandler对象为参数,实例化一个Proxy对象。

使用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
Copy link
Owner Author

afredlyj commented Apr 6, 2016

类初始化

类初始化包括三个步骤:

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

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

  • 创建类的实例
  • 访问某个类或者接口的静态变量,或者对该静态变量赋值(如果访问静态编译时常量(即编译时可以确定值的常量)不会导致类的初始化)
  • 调用类的静态方法
  • 反射(Class.forName(xxx.xxx.xxx))
  • 初始化一个类的子类(相当于对父类的主动使用),不过直接通过子类引用父类元素,不会引起子类的初始化
  • Java虚拟机被标明为启动类的类(包含main方法的)

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

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

@afredlyj
Copy link
Owner Author

@afredlyj
Copy link
Owner Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant