定义注解
/** * 自定义hessian注解 * */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface HessianService { String description() default ""; /** * 是否支持方法重载 * @return */ boolean overloadEnabled() default false; /** * hessian远程访问后缀 ,打头需要加 “/” * @return */ String suffix(); /** * hessian远程访问前缀,一般情况固定为:http://ip:port/projectName/remote * @return */ String prefix(); }
定义server端扫描类HessianServerScannerConfigurer.java
import static org.springframework.util.Assert.notNull; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.springframework.aop.support.AopUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationBeanNameGenerator; import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; import org.springframework.context.annotation.ScannedGenericBeanDefinition; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.core.type.filter.AssignableTypeFilter; import org.springframework.core.type.filter.TypeFilter; import org.springframework.remoting.caucho.HessianServiceExporter; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; import org.springframework.web.context.support.XmlWebApplicationContext; /** * hessian 接口服务端自动扫描注入 * * 原作者:http://git.oschina.net/huapox/hession_toolkit * */ public class HessianServerScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware { private String beanName; private String basePackage; private boolean includeAnnotationConfig = true; private ApplicationContext applicationContext; // 实现了该接口 private Class<?> markerInterface; // 配置了该注解 private Class<? extends Annotation> annotationClass; // 存放spring 容器中的有接口的实现类的bean name private Map<String, String> implClassContextName = new HashMap<String, String>(); private BeanNameGenerator nameGenerator = new AnnotationBeanNameGenerator() { @Override protected String buildDefaultBeanName(BeanDefinition definition) { AnnotationMetadata metadata = ((ScannedGenericBeanDefinition)definition).getMetadata(); Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(annotationClass.getName()); String suffix = (String)annotationAttributes.get("suffix"); return suffix; } }; public void setBasePackage(String basePackage) { this.basePackage = basePackage; } public void setIncludeAnnotationConfig(boolean includeAnnotationConfig) { this.includeAnnotationConfig = includeAnnotationConfig; } public Class<?> getMarkerInterface() { return markerInterface; } public void setMarkerInterface(Class<?> markerInterface) { this.markerInterface = markerInterface; } public Class<? extends Annotation> getAnnotationClass() { return annotationClass; } public void setAnnotationClass(Class<? extends Annotation> annotationClass) { this.annotationClass = annotationClass; } public BeanNameGenerator getNameGenerator() { return nameGenerator; } public void setNameGenerator(BeanNameGenerator nameGenerator) { this.nameGenerator = nameGenerator; } @Override public void setBeanName(String name) { this.beanName = name; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @SuppressWarnings("unchecked") @Override public void afterPropertiesSet() throws Exception { notNull(this.basePackage, "Property 'basePackage' is required " + beanName); notNull(this.annotationClass, "Property 'annotationClass' is required " + beanName); XmlWebApplicationContext xmlContext = (XmlWebApplicationContext)applicationContext; do { DefaultListableBeanFactory beanFoctory = (DefaultListableBeanFactory)xmlContext.getAutowireCapableBeanFactory(); Field findField = ReflectionUtils.findField(beanFoctory.getClass(), "singletonObjects"); ReflectionUtils.makeAccessible(findField); Map<String, Object> field = (Map<String, Object>)ReflectionUtils.getField(findField, beanFoctory); for (Entry<String, Object> entry : field.entrySet()) { Class<?>[] interfaces = AopUtils.getTargetClass(entry.getValue()).getInterfaces(); for (Class<?> interfaceClass : interfaces) { Annotation annotation = interfaceClass.getAnnotation(annotationClass); if (annotation != null) { implClassContextName.put(interfaceClass.getName(), entry.getKey()); } } } } while ((xmlContext = (XmlWebApplicationContext)xmlContext.getParentBeanFactory()) != null); } @Override public void postProcessBeanFactory( ConfigurableListableBeanFactory beanFactory) throws BeansException { } @Override public void postProcessBeanDefinitionRegistry( BeanDefinitionRegistry registry) throws BeansException { HessianClassPathScanner scan = new HessianClassPathScanner(registry); scan.setResourceLoader(this.applicationContext); scan.setBeanNameGenerator(this.nameGenerator); // 引入注解配置 scan.setIncludeAnnotationConfig(this.includeAnnotationConfig); scan.registerFilters(); String[] basePackages = StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); scan.scan(basePackages); } private class HessianClassPathScanner extends ClassPathBeanDefinitionScanner { public HessianClassPathScanner(BeanDefinitionRegistry registry) { super(registry, false); } @Override public Set<BeanDefinitionHolder> doScan(String... basePackages) { Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); if (beanDefinitions.isEmpty()) { logger.warn("No hessian was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration."); } else { for (BeanDefinitionHolder holder : beanDefinitions) { GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition(); if (logger.isDebugEnabled()) { logger.debug("Creating HessianServiceExporter with name '" + holder.getBeanName() + "' and '" + definition.getBeanClassName() + "' serviceInterface"); } // the mapper interface is the original class of the bean // but, the actual class of the bean is HessianServiceExporter definition.getPropertyValues().add("serviceInterface", definition.getBeanClassName()); String beanNameRef = implClassContextName.get(definition.getBeanClassName()); definition.getPropertyValues().add("service", new RuntimeBeanReference(beanNameRef)); definition.setBeanClass(HessianServiceExporter.class); } } return beanDefinitions; } @Override protected boolean isCandidateComponent( AnnotatedBeanDefinition beanDefinition) { return (beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent()); } /** * {@inheritDoc} */ @Override protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException { String implBeanName = implClassContextName.get(beanDefinition.getBeanClassName()); if (!(null==implBeanName||"".equals(implBeanName)) && super.checkCandidate(beanName, beanDefinition)) { //if (!StringUtils.isEmpty(implBeanName) && super.checkCandidate(beanName, beanDefinition)) { return true; } else { System.err.println("Skipping HessianServiceExporter with name '" + beanName + "' and '" + beanDefinition.getBeanClassName() + "' serviceInterface " + ". Bean already defined with the same name!"); logger.warn("Skipping HessianServiceExporter with name '" + beanName + "' and '" + beanDefinition.getBeanClassName() + "' serviceInterface " + ". Bean already defined with the same name!"); return false; } } public void registerFilters() { boolean acceptAllInterfaces = true; // if specified, use the given annotation and / or marker interface if (HessianServerScannerConfigurer.this.annotationClass != null) { addIncludeFilter(new AnnotationTypeFilter(HessianServerScannerConfigurer.this.annotationClass)); acceptAllInterfaces = false; } // override AssignableTypeFilter to ignore matches on the actual marker interface if (HessianServerScannerConfigurer.this.markerInterface != null) { addIncludeFilter(new AssignableTypeFilter(HessianServerScannerConfigurer.this.markerInterface) { @Override protected boolean matchClassName(String className) { return false; } }); acceptAllInterfaces = false; } if (acceptAllInterfaces) { // default include filter that accepts all classes addIncludeFilter(new TypeFilter() { public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { return true; } }); } // exclude package-info.java addExcludeFilter(new TypeFilter() { public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { String className = metadataReader.getClassMetadata().getClassName(); return className.endsWith("package-info"); } }); } } }
server端创建spring_hession_context.xml
<bean class="com.xx.HessianServerScannerConfigurer"> <!-- 基类包路径 --> <property name="basePackage" value="com.faceghost.elasticbg.base.service"></property> <!--hession自定义注解 --> <property name="annotationClass" value="com.xx.annotation.HessianService"></property> </bean>
Server端web.xml初始化Hession
<servlet> <servlet-name>Hessian-servlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring_hession_context.xml </param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>Hessian-servlet</servlet-name> <url-pattern>/remote/*</url-pattern> </servlet-mapping>
定义client端扫描类HessianClientScannerConfigurer.java
import static org.springframework.util.Assert.notNull; import java.io.IOException; import java.lang.annotation.Annotation; import java.util.Arrays; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import org.apache.commons.collections.MapUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; import org.springframework.context.annotation.ScannedGenericBeanDefinition; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.core.type.filter.AssignableTypeFilter; import org.springframework.core.type.filter.TypeFilter; import org.springframework.remoting.caucho.HessianProxyFactoryBean; import org.springframework.util.StringUtils; /** * hessian 接口客户端自动扫描注入 * * 原作者:http://git.oschina.net/huapox/hession_toolkit * */ public class HessianClientScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware { protected final Logger logger = LoggerFactory.getLogger(getClass()); private String beanName; private String basePackage; private boolean includeAnnotationConfig = true; private ApplicationContext applicationContext; // 实现了该接口 private Class<?> markerInterface; // 配置了该注解 private Class<? extends Annotation> annotationClass; private BeanNameGenerator nameGenerator; @Override public void postProcessBeanFactory( ConfigurableListableBeanFactory beanFactory) throws BeansException { } @Override public void setBeanName(String name) { this.beanName = name; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @Override public void afterPropertiesSet() throws Exception { notNull(this.basePackage, "Property 'basePackage' is required " + beanName); Properties props = new Properties(); for (Entry<Object, Object> resource : props.entrySet()) { System.setProperty((String)resource.getKey(), (String)resource.getValue()); } } @Override public void postProcessBeanDefinitionRegistry( BeanDefinitionRegistry registry) throws BeansException { HessianClassPathScanner scan = new HessianClassPathScanner(registry); scan.setResourceLoader(this.applicationContext); scan.setBeanNameGenerator(this.nameGenerator); // 引入注解配置 scan.setIncludeAnnotationConfig(this.includeAnnotationConfig); scan.registerFilters(); String[] basePackages = StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); scan.scan(basePackages); } public void setBasePackage(String basePackage) { this.basePackage = basePackage; } public void setIncludeAnnotationConfig(boolean includeAnnotationConfig) { this.includeAnnotationConfig = includeAnnotationConfig; } public Class<?> getMarkerInterface() { return markerInterface; } public void setMarkerInterface(Class<?> markerInterface) { this.markerInterface = markerInterface; } public Class<? extends Annotation> getAnnotationClass() { return annotationClass; } public void setAnnotationClass(Class<? extends Annotation> annotationClass) { this.annotationClass = annotationClass; } public BeanNameGenerator getNameGenerator() { return nameGenerator; } public void setNameGenerator(BeanNameGenerator nameGenerator) { this.nameGenerator = nameGenerator; } private class HessianClassPathScanner extends ClassPathBeanDefinitionScanner { public HessianClassPathScanner(BeanDefinitionRegistry registry) { super(registry, false); } @Override public Set<BeanDefinitionHolder> doScan(String... basePackages) { Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); if (beanDefinitions.isEmpty()) { logger.warn("No hessian was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration."); } else { for (BeanDefinitionHolder holder : beanDefinitions) { GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition(); if (logger.isDebugEnabled()) { logger.debug("Creating HessianFactoryBean with name '" + holder.getBeanName() + "' and '" + definition.getBeanClassName() + "' hessianInterface"); } AnnotationMetadata metadata = ((ScannedGenericBeanDefinition)definition).getMetadata(); Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(annotationClass.getName()); String context = (String)annotationAttributes.get("prefix"); String suffix = (String)annotationAttributes.get("suffix"); Boolean overloadEnabled = MapUtils.getBoolean(annotationAttributes, "overloadEnabled", false); definition.getPropertyValues().add("serviceUrl", context + suffix); definition.getPropertyValues().add("serviceInterface", definition.getBeanClassName()); // 新增overloadEnabled属性,并把它的值设置为true,默认是false,则Hessian就能支持方法的重载了 definition.getPropertyValues().add("overloadEnabled", overloadEnabled); definition.setBeanClass(HessianProxyFactoryBean.class); // the mapper interface is the original class of the bean // but, the actual class of the bean is HessianFactoryBean // definition.getPropertyValues().add("hessianInterface", definition.getBeanClassName()); // definition.setBeanClass(HessianFactoryBean.class); } } return beanDefinitions; } @Override protected boolean isCandidateComponent( AnnotatedBeanDefinition beanDefinition) { return (beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent()); } /** * {@inheritDoc} */ @Override protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException { if (super.checkCandidate(beanName, beanDefinition)) { return true; } else { logger.warn("Skipping HessianFactoryBean with name '" + beanName + "' and '" + beanDefinition.getBeanClassName() + "' hessianInterface" + ". Bean already defined with the same name!"); return false; } } public void registerFilters() { boolean acceptAllInterfaces = true; // if specified, use the given annotation and / or marker interface if (HessianClientScannerConfigurer.this.annotationClass != null) { addIncludeFilter(new AnnotationTypeFilter(HessianClientScannerConfigurer.this.annotationClass)); acceptAllInterfaces = false; } // override AssignableTypeFilter to ignore matches on the actual marker interface if (HessianClientScannerConfigurer.this.markerInterface != null) { addIncludeFilter(new AssignableTypeFilter(HessianClientScannerConfigurer.this.markerInterface) { @Override protected boolean matchClassName(String className) { return false; } }); acceptAllInterfaces = false; } if (acceptAllInterfaces) { // default include filter that accepts all classes addIncludeFilter(new TypeFilter() { public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { return true; } }); } // exclude package-info.java addExcludeFilter(new TypeFilter() { public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { String className = metadataReader.getClassMetadata().getClassName(); return className.endsWith("package-info"); } }); } } }
client端创建spring_hession_context.xml
<bean class="com.xx.HessianClientScannerConfigurer"> <!-- 基类包路径 --> <property name="basePackage" value="com.xx.service" /> <!--hession自定义注解 --> <property name="annotationClass" value="com.xx.annotation.HessianService" /> </bean>
使用
@HessianService(prefix="http://localhost:port/projectName/remote",suffix="/testService") public interface TestService { //... }