Использование разных реализаций DocumentBuilder на одной и той же виртуальной машине Java
Я знаю, что этот вопрос уже задавался, но в другом аромате, поэтому я спрашиваю снова из моего POV.
На нашем сервере приложений находится несколько EJB (так, AFAIK, несколько потоков, по одному на каждый вызов EJB). Некоторым EJB для правильного функционирования требуется, чтобы фабрика DocumentBuilder создавала экземпляры xerces, а некоторым EJB нужны малиновые экземпляры.
В настоящее время был сделан выбор принудительной установки xerces по умолчанию, поэтому класс xerces был внедрен в соответствующий System.property, который является глобальным.
Насколько я вижу, класс DocumentBuilder сначала ищет System.property, затем файл свойств в папке JRE, затем снова файлы свойств в JAR/Services.
Чтобы изолировать библиотеку, для работы которой нужен малиновый цвет, я написал собственный загрузчик классов, чтобы их файлы не находились в пути к классам, и я могу быть уверен, что другие части "набора" надежны и защищены от помех.
Но даже если я изолирую эти банки, они используют DocumentBuilder, который ищет реализацию, как было сказано ранее. Если я изменю свойство System.property в течение строгого времени, необходимого для вызова библиотеки, я рискую аварийно завершить работу других EJB-компонентов, поскольку они не получают правильную реализацию.
Я также попытался написать поддельный класс DocumentBuilder для переключения результата newInstance на основе вызывающего потока, но это не сработало (слишком плохо, что вызываемая библиотека маскирует исключения, перехватывая исходные исключения и выбрасывая новые исключения, получая только исходное сообщение, чего недостаточно, чтобы получить точку)
Я ищу способ изолировать изменение свойства на уровне потока, но не могу понять это.
Какие-нибудь мысли? Спасибо!
1 ответ
Хорошо, я понял, как обойти эту проблему.
Я на самом деле написал поддельный DocumentBuilder, который принимает в статическом поле Thread, который должен получить малиновую реализацию. Таким образом, только этот поток станет малиновым, все остальные потоки получат xerces. Затем я просто устанавливаю этот класс в системном свойстве javax.xml.parsers.DocumentBuilderFactory и возвращаю исходное значение по окончании. Это решение может быть обобщено на постоянный класс, который обрабатывает запросы от различных потоков, я полагаю.
Вот источник поддельного DocumentBuilder:
public class DocumentBuilderFactoryTweak
extends DocumentBuilderFactory
{
private static Thread tweakingTH = null;
private DocumentBuilderFactory impl = null;
public DocumentBuilderFactoryTweak() {
super();
try {
this.impl =
Thread.currentThread() == tweakingTH
? (DocumentBuilderFactory)tweakingTH.getContextClassLoader().loadClass( "org.apache.crimson.jaxp.DocumentBuilderFactoryImpl" ).newInstance()
: (DocumentBuilderFactory)Class.forName( "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl" ).newInstance();
}
catch( Throwable exc ) { exc.printStackTrace(); }
}
public synchronized static void setTweakingThread( Thread th ) { tweakingTH = th; }
public boolean isCoalescing () { return this.impl.isCoalescing (); }
public boolean isExpandEntityReferences () { return this.impl.isExpandEntityReferences (); }
public boolean isIgnoringComments () { return this.impl.isIgnoringComments (); }
public boolean isIgnoringElementContentWhitespace () { return this.impl.isIgnoringElementContentWhitespace(); }
public boolean isNamespaceAware () { return this.impl.isNamespaceAware (); }
public boolean isValidating () { return this.impl.isValidating (); }
public void setCoalescing ( boolean v ) { this.impl.setCoalescing ( v ); }
public void setExpandEntityReferences ( boolean v ) { this.impl.setExpandEntityReferences ( v ); }
public void setIgnoringComments ( boolean v ) { this.impl.setIgnoringComments ( v ); }
public void setIgnoringElementContentWhitespace ( boolean v ) { this.impl.setIgnoringElementContentWhitespace ( v ); }
public void setNamespaceAware ( boolean v ) { this.impl.setNamespaceAware ( v ); }
public void setValidating ( boolean v ) { this.impl.setValidating ( v ); }
public javax.xml.parsers.DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { return this.impl.newDocumentBuilder (); }
public Object getAttribute ( String k ) { return this.impl.getAttribute ( k ); }
public void setAttribute ( String k, Object v ) { this.impl.setAttribute ( k, v ); }
}