上篇成功配置了J2SE环境下的 EclipseLink 实现的 JPA:
http://blog.csdn.net/srmana/article/details/56839116
当我试图在Java EE中去配置时,出了问题。
先是试 RAD + WAS, 在 WAS Admin Console-> server -> Java and Process Management -> process definition -> JVM -> generic, 加入 JVM 参数:
-javaagent:C:\Users\IBM_ADMIN\.m2\repository\org\springframework\spring-instrument\4.3.6.RELEASE\spring-instrument-4.3.6.RELEASE.jar
但是不工作!得到错误:
SEVERE: Servlet.service() for servlet [appServlet] in context with path [/SpringMVCCase] threw exception [Handler dispatch failed; nested exception is java.lang.ExceptionInInitializerError] with root cause
java.lang.IllegalStateException: Must start with Java agent to use InstrumentationLoadTimeWeaver. See Spring documentation.
at org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver.addTransformer(InstrumentationLoadTimeWeaver.java:88)
at org.springframework.orm.jpa.persistenceunit.SpringPersistenceUnitInfo.addTransformer(SpringPersistenceUnitInfo.java:82)
at org.eclipse.persistence.jpa.PersistenceProvider.createContainerEntityManagerFactoryImpl(PersistenceProvider.java:373)
at org.eclipse.persistence.jpa.PersistenceProvider.createContainerEntityManagerFactory(PersistenceProvider.java:313)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:353)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:373)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:362)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1081)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:856)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.(AnnotationConfigApplicationContext.java:84)
同样的参数在 J2SE ( Run as -> Run Configurations -> Arguments) 里是生效的。
我又转战 Eclipse + Tomcat: 在 Servers 里双击 tomcat server, 然后点 Open Launch Configuration -> Arguments:
完全一样的错误!!!
于是,我去看出错点的源代码。发现InstrumentationLoadTimeWeaver 从InstrumentationSavingAgent去取Instrumentation, 而类 org.springframework.instrument.InstrumentationSavingAgent 可以被加载,但是InstrumentationSavingAgent.getInstrumentation() 返回空。
试了一下,同样的方法在 J2SE 下返回的不是空:
getInstrumentation = sun.instrument.InstrumentationImpl@d7ba7a3c
网上找到解释:http://www.cnblogs.com/wade-luffy/p/6078446.html
this.loadTimeWeaver = new InstrumentationLoadTimeWeaver(classLoader);
这句代码不仅仅是实例化了一个InstrumentationLoadTimeWeaver类型的实例,而且在实例化过程中还做了一些额外的操作。在实例化过程中判断了当前是否存在Instrumentation实例,最终会取InstrumentationSavingAgent类中的instrumentation的静态属性,判断这个属性是否是null,InstrumentationSavingAgent这个类是spring-instrument-3.2.9.RELEASE.jar的代理入口类,当应用程序启动时启动了spring-instrument-3.2.9.RELEASE.jar代理时,即在虚拟机参数中设置了-javaagent参数,虚拟机会创建Instrumentation实例并传递给premain方法,InstrumentationSavingAgent会把这个类保存在instrumentation静态属性中。所以在程序启动时启动了代理时InstrumentationLoadTimeWeaver.isInstrumentationAvailable()这个方法是返回true的,所以loadTimeWeaver属性会设置成InstrumentationLoadTimeWeaver对象。对于注册转换器,如addTransformer函数等,便可以直接使用此属性(instrumentation)进行操作了。
所以,-javaagent 中的agent 类的 premain 方法在 主程序 main 之前被执行,但在 Java EE 中,没有这个主程序,所以没有执行?
InstrumentationSavingAgent 的代码非常简单,它只是利用这个机制来保存 instrumentation 的实现类实例,如果 remain 没有被执行,则该变量为空。
private static volatile Instrumentation instrumentation;
public static void premain(String agentArgs, Instrumentation inst)
{
instrumentation = inst;
}
public static void agentmain(String agentArgs, Instrumentation inst)
{
instrumentation = inst;
}
public static Instrumentation getInstrumentation()
{
return instrumentation;
}
现在原因似乎弄清楚了,但怎么才能在Java EE 中enable 这个 instrumentation 呢?哭。。。。
最后,我绕过了这个问题,disable 了 load time weaving:
Map jpaProperties = new HashMap();
jpaProperties.put("eclipselink.weaving", "false");
emfb.setJpaPropertyMap(jpaProperties);
这虽然能工作,但不是我想要的!问题终究还是没有正面解决!没有load time weaving 就没有优化,性能会差!~!