Spring Boot部署到Resin遇到的问题

Spring-boot-1.3.1

Resin-4.0.47

部署Spring Boot到Resin后,出现异常:

2016-01-23 23:41:02,334 [WARN ] o.s.b.f.s.DefaultListableBeanFactory - Bean creation exception on FactoryBean type check: org.springframework.beans.factory.U

nsatisfiedDependencyException: Error creating bean with name 'userWoundedArmyMapper' defined in URL [jar:file:/opt/resin-test/webapps/rabbit-webapp/WEB-INF/l

ib/rabbit-dao-0.0.1-SNAPSHOT.jar!/com/qiyun/persistence/UserWoundedArmyMapper.class]: Unsatisfied dependency expressed through bean property 'sqlSessionFacto

ry': : Error creating bean with name 'org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration': Injection of autowired dependencies failed; nested exc

eption is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.mybatis.spring.boot.autoconfigure.MybatisProperties

org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration.properties; nested exception is org.springframework.beans.factory.BeanCreationException: Error

creating bean with name 'mybatis.CONFIGURATION_PROPERTIES': Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: Could not ini

tialize class org.hibernate.validator.internal.engine.ConfigurationImpl; nested exception is org.springframework.beans.factory.BeanCreationException: Error c

reating bean with name 'org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration': Injection of autowired dependencies failed; nested exception is org.

springframework.beans.factory.BeanCreationException: Could not autowire field: private org.mybatis.spring.boot.autoconfigure.MybatisProperties org.mybatis.sp

ring.boot.autoconfigure.MybatisAutoConfiguration.properties; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean

with name 'mybatis.CONFIGURATION_PROPERTIES': Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: Could not initialize class

org.hibernate.validator.internal.engine.ConfigurationImpl

-  -

2016-01-23 23:41:02,894 [WARN ] o.s.b.f.s.DefaultListableBeanFactory - Bean creation exception on FactoryBean type check: org.springframework.beans.factory.U

nsatisfiedDependencyException: Error creating bean with name 'userWoundedArmyMapper' defined in URL [jar:file:/opt/resin-test/webapps/rabbit-webapp/WEB-INF/l

ib/rabbit-dao-0.0.1-SNAPSHOT.jar!/com/qiyun/persistence/UserWoundedArmyMapper.class]: Unsatisfied dependency expressed through bean property 'sqlSessionFacto

ry': : Error creating bean with name 'sqlSessionFactory': Requested bean is currently in creation: Is there an unresolvable circular reference?; nested excep

tion is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'sqlSessionFactory': Requested bean is currently in

creation: Is there an unresolvable circular reference?

异常的大概问题就是,创建'userWoundedArmyMapper'时失败,因为无法注入sqlSessionFactory失败。

而sqlSessionFactory在MybatisAutoConfiguration中创建的,故需要先创建MybatisAutoConfiguration,在创MybatisAutoConfiguration时失败,因为无法注入MybatisProperties。

创建MybatisProperties后,初始化MybatisProperties失败,因为它的初始化是由ConfigurationPropertiesBindingPostProcessor进行初始化的,在ConfigurationPropertiesBindingPostProcessor中,使用了Javax Validation,在应用中使用了Hibernate的Validation实现,找不到ConfigurationImpl的定义。

进行远程Debug,并结合jvminspect.jar,发现Resin/lib目录下存在validation-api和hibernate-validator,且版本与项目引用的版本不一致。

ConfigurationImpl类,发现静态代码块

static{

Version.touch();

}

private static final Log log = LoggerFactory.make();

LoggerFactory类的make方法:

public static Log make() {

Throwable t =newThrowable();

StackTraceElement directCaller = t.getStackTrace()[1];

returnLogger.getMessageLogger( Log.class, directCaller.getClassName() );

}

其中使用了jboss的logging,很有可能是jboss logging存在多个版本导致ConfigurationImpl静态代码块执行失败,发现Resin/lib下存在jboss-logging,于是问题明朗了。

由于重复的validation-api、hibernate-validator、jboss-logging,导致加载ConfigurationImpl后进行静态代码块执行时,引用jboss logger错误,导致ConfigurationImpl出现NoClassDefFoundError。

解决方法:删除Resin/lib下的validation-api、hibernate-validator、jboss-loggingjar包。

之后,又出现了另外的问题:

java.lang.IndexOutOfBoundsException: Index: 0, Size: 0

at java.util.ArrayList.rangeCheck(ArrayList.java:635) ~[na:1.7.0_67]

at java.util.ArrayList.get(ArrayList.java:411) ~[na:1.7.0_67]

at com.caucho.server.webapp.WebApp.hasListener(WebApp.java:2197) ~[resin.jar:4.0.47]

at com.caucho.server.webapp.WebApp.addListenerObject(WebApp.java:2148) ~[resin.jar:4.0.47]

at com.caucho.server.webapp.WebApp.addListener(WebApp.java:2108) ~[resin.jar:4.0.47]

经过查看Resin源码,发现这是resin-4.0.45版本中引入的bug:

/**

* Returns true if a listener with the given type exists.

*/

public boolean hasListener(ArrayList listeners, Class listenerClass)

{

for (int i = 0; i < listeners.size(); i++) {

Object listener = _listeners.get(i);

if (listener.getClass().equals(listenerClass)) {

return true;

}

}

return false;

}

其中Object listener = _listeners.get(i);的_listeners使用了类属性,而不是参数listeners,导致异常,这个BUG只能等后续版本修复。

于是,我下载了未引入这个BUG的Resin-4.0.44版本,运行之后,又发现了新的问题:

Custom bean class '{0}' is not public.  Bean classes must be public, concrete, and have a zero-argument constructor.

经过查看Resin源码,发现com.caucho.server.dispatch.FilterConfigImpl的setFilterClass方法:

@DisableConfig

public void setFilterClass(Class filterClass)

{

this._filterClass = filterClass;

Config.validate(this._filterClass, Filter.class);

}

这又是Resin的一个BUG,当直接添加Filter对象到ServletContext时,Resin还会去验证Filter的CLass是不是public的类。这个Bug在Resin-4.0.46中修复了。

servlet: drop instantiation check for instances of servlets and filters (#5934)

@DisableConfig

public void setFilterClass(Class filterClass)

{

_filterClass = filterClass;

if (_filter == null)

Config.validate(_filterClass, Filter.class);

}

为了解决这个问题,必须使用Resin-4.0.46以后的版本。

综合Resin上诉2个BUG,导致Resin目前没有一个版本可以完美支持Spring Boot,只能换Tomcat和Jetty了。

你可能感兴趣的:(Spring Boot部署到Resin遇到的问题)