诡异的问题,static变量竟然被两个实例引用?好几天睡不着了,大神们来。

小偷家的保安 发布于 2017/03/24 09:43
阅读 710
收藏 1

这个问题,只在idea+jetty启动下出现,在eclipse+jetty、tomcat和weblogic下都不会出现。

已经折磨我好几天了,废话不说上代码。

1.本人写了一个基于jfinal的mybatis的plugin,很简单就是jfinal调用start方法初始化mybatis的factory。

package com.qysoft.rapid.plugin.mybatis;

import java.io.Reader;

import org.apache.ibatis.datasource.DataSourceFactory;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import com.jfinal.plugin.IPlugin;

/**
 * mybatis插件
 * @author liugong
 *
 */
public class MyBatisPlugin implements IPlugin {

	private static SqlSessionFactory sqlSessionFactory;
	private static Reader reader;

	public static SqlSessionFactory getSqlSessionFactory() {
		return sqlSessionFactory;
	}

	private DataSourceFactory ds = null;


	public MyBatisPlugin(DataSourceFactory ds){
		this.ds = ds;
	}

	@Override
	public boolean start() {
		try {
			reader = Resources.getResourceAsReader("config/mybatis/Configuration.xml");
			sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
			Environment environment = new Environment("druid", new JdbcTransactionFactory(), ds.getDataSource());
			sqlSessionFactory.getConfiguration().setEnvironment(environment);
		} catch (Exception e) {
			e.printStackTrace();
		}  
		return true;
	}

	@Override
	public boolean stop() {
		sqlSessionFactory = null;
		return true;
	}

}

2.然后诡异的事情发生了,这个MybatisPlugin的静态变量貌似被不同的MyBatisPlugin的实例引用了,一会儿是初始化的值,一会儿又报NullPointer异常。

这段代码是有值的

public void validateLogin(){
		//获取表单提交的用户名和密码
		String username = getPara("username").trim();;
		String password = getPara("password").trim();
		//绑定登陆凭证
		UsernamePasswordToken token = new UsernamePasswordToken(username, password);
		//获取当前用户
		Subject subject = SecurityUtils.getSubject();
		//执行登陆
		try {
			System.out.println("MainAction里的我:"+MyBatisPlugin.getSqlSessionFactory());
			System.out.println("RapidRealm里的hashcode:"+ MyBatisPlugin.class.hashCode());
			subject.login(token);

这段代码是null

protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {
		UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
		//通过用户名查找人员信息
		Bean ryxx;
		try {
			System.out.println("RapidRealm里的我:"+ MyBatisPlugin.getSqlSessionFactory());
			System.out.println("RapidRealm里的hashcode:"+ MyBatisPlugin.class.hashCode());
			ryxx = RYGLService.queryRyByDm(usernamePasswordToken.getUsername());

而且hashcode也不一样,这是控制台输出。

3.妈蛋,难道是不同的vm么。我来个static块,看看这个贱人类加载了几次。

 */
public class MyBatisPlugin implements IPlugin {

	private static SqlSessionFactory sqlSessionFactory;
	private static Reader reader;

	public static SqlSessionFactory getSqlSessionFactory() {
		return sqlSessionFactory;
	}

	private DataSourceFactory ds = null;

	static{
		System.out.println("我被加载了,我倒要看看你们要加载我几次!");
	}

啊啊啊啊啊啊,妈蛋两次,而且最贱的是,有且仅有两次。刷新一遍,还是它用他的实例,我用这个实例。

第一次,初始化插件的时候

第二次,

刷新一遍程序,不加载了。但是各用各的,而且一直这样它用它的,我用我的。从hashcode前后一致就可以看出来

妈蛋,我疯了,咋回事,难道是两个vm吗,而且最重要的是这个问题在eclipse+jetty、tomcat和weblogic下都不会出现。

求大神,来给我答疑解惑。

加载中
0
小偷家的保安
小偷家的保安

各路大神,走过路过,留下你们的回复

0
小lian
小lian

先围观一下,稍后再来。

0
风翔飞
风翔飞

围观!!!

0
小偷家的保安
小偷家的保安

就这样沉了吗?

0
JFinal
JFinal

IDEA 不支持集成 jetty 时切换 classloader,可能会有问题,升级到 jfinal 3.0, 启动时去掉最后一个 int 参数

小偷家的保安
小偷家的保安
波总,换成3.0确实没问题了。3q,但还是不理解idea+jetty在jfinal2.0为什么会出现重复的classloader
0
刘柳
刘柳

可能是有了多个ClassLoader

0
小偷家的保安
小偷家的保安

引用来自“JFinal”的评论

IDEA 不支持集成 jetty 时切换 classloader,可能会有问题,升级到 jfinal 3.0, 启动时去掉最后一个 int 参数

波总,换成3.0确实没问题了。3q,但还是不理解idea+jetty在jfinal2.0为什么会出现重复的classloader

JFinal
JFinal
其实道理很简单,老版本的 JettyServer.java 中的 changeClassLoader() 方法中少了一个 webApp.setClassLoader(loader); 调用,这个问题只出现在开发阶段,并且只是多 new 了一次对象,影响很小,所以只有一个人曾经发现过
返回顶部
顶部