文档章节

自定义标签实现远程接口发布

十二缸帕萨特
 十二缸帕萨特
发布于 2015/06/26 11:12
字数 1514
阅读 272
收藏 5

服务端配置

1、注解定义

package org.springframework.remoting;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.stereotype.Component;

/**
 * 在类上声明
 * 
 * @author gaowenming
 *
 */
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface RemoteService {

	ServiceType serviceType() default ServiceType.HTTP;

	Class<?> serviceInterface();
}

2、服务发布类型

package org.springframework.remoting;

/**
 * 远程调用类型
 * 
 * @author gaowenming
 *
 */
public enum ServiceType {
	HTTP, BURLAP, HESSIAN, RMI
}

3、RMI发布接口设置

package org.springframework.remoting;

import org.springframework.stereotype.Component;

import java.lang.annotation.*;
import java.rmi.registry.Registry;

/**
 * RMI默认是1099端口,可以配置
 * 
 * @author gaowenming
 *
 */
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface RmiServiceProperty {
	int registryPort() default Registry.REGISTRY_PORT;
}

4、注解标签解析

package org.springframework.beans.factory.annotation;

import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.remoting.RemoteService;
import org.springframework.remoting.RmiServiceProperty;
import org.springframework.remoting.ServiceType;
import org.springframework.remoting.caucho.BurlapServiceExporter;
import org.springframework.remoting.caucho.HessianServiceExporter;
import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter;
import org.springframework.remoting.rmi.RmiServiceExporter;

import java.rmi.RemoteException;

/**
 * 解析注解
 * 
 * @author gaowenming
 *
 */
public class ServiceAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements PriorityOrdered {

	private int order = Ordered.LOWEST_PRECEDENCE - 1;

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

		RemoteService service = AnnotationUtils.findAnnotation(bean.getClass(), RemoteService.class);

		Object resultBean = bean;

		if (null != service) {

			if (ServiceType.HTTP == service.serviceType()) {

				if (!beanName.startsWith("/")) {
					throw new FatalBeanException("Exception initializing  HttpInvokerService for " + beanName + ",beanName should bean start with \"/\".");
				}

				HttpInvokerServiceExporter httpInvokerServiceExporter = new HttpInvokerServiceExporter();
				httpInvokerServiceExporter.setServiceInterface(service.serviceInterface());
				httpInvokerServiceExporter.setService(bean);
				httpInvokerServiceExporter.afterPropertiesSet();
				resultBean = httpInvokerServiceExporter;

			} else if (ServiceType.HESSIAN == service.serviceType()) {

				if (!beanName.startsWith("/")) {
					throw new FatalBeanException("Exception initializing  HessianService for " + beanName + ",beanName should bean start with \"/\".");
				}

				HessianServiceExporter hessianServiceExporter = new HessianServiceExporter();
				hessianServiceExporter.setServiceInterface(service.serviceInterface());
				hessianServiceExporter.setService(bean);
				hessianServiceExporter.afterPropertiesSet();
				resultBean = hessianServiceExporter;

			} else if (ServiceType.BURLAP == service.serviceType()) {

				if (!beanName.startsWith("/")) {
					throw new FatalBeanException("Exception initializing BurlapService for " + beanName + ",beanName should bean start with \"/\".");
				}

				BurlapServiceExporter burlapServiceExporter = new BurlapServiceExporter();
				burlapServiceExporter.setServiceInterface(service.serviceInterface());
				burlapServiceExporter.setService(bean);
				burlapServiceExporter.afterPropertiesSet();
				resultBean = burlapServiceExporter;

			} else if (ServiceType.RMI == service.serviceType()) {

				RmiServiceExporter rmiServiceExporter = new RmiServiceExporter();
				rmiServiceExporter.setServiceInterface(service.serviceInterface());
				rmiServiceExporter.setService(bean);
				RmiServiceProperty rmiServiceProperty = bean.getClass().getAnnotation(RmiServiceProperty.class);
				if (rmiServiceProperty != null) {
					rmiServiceExporter.setRegistryPort(rmiServiceProperty.registryPort());
				}
				String serviceName = beanName;
				if (serviceName.startsWith("/")) {
					serviceName = serviceName.substring(1);
				}
				rmiServiceExporter.setServiceName(serviceName);
				try {
					rmiServiceExporter.afterPropertiesSet();
				} catch (RemoteException remoteException) {
					throw new FatalBeanException("Exception initializing RmiServiceExporter", remoteException);
				}
				resultBean = rmiServiceExporter;
			}
		}

		return resultBean;
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	public void setOrder(int order) {
		this.order = order;
	}

	@Override
	public int getOrder() {
		return order;
	}
}

5、重写AnnotationConfigUtils,必须与原类在同一目录

/*
 * Copyright 2002-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.context.annotation;

import java.util.LinkedHashSet;
import java.util.Set;

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.ServiceAnnotationBeanPostProcessor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;

import static org.springframework.context.annotation.MetadataUtils.*;

/**
 * Utility class that allows for convenient registration of common
 * {@link org.springframework.beans.factory.config.BeanPostProcessor} and
 * {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor}
 * definitions for annotation-based configuration.
 *
 * @author Mark Fisher
 * @author Juergen Hoeller
 * @author Chris Beams
 * @since 2.5
 * @see CommonAnnotationBeanPostProcessor
 * @see org.springframework.context.annotation.ConfigurationClassPostProcessor
 * @see org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
 * @see org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor
 * @see org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor
 */
public class AnnotationConfigUtils {

    public static final String SERVICE_ANNOTATION_PROCESSOR_BEAN_NAME =
            "org.springframework.beans.factory.annotation.serviceAnnotationBeanPostProcessor";
    
	/**
	 * The bean name of the internally managed Configuration annotation processor.
	 */
	public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
			"org.springframework.context.annotation.internalConfigurationAnnotationProcessor";

	/**
	 * The bean name of the internally managed BeanNameGenerator for use when processing
	 * {@link Configuration} classes. Set by {@link AnnotationConfigApplicationContext}
	 * and {@code AnnotationConfigWebApplicationContext} during bootstrap in order to make
	 * any custom name generation strategy available to the underlying
	 * {@link ConfigurationClassPostProcessor}.
	 * @since 3.1.1
	 */
	public static final String CONFIGURATION_BEAN_NAME_GENERATOR =
			"org.springframework.context.annotation.internalConfigurationBeanNameGenerator";

	/**
	 * The bean name of the internally managed Autowired annotation processor.
	 */
	public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
			"org.springframework.context.annotation.internalAutowiredAnnotationProcessor";

	/**
	 * The bean name of the internally managed Required annotation processor.
	 */
	public static final String REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
			"org.springframework.context.annotation.internalRequiredAnnotationProcessor";

	/**
	 * The bean name of the internally managed JSR-250 annotation processor.
	 */
	public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME =
			"org.springframework.context.annotation.internalCommonAnnotationProcessor";

	/**
	 * The bean name of the internally managed Scheduled annotation processor.
	 */
	public static final String SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME =
			"org.springframework.context.annotation.internalScheduledAnnotationProcessor";

	/**
	 * The bean name of the internally managed Async annotation processor.
	 */
	public static final String ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME =
			"org.springframework.context.annotation.internalAsyncAnnotationProcessor";

	/**
	 * The bean name of the internally managed AspectJ async execution aspect.
	 */
	public static final String ASYNC_EXECUTION_ASPECT_BEAN_NAME =
			"org.springframework.scheduling.config.internalAsyncExecutionAspect";

	/**
	 * The class name of the AspectJ async execution aspect.
	 */
	public static final String ASYNC_EXECUTION_ASPECT_CLASS_NAME =
			"org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect";

	/**
	 * The name of the AspectJ async execution aspect @{@code Configuration} class.
	 */
	public static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
			"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";

	/**
	 * The bean name of the internally managed cache advisor.
	 */
	public static final String CACHE_ADVISOR_BEAN_NAME =
			"org.springframework.cache.config.internalCacheAdvisor";

	/**
	 * The bean name of the internally managed cache aspect.
	 */
	public static final String CACHE_ASPECT_BEAN_NAME =
			"org.springframework.cache.config.internalCacheAspect";

	/**
	 * The class name of the AspectJ caching aspect.
	 */
	public static final String CACHE_ASPECT_CLASS_NAME =
			"org.springframework.cache.aspectj.AnnotationCacheAspect";

	/**
	 * The name of the AspectJ caching aspect @{@code Configuration} class.
	 */
	public static final String CACHE_ASPECT_CONFIGURATION_CLASS_NAME =
			"org.springframework.cache.aspectj.AspectJCachingConfiguration";

	/**
	 * The bean name of the internally managed JPA annotation processor.
	 */
	public static final String PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME =
			"org.springframework.context.annotation.internalPersistenceAnnotationProcessor";


	private static final String PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME =
			"org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor";


	private static final boolean jsr250Present =
			ClassUtils.isPresent("javax.annotation.Resource", AnnotationConfigUtils.class.getClassLoader());

	private static final boolean jpaPresent =
			ClassUtils.isPresent("javax.persistence.EntityManagerFactory", AnnotationConfigUtils.class.getClassLoader()) &&
			ClassUtils.isPresent(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, AnnotationConfigUtils.class.getClassLoader());


	/**
	 * Register all relevant annotation post processors in the given registry.
	 * @param registry the registry to operate on
	 */
	public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
		registerAnnotationConfigProcessors(registry, null);
	}

	/**
	 * Register all relevant annotation post processors in the given registry.
	 * @param registry the registry to operate on
	 * @param source the configuration source element (already extracted)
	 * that this registration was triggered from. May be <code>null</code>.
	 * @return a Set of BeanDefinitionHolders, containing all bean definitions
	 * that have actually been registered by this call
	 */
	public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, Object source) {

		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);

        if (!registry.containsBeanDefinition(SERVICE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
            def.setSource(source);
            def.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            beanDefs.add(registerPostProcessor(registry, def, SERVICE_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
		if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
		if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition();
			try {
				ClassLoader cl = AnnotationConfigUtils.class.getClassLoader();
				def.setBeanClass(cl.loadClass(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME));
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
			}
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		return beanDefs;
	}

	private static BeanDefinitionHolder registerPostProcessor(
			BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {

		definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(beanName, definition);
		return new BeanDefinitionHolder(definition, beanName);
	}

	static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
		AnnotationMetadata metadata = abd.getMetadata();
		if (metadata.isAnnotated(Primary.class.getName())) {
			abd.setPrimary(true);
		}
		if (metadata.isAnnotated(Lazy.class.getName())) {
			abd.setLazyInit(attributesFor(metadata, Lazy.class).getBoolean("value"));
		}
		if (metadata.isAnnotated(DependsOn.class.getName())) {
			abd.setDependsOn(attributesFor(metadata, DependsOn.class).getStringArray("value"));
		}
		if (abd instanceof AbstractBeanDefinition) {
			if (metadata.isAnnotated(Role.class.getName())) {
				Integer role = attributesFor(metadata, Role.class).getNumber("value");
				((AbstractBeanDefinition)abd).setRole(role);
			}
		}
	}

	static BeanDefinitionHolder applyScopedProxyMode(
			ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {

		ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
		if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
			return definition;
		}
		boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
		return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
	}


}

6、接口定义

package org.spring.remote.hessian;

/**
 * Description: <类功能描述>. <br>
 * <p>
 * <使用说明>
 * </p>
 * Makedate:2015年6月25日 下午4:32:57
 * 
 * @author gaowenming
 * @version V1.0
 */
public interface HessianService {
	public void sayHello();
}

7、接口实现与发布

package org.spring.remote.hessian.impl;

import org.spring.remote.hessian.HessianService;
import org.springframework.remoting.RemoteService;
import org.springframework.remoting.ServiceType;
import org.springframework.stereotype.Service;

/**
 * Description: <类功能描述>. <br>
 * 
 * @Service : spring bean的声明,但是由于是远程调用的接口,所以必须斜杠开始
 * @RemoteService : 远程调用的配置
 * 
 * @author gaowenming
 * @version V1.0
 */
@Service("/HessianService.service")
@RemoteService(serviceInterface = HessianService.class, serviceType = ServiceType.HESSIAN)
public class HessianServiceImpl implements HessianService {

	@Override
	public void sayHello() {
		System.out.println("hello HessianService");

	}

}

至此,服务端的服务就发布完成

客户端配置

1、定义服务

<?xml version="1.0" encoding="ISO-8859-1"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
	<!--httpInvoker client -->
	<bean id="httpService"
		class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
		<property name="serviceUrl"
			value="http://localhost:8080/spring-remote/HttpService.service" />
		<property name="serviceInterface" value="org.spring.remote.http.HttpService" />
	</bean>
	<!--rmi client -->
	<bean id="rmiService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
		<property name="serviceUrl" value="rmi://localhost:9000/RMIService.service" />
		<property name="serviceInterface" value="org.spring.remote.rmi.RMIService" />
	</bean>
	<!--hessian client -->
	<bean id="hessianService"
		class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
		<property name="serviceUrl"
			value="http://localhost:8080/spring-remote/HessianService.service" />
		<property name="serviceInterface" value="org.spring.remote.hessian.HessianService" />
	</bean>
	<!--burlap client -->
	<bean id="burlapService"
		class="org.springframework.remoting.caucho.BurlapProxyFactoryBean">
		<property name="serviceUrl"
			value="http://localhost:8080/spring-remote/BurlapService.service" />
		<property name="serviceInterface" value="org.spring.remote.burlap.BurlapService" />
	</bean>

</beans>

2、测试服务

package org.smart.remote_client;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.spring.remote.hessian.HessianService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * Description: <类功能描述>. <br>
 * <p>
 * <使用说明>
 * </p>
 * Makedate:2015年6月25日 下午4:48:30
 * 
 * @author gaowenming
 * @version V1.0
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:applicationContext-remote.xml" })
public class HessianServiceTest {

	@Autowired
	private HessianService hessianService;

	@Test
	public void test() {
		hessianService.sayHello();
	}
}



本文转载自:http://my.oschina.net/damihui/blog/354055

十二缸帕萨特
粉丝 20
博文 65
码字总数 29186
作品 0
海淀
高级程序员
私信 提问
SPRING注解发布RMI/HTTPInvoker/Hessian/Burlap服务

最近做系统重构,计划将多个系统的公共部分抽取出来作为一项公共服务,为以后项目维护和横向扩展奠定基础。 常用的服务发布方式有RMI / HTTPInvoker / Hessian / Burlap,关于这几类java远程...

大米被占用
2014/12/09
7.6K
10
bbossgroups 分布式事件处理框架特性

最近发布的bbossgroups框架中,包含了一个事件处理框架子项目bboss-event,该事件框架特性如下: 1.构建事件接口简洁,通俗易懂 2.发布事件接口简单,通俗易懂 3.事件发布器可以发布本地事件...

yin_bp
2010/04/06
8
0
Dubbo原理和源码解析之服务暴露

一、框架设计 在官方《Dubbo 用户指南》架构部分,给出了服务调用的整体架构和流程: 另外,在官方《Dubbo 开发指南》框架设计部分,给出了整体设计: 以及暴露服务时序图: 本文将根据以上几...

明瞐
2018/09/29
302
0
Spring源码学习之:FactoryBean的使用

转载:http://book.51cto.com/art/201311/419081.htm ==========个人理解========================= FactoryBean和BeanFactory的关系 【1】FactoryBean:是一个接口,是一个用户自定义实现类实...

无信不立
2016/12/30
0
0
一个JAVA_WEB项目,需要调用极光推送的接口

已知现有一个app,但是没有后台管理项目,现在对后台管理进行开发。 目前需求在项目中集成极光推送的接口,远程调用。 使用的是jpush-client-3.2.9 (java) 目前需求3个接口: 0、全平台推送;...

娄外楼
2016/09/19
3.7K
5

没有更多内容

加载失败,请刷新页面

加载更多

如何有效地计算JavaScript中对象的键/属性数量?

计算对象的键/属性数的最快方法是什么? 是否可以在不迭代对象的情况下执行此操作? 即不做 var count = 0;for (k in myobj) if (myobj.hasOwnProperty(k)) count++; (Firefox确实提供了一...

技术盛宴
24分钟前
3
0
百度网址安全中心拦截解除的办法分享

临近2019年底,客户的公司网站被百度网址安全中心拦截了,公司网站彻底打不开了,影响范围很大,于是通过朋友介绍找到我们SINE安全公司寻求帮忙解封,关于如何解除百度的安全拦截提示,下面就...

网站安全
35分钟前
3
0
Tomcat8源码分析-启动流程-start方法

上一篇:Tomcat8源码分析-启动流程-load方法 前面讲了启动流程中的Catalina.load,进一步调用绝大部分组建的init操作,主要完成对server.xml解析,并根据解析的结果结合设置的Rule(规则)构造...

特拉仔
43分钟前
6
0
Xamarin.FormsShell基础教程(7)Shell项目关于页面的介绍

Xamarin.FormsShell基础教程(7)Shell项目关于页面的介绍 轻拍标签栏中的About标签,进入关于页面,如图1.8和图1.9所示。它是对应用程序介绍的页面。 该页面源自Views文件夹中的AboutPage.x...

大学霸
50分钟前
3
0
一步一步理解Impala query profile(一)

很多Impala用户不知道如何阅读Impala query profile来了解一个查询背后正在执行的操作,从而在此基础上对查询进行调优以充分发挥查询的性能。因此我想写一篇简单的文章来分享我的经验,并希望...

九州暮云
51分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部