sil*_*ris 1 java reflection parsing dynamic classloader
我很确定这对于专家来说是非常基础的东西,但对我来说,作为一个新手,它给我带来了困难.
我有3个解析器,每个解析器都有自己的功能,将来会有更多的解析器.现在我想做的是:我希望我的应用程序在运行时根据要出现的页面选择正确的解析器.
为此,我做了以下内容:我有一个接口(IWebParser):
public interface IWebParser {
public abstract Object execute(String page, URL url);
public abstract List<SimpleWebPosting> parse(String page, URL url, List<String> tokens);
public abstract Boolean canExecute(URL url);
}
Run Code Online (Sandbox Code Playgroud)
我的每个解析器都实现了这个接口.我有另一个名为ParserControl的类,其中有一个方法提交(String page,URL url) - 这是我的程序总是调用的,只要有一个页面要解析.此类ParserControl从xml文件获取可用的解析器,并尝试(在while语句中)任何解析器是否可以解析相关页面.这是通过canExecute(URL url)方法完成的.现在,在canExecute上收到true后,我想执行该特定的解析器.
我的类ParserControl看起来像这样:
public class ParserControl {
private static final Logger logger = Logger.getLogger("de.comlineag.snc.parser.ParserControl");
// the list of operational web parser as taken from the properties file is stored within this structure
private static List<IWebParser> webParser;
// the ParserControl instance - used during instantiation of the class and later to retrieve the list
private static ParserControl pc = null;
// ParserControl is not to be directly instantiated by other classes
private ParserControl() {
try {
webParser = getAllParser();
} catch (XPathExpressionException | IOException
| ParserConfigurationException | SAXException e) {
logger.error("EXCEPTION :: error during parser execution " + e.getMessage());
e.printStackTrace();
}
};
// Static 'instance' method - this method is called every time
// the submit method is called but can also be called implicitely to get
// an instance of ParserControl
public static ParserControl getInstance() throws XPathExpressionException, ParserConfigurationException, SAXException, IOException {
if (pc == null) {pc = new ParserControl();}
return pc;
}
public static List<SimpleWebPosting> submit(String page, URL url, ArrayList<String> tTerms) throws XPathExpressionException, ParserConfigurationException, SAXException, IOException{
logger.trace("ParserControl called");
pc = getInstance();
while (pc.webParser.iterator().hasNext()) {
logger.trace("trying parser " + pc.webParser.iterator().getClass().getSimpleName().toString());
if (((IWebParser) pc.webParser.iterator().getClass().getClassLoader()).canExecute(url)) {
return ((IWebParser) pc.webParser.iterator().getClass().getClassLoader()).parse(page, url, tTerms);
} else {
logger.trace("parser " + pc.webParser.iterator().getClass().getSimpleName().toString() + " returned false to canExecute()" );
}
}
return null;
}
// retrieves all configured parser from the properties file and creates the parser list
@SuppressWarnings("unchecked")
private <T> ArrayList<T> getAllParser() throws IOException, ParserConfigurationException, SAXException, XPathExpressionException {
String fileName = "webapp/WEB-INF/properties/webparser.xml";
ArrayList<T> ar = new ArrayList<T>();
File file = new File(fileName);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(file);
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
String expression = "//parser[@type='webparser']/value";
NodeList nodeList= (NodeList) xpath.compile(expression).evaluate(doc, XPathConstants.NODESET);
for (int i = 0 ; i < nodeList.getLength() ; i++) {
ar.add((T) nodeList.item(i).getTextContent());
logger.trace("found parser " + nodeList.item(i).getTextContent().toString() + " in configuration file " + fileName);
}
return ar;
}
}
Run Code Online (Sandbox Code Playgroud)
现在,经过这个冗长的介绍,我的问题是:执行此操作时,我无法实例化解析器类,而是获得NullPointerException.while循环中的logger.trace返回:
TRACE ParserControl - trying parser Itr <--- I would expect the class name here!!!
ERROR SimpleWebCrawler - WEBCRAWLER-Crawler Exception java.lang.NullPointerException
Run Code Online (Sandbox Code Playgroud)
谁能告诉我,我在这里做错了什么?
你有一些奇怪的东西在这里发生.我看到的问题:
IWebParser界面可以返回a Boolean,可以为null.它应该能够返回null吗?或者它应该是原始类型(boolean).如果它返回null并且你在if语句中有它,那么你将得到一个NPE.例如:Boolean b=null; if(b) {} // NPE!!修正:
static从webParser变量中删除getAllParser构造函数读取中删除泛型List<IWebParser> getAllParser()(也可以看到我替换ArrayList为List).ClassLoader迭代器并尝试将其转换为a IWebParser,显然不会工作.这是你的循环的一个工作版本,你可以看到我在外面声明了迭代器并.next()用来获取IWebParser循环中的下一个.Iterator<IWebParser> it = pc.webParser.iterator();
while (it.hasNext()) {
IWebParser parser = it.next();
logger.trace("trying parser " + parser.getClass().getSimpleName().toString());
if (parser.canExecute(url)) {
return parser.parse(page, url, tTerms);
} else {
logger.trace("parser " + parser.getClass().getSimpleName().toString() + " returned false to canExecute()" );
}
}
Run Code Online (Sandbox Code Playgroud)
想象一个Iterator是一个对象,其指针位于排序列表中的某个位置.当你调用webParser.iterator()它时,构造一个Iterator指向列表开头的新元素.现在,如果你试图遍历这些并且你一直在调用,webParser.iterator()你总会得到一个指向第一个元素的迭代器.这就是为什么重要的是声明你的Iterator外部循环并在内部重用相同的循环.还值得注意的是,.next()当你想将指针移动到下一个索引时,你只调用迭代器,这就是我声明parser变量并将其设置为while循环内的下一个变量的原因.
Awnsers评论
为什么这是单身设计模式?
单例是一种对象,其中应用程序中应该只创建一个且只有一个实例.在Java中,这通常通过使用具有private通常命名的公共静态方法的构造函数来获得getInstance().getInstance()然后,该方法将创建自身的实例(如果尚未创建和存储它)或返回存储的实例,这通常通过使用静态变量来存储该类的唯一实例来完成.
当您使用面向对象编程时,重要的是充分利用类和类的实例意味着什么.当您合并静态变量和方法时,您应该始终考虑它们为什么应该是静态的.我认为始终可以开始使用非静态变量,只有在需要时才能使其静态化.在这种情况下,它List webParser真正属于类实例而不是每个人,它在类的构造函数中初始化,然后它只在类的非静态实例中使用...因此为什么要静态?你也使用单例模式,这意味着无论如何只有一个实例!
getAllParsers()出错
我假设你传递一些解析器的类名来添加到这个ParserControl类.在这种情况下,您可以使用Class.forName(className).newInstance().
用线替换r.add((T) nodeList.item(i).getTextContent());
线r.add((IWebParser)Class.forName(nodeList.item(i).getTextContent()).newInstance());
您需要将完整路径传递给该类.EG com.me.parsers.IFrameParser:,如果你在一个班级里面有一个班级你用它$来指定班级,那么也是如此:EG:com.me.parsers.ParserClass$InnerClassParser
| 归档时间: |
|
| 查看次数: |
428 次 |
| 最近记录: |