使用自定义的spring注解标签发布RMI/HTTPInvoker/Hessian/Burlap远程服务

1.依赖jar的pom.xml配置

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.slimsmart.spring.rpc.annotation.demo</groupId>
<artifactId>spring-rpc-annotation-demo</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.38</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>8.1.3.v20120416</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.5</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
</plugins>
</build>
</project>

2.改造spring,使其支持注解发布不同服务

1)定义远程发布服务注解

RemoteService.Java


package org.springframework.remoting.annotation;

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;

/**
* 远程发布注解RemoteService
*/
@Target({ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface RemoteService {

ServiceType serviceType() default ServiceType.HTTP;

Class<?> serviceInterface();
}

2)RmiServiceProperty.java

RemoteService辅助标签,在发布RMI服务时,用来指定RMI服务发布的端口。


package org.springframework.remoting.annotation;

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 java.rmi.registry.Registry;

import org.springframework.stereotype.Component;

/**
* RemoteService辅助标签,在发布RMI服务时,用来指定RMI服务发布的端口。
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface RmiServiceProperty {
int registryPort() default Registry.REGISTRY_PORT;
}

3)定义发布服务的类型枚举

package org.springframework.remoting.annotation;

/**
* ServiceType,指定发布服务的类型
*/
public enum ServiceType {
HTTP, BURLAP, HESSIAN, RMI
}

4)注解解析实现

ServiceAnnotationBeanPostProcessor.java


package org.springframework.factory.annotation;

import java.rmi.RemoteException;

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.annotation.RemoteService;
import org.springframework.remoting.annotation.RmiServiceProperty;
import org.springframework.remoting.annotation.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;

/**
* 解析RemoteService注解标签,发布服务
*/
@SuppressWarnings("deprecation")
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) {
//HttpInvoker 服务发布
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;
//Hessian 服务发布
} 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;
//Burlap 服务发布
} 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;
//RIM 服务发布
} 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 int getOrder() {
return order;
}
}

5)重写AnnotationConfigUtils类

重写spring注解配置工具类AnnotationConfigUtils.java 需与spring的在同一包目录


/*
* Copyright 2002-2014 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.Collections;
import java.util.LinkedHashSet;
import java.util.Map;
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.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.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.factory.annotation.ServiceAnnotationBeanPostProcessor;
import org.springframework.util.ClassUtils;


/**
* 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. Also registers a common
* {@link org.springframework.beans.factory.support.AutowireCandidateResolver}.
*
* @author Mark Fisher
* @author Juergen Hoeller
* @author Chris Beams
* @author Phillip Webb
* @since 2.5
* @see ContextAnnotationAutowireCandidateResolver
* @see CommonAnnotationBeanPostProcessor
* @see ConfigurationClassPostProcessor
* @see org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
* @see org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor
* @see org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor
*/
//重写Spring框架 AnnotationConfigUtils,与spring相同包目录
public class AnnotationConfigUtils {

/**
* The bean name of the internally managed Configuration annotation processor.
*/
public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.factory.annotation.internalConfigurationAnnotationProcessor";
/***
* 定义注解解析实现
*/
public static final String SERVICE_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.remoting.ServiceAnnotationBeanPostProcessor";

/**
* 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 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";


/**
* The bean name of the internally managed Scheduled annotation processor.
* <p>ATTENTION:</p> This constant is meant for internal use only. The value is stable
* but don't rely on the presence of this constant declaration; rather copy the value.
*/
public static final String SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalScheduledAnnotationProcessor";

/**
* The bean name of the internally managed Async annotation processor.
* <p>ATTENTION:</p> This constant is meant for internal use only. The value is stable
* but don't rely on the presence of this constant declaration; rather copy the value.
*/
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.
* <p>ATTENTION:</p> This constant is meant for internal use only. The value is stable
* but don't rely on the presence of this constant declaration; rather copy the value.
*/
public static final String ASYNC_EXECUTION_ASPECT_BEAN_NAME =
"org.springframework.scheduling.config.internalAsyncExecutionAspect";

/**
* The class name of the AspectJ async execution aspect.
* <p>ATTENTION:</p> This constant is meant for internal use only. The value is stable
* but don't rely on the presence of this constant declaration; rather copy the value.
*/
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.
* <p>ATTENTION:</p> This constant is meant for internal use only. The value is stable
* but don't rely on the presence of this constant declaration; rather copy the value.
*/
public static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";

/**
* The bean name of the internally managed cache advisor.
* <p>ATTENTION:</p> This constant is meant for internal use only. The value is stable
* but don't rely on the presence of this constant declaration; rather copy the value.
*/
public static final String CACHE_ADVISOR_BEAN_NAME =
"org.springframework.cache.config.internalCacheAdvisor";

/**
* The bean name of the internally managed cache aspect.
* <p>ATTENTION:</p> This constant is meant for internal use only. The value is stable
* but don't rely on the presence of this constant declaration; rather copy the value.
*/
public static final String CACHE_ASPECT_BEAN_NAME =
"org.springframework.cache.config.internalCacheAspect";

/**
* The class name of the AspectJ caching aspect.
* <p>ATTENTION:</p> This constant is meant for internal use only. The value is stable
* but don't rely on the presence of this constant declaration; rather copy the value.
*/
public static final String CACHE_ASPECT_CLASS_NAME =
"org.springframework.cache.aspectj.AnnotationCacheAspect";

/**
* The name of the AspectJ caching aspect @{@code Configuration} class.
* <p>ATTENTION:</p> This constant is meant for internal use only. The value is stable
* but don't rely on the presence of this constant declaration; rather copy the value.
*/
public static final String CACHE_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.cache.aspectj.AspectJCachingConfiguration";


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}.
* @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) {

DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}

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

/**
* 非ServiceAnnotationBeanPostProcessor类处理
*/
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 {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
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);
}

private static DefaultListableBeanFactory unwrapDefaultListableBeanFactory(BeanDefinitionRegistry registry) {
if (registry instanceof DefaultListableBeanFactory) {
return (DefaultListableBeanFactory) registry;
}
else if (registry instanceof GenericApplicationContext) {
return ((GenericApplicationContext) registry).getDefaultListableBeanFactory();
}
else {
return null;
}
}

public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
processCommonDefinitionAnnotations(abd, abd.getMetadata());
}

static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
if (metadata.isAnnotated(Lazy.class.getName())) {
abd.setLazyInit(attributesFor(metadata, Lazy.class).getBoolean("value"));
}
else if (abd.getMetadata() != metadata && abd.getMetadata().isAnnotated(Lazy.class.getName())) {
abd.setLazyInit(attributesFor(abd.getMetadata(), Lazy.class).getBoolean("value"));
}

if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
if (metadata.isAnnotated(DependsOn.class.getName())) {
abd.setDependsOn(attributesFor(metadata, DependsOn.class).getStringArray("value"));
}

if (abd instanceof AbstractBeanDefinition) {
AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;
if (metadata.isAnnotated(Role.class.getName())) {
absBd.setRole(attributesFor(metadata, Role.class).getNumber("value").intValue());
}
if (metadata.isAnnotated(Description.class.getName())) {
absBd.setDescription(attributesFor(metadata, Description.class).getString("value"));
}
}
}

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);
}

static AnnotationAttributes attributesFor(AnnotatedTypeMetadata metadata, Class<?> annotationClass) {
return attributesFor(metadata, annotationClass.getName());
}

static AnnotationAttributes attributesFor(AnnotatedTypeMetadata metadata, String annotationClassName) {
return AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(annotationClassName, false));
}

static Set<AnnotationAttributes> attributesForRepeatable(AnnotationMetadata metadata,
Class<?> containerClass, Class<?> annotationClass) {

return attributesForRepeatable(metadata, containerClass.getName(), annotationClass.getName());
}

@SuppressWarnings("unchecked")
static Set<AnnotationAttributes> attributesForRepeatable(AnnotationMetadata metadata,
String containerClassName, String annotationClassName) {

Set<AnnotationAttributes> result = new LinkedHashSet<AnnotationAttributes>();
addAttributesIfNotNull(result, metadata.getAnnotationAttributes(annotationClassName, false));

Map<String, Object> container = metadata.getAnnotationAttributes(containerClassName, false);
if (container != null && container.containsKey("value")) {
for (Map<String, Object> containedAttributes : (Map<String, Object>[]) container.get("value")) {
addAttributesIfNotNull(result, containedAttributes);
}
}
return Collections.unmodifiableSet(result);
}

private static void addAttributesIfNotNull(Set<AnnotationAttributes> result, Map<String, Object> attributes) {
if (attributes != null) {
result.add(AnnotationAttributes.fromMap(attributes));
}
}

}

3.测试类

先使用jetty启动web服务,再通过客户端调用


ServerRunner.java

package cn.lyz.spring.rpc.annotation.demo;

import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
* 使用jetty作为服务端,运行测试前,先启动startWebapp
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:applicationContext-test.xml"})
public class ServerRunner {
private static Server server;

@BeforeClass
public static void startWebapp() throws Exception {
server = new Server();
Connector connector = new SelectChannelConnector();
connector.setPort(8080); //设置webapp端口
server.addConnector(connector);
WebAppContext webAppContext = new WebAppContext();
//设置工程名称
webAppContext.setContextPath("/remoting");
//这是webapp目录
webAppContext.setWar("src/main/webapp");
server.setHandler(webAppContext);
server.start();
System.out.println("syetem start sucess.");
}

@AfterClass
public static void stopWebapp() throws Exception {
server.stop();
}
}

UserServiceTest.java

package cn.lyz.spring.rpc.annotation.demo;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

/**
* UserService测试类
*/
public class UserServiceTest extends ServerRunner{
@Autowired
private UserService userService;

@Test
public void getUser() {
System.out.println(userService.getUser("slim"));
}
}