`
Fly_m
  • 浏览: 257982 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

equinox中http service的详细注入过程

    博客分类:
  • osgi
阅读更多

    在做上一个例子即petstore的例子中,曾出现了应用找不到http service的问题,后来找了半天发现是缺少两个包所致,这两个包为:

org.eclipse.equinox.http.jetty(equinox3.5.1包提供)

org.eclipse.equinox.http.servlet(equinox3.5.1包提供,这个不同于javax.servlet包)

    即最终来说,是这两个包负责来初始化一个httpService并放入bundleContext中,并由其他类来监听相应的httpService并与之进行交互。(在下文中,http.jetty表示org.eclipse.equinox.http.jetty,http.servlet表示org.eclipse.equinox.http.servlet,并没有提及到其他引用包)

   首先看http.servlet包,经过代码分析,httpService的实现类HttpServiceImpl便在此包中,查看相应的jar,即从启动类org.eclipse.equinox.http.servlet.internal.Activator开始。

    1,查看它的start方法,只看到一个进行httpServiceProxy的注册活动startHttpServiceProxy(context);这个方法如下

		context = bundleContext;
		Object[] proxyServlets = serviceRegistrations.keySet().toArray();
		for (int i = 0; i < proxyServlets.length; ++i) {
			ServiceRegistration registration = registerHttpService((ProxyServlet) proxyServlets[i]);
			serviceRegistrations.put(proxyServlets[i], registration);
		}

 

首先将context静态绑定在当前类中,然后将service注册信息进行重新注册。在这里,serviceRegistrations默认是empty的,所以这段代码在这里执行没有任何效果。 那么,我们来看http.jetty包。

    2,查看org.eclipse.equinox.http.jetty.internal.Activator的start方法,其中代码

String autostart = context.getProperty(AUTOSTART);
if ((autostart == null || Boolean.valueOf(autostart).booleanValue()) && !isBundleActivationPolicyUsed(context)) {
        Dictionary defaultSettings = createDefaultSettings(context);
        httpServerManager.updated(DEFAULT_PID, defaultSettings);
}

 

这段代码判断是否自动启动一个应用,这个属性值默认为null,所以会进入到启动应用的代码。首先根据相应的参数创建一个默认的启动参数设置,然后由httpServerManager,来进行相应的应用启动, 进入到updated方法。

    3,httpServerManager的相应启动应用服务代码

public synchronized void updated(String pid, Dictionary dictionary) throws ConfigurationException {
	deleted(pid);
	Server server = new Server();
	JettyCustomizer customizer = createJettyCustomizer(dictionary);
......
	ServletHolder holder = new ServletHolder(new InternalHttpServiceServlet());
	holder.setInitOrder(0);
	holder.setInitParameter(Constants.SERVICE_VENDOR, "Eclipse.org"); //$NON-NLS-1$
	holder.setInitParameter(Constants.SERVICE_DESCRIPTION, "Equinox Jetty-based Http Service"); //$NON-NLS-1$
	......
	httpContext.addServlet(holder, "/*"); //$NON-NLS-1$
	server.addHandler(httpContext);
	try {
		server.start();
	} catch (Exception e) {
		throw new ConfigurationException(pid, e.getMessage(), e);
	}
	servers.put(pid, server);
}

 

这段代码首先将相应的应用服务删除(具体逻辑略去),然后再创建一个server,并绑定相应的服务处理处理上下文(context),并由context来设置一个相应的具体服务处理的servlet,最后启动这个server.server对象是由Jetty提供的,所以就会最终启动起jetty的一个应用服务起来。但jetty自身并不提供httpService的实现,所以其实现的提供还是得由这两个包提供。

    4,这里值得注意的就是所谓的servletHolder,即处理所有具体应用服务的类,它接收一个servlet对象,并将相应的逻辑操作并由这个servlet去执行,来看这个对象的init方法。

public void init(ServletConfig config) throws ServletException {
	ServletContext context = config.getServletContext();
	contextLoader = (ClassLoader) context.getAttribute(INTERNAL_CONTEXT_CLASSLOADER);
	Thread thread = Thread.currentThread();
	ClassLoader current = thread.getContextClassLoader();
	thread.setContextClassLoader(contextLoader);
	try {
		httpServiceServlet.init(config);
	} finally {			thread.setContextClassLoader(current);
	}
}

 

这段代码具体,除进行classLoader的转换之外(这段代码限于知识略去),即调用httpServiceServlet的init方法。而这个httpServiceServlet是用new方法进行声明的,且这个servlet是位于包http.servlet中的!再看相应的service方法,也可以得知,其相应的具体逻辑处理也是并由这个httpServiceServlet来处理的,那么进入这个方法。

    5,这个servlet(org.eclipse.equinox.http.servlet.HttpServiceServlet)继承于一个internal的ProxyServlet,进入到其中的init方法。

public void init(ServletConfig config) throws ServletException {
	super.init(config);
	proxyContext = new ProxyContext(config.getServletContext());
	Activator.addProxyServlet(this);
}

 这个方法中的最后一行,即将这个servlet添加到Activator中,而这个Activator即是http.servlet的启动类!进入到这个方法。

static synchronized void addProxyServlet(ProxyServlet proxyServlet) {
	ServiceRegistration registration = null;
	if (context != null)
		registration = registerHttpService(proxyServlet);
		serviceRegistrations.put(proxyServlet, registration);
}

 

这个方法会使用这个servlet进行httpService的注册,即registerHttpService方法。

    6,之所以是使用这个servlet,原因是在registerHttpService方法中,并没有将servlet与httpService之间进行相应的操作,而只是使用了servlet的servletConfig对象,以取得相应的信息。见代码:

private static ServiceRegistration registerHttpService(ProxyServlet proxyServlet) {
	HttpServiceFactory factory = new HttpServiceFactory(proxyServlet);
	Dictionary serviceProperties = new Hashtable(2);
	ServletConfig config = proxyServlet.getServletConfig();
	Enumeration initparameterNames = config.getInitParameterNames();
	while (initparameterNames.hasMoreElements()) {
		String name = (String) initparameterNames.nextElement();
		serviceProperties.put(name, config.getInitParameter(name));
	}
	if (serviceProperties.get(Constants.SERVICE_VENDOR) == null)
	serviceProperties.put(Constants.SERVICE_VENDOR, DEFAULT_SERVICE_VENDOR);
	if (serviceProperties.get(Constants.SERVICE_DESCRIPTION) == null)
		serviceProperties.put(Constants.SERVICE_DESCRIPTION, DEFAULT_SERVICE_DESCRIPTION);
	return context.registerService(HttpService.class.getName(), factory, serviceProperties);
}

 

这个方法里面,最后用httpServiceFactory对象来进行httpService的注册,即完成了httpService的注册。那么我们来看HttpServiceFactory是如何取得httpService的。

    7,httpServiceFactory是一个serviceFactory(org.osgi.framework.ServiceFactory)的实现类,其调用getService方法来取得具体的service实现类。代码如下:

public Object getService(Bundle bundle, ServiceRegistration registration) {
	return new HttpServiceImpl(bundle, proxy);
}

 

这个方法,直接返回一个HttpServiceImpl对象,即最终我们想要的httpService实现类。至此,HttpService的实例化完成,并最终注册到bundleContext中。

 

    在上面的几个步骤中,1,5,6,7步骤是访问http.servlet包中的方法,而2,3,4是访问http.jetty中的方法,两个包一起协同,并终实例化HttpService,以用于我们的实际应用。所以,在用equinox配合springdm作用osgi框架启动时,这两个包是必不可少的包。

分享到:
评论
1 楼 xiaoasha 2014-10-07  
   终于找到解决方法了

相关推荐

Global site tag (gtag.js) - Google Analytics