服务端配置
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(); } }