RMI服务端的发布
1、原理:通过注解注释要发布服务的实现类,修改 spring 的注解扫描工具,当扫描到一个指定的注解就发布一个 rmi 服务。
2、spring 发布 rmi 服务的代码:
RmiServiceExporter rmiExporter = new RmiServiceExporter();
rmiExporter.setService(bean);// 注入要发布的 service 的 bean
rmiExporter.setServiceName(“DateRemoteService”);
rmiExporter.setServiceInterface(DateRemote.class);
rmiExporter.setRegistryPort(1199);// 不设置默认为端口 1099
hessianServiceExporter.afterPropertiesSet();
3、实现,需要 4 个类,2 个注解类,一个服务发布类,一个 spring 工具类的替换类:RemoteService,注解类,注释在需要发布的实现类上:
package com.yuntu.manager.base.annotation;
import com.yuntu.manager.base.enumeration.ServiceType;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
/**
*
* 使用这个标签的实现类,将会在注册一个由spring管理的rmi服务,服务名就是其指定的接口名称。服务端口号是由RmiServiceProperty注释指定
* Created by niuzy on 2018-09-19.
*/
@Target({ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface RemoteService {
ServiceType serviceType() default ServiceType.RMI;
Class<?> serviceInterface();
}
RmiServiceProperty 注释类,指定发布服务的端口,也可以更上面的注释类合并
package com.yuntu.manager.base.annotation;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
import java.rmi.registry.Registry;
/**
* 指定服务端口号
* Created by niuzy on 2018-09-19.
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface RmiServiceProperty {
int registryPort() default Registry.REGISTRY_PORT;
}
ServiceAnnotationBeanPostProcessor,用于发布 rmi 服务:
package com.yuntu.manager.base.core;
import com.yuntu.manager.base.annotation.RemoteService;
import com.yuntu.manager.base.annotation.RmiServiceProperty;
import com.yuntu.manager.base.enumeration.ServiceType;
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.caucho.HessianServiceExporter;
import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter;
import org.springframework.remoting.rmi.RmiServiceExporter;
import java.rmi.RemoteException;
/**
* Created by niuzy on 2018-09-19.
*/
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) {
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 = service.serviceInterface().getSimpleName();
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;
}
}
AnnotationConfigUtils ,用于替换 spring 的 AnnotationConfigUtils,注意包名。
package org.springframework.context.annotation;
import com.yuntu.manager.base.core.ServiceAnnotationBeanPostProcessor;
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.event.DefaultEventListenerFactory;
import org.springframework.context.event.EventListenerMethodProcessor;
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.lang.Nullable;
import org.springframework.util.ClassUtils;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
/**
* 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
* @author Stephane Nicoll
* @since 2.5
* @see ContextAnnotationAutowireCandidateResolver
* @see CommonAnnotationBeanPostProcessor
* @see ConfigurationClassPostProcessor
* @see AutowiredAnnotationBeanPostProcessor
* @see RequiredAnnotationBeanPostProcessor
*/
public class AnnotationConfigUtils {
/**
* The bean name of the internally managed Configuration annotation processor.
*/
public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.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 @EventListener annotation processor.
*/
public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME =
"org.springframework.context.event.internalEventListenerProcessor";
/**
* The bean name of the internally managed EventListenerFactory.
*/
public static final String EVENT_LISTENER_FACTORY_BEAN_NAME =
"org.springframework.context.event.internalEventListenerFactory";
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, @Nullable 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<>(4);
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));
}
/**
* 非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(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));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_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);
}
@Nullable
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) {
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
else if (abd.getMetadata() != metadata) {
lazy = attributesFor(abd.getMetadata(), Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
}
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}
if (abd instanceof AbstractBeanDefinition) {
AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
absBd.setRole(role.getNumber("value").intValue());
}
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
absBd.setDescription(description.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);
}
@Nullable
static AnnotationAttributes attributesFor(AnnotatedTypeMetadata metadata, Class<?> annotationClass) {
return attributesFor(metadata, annotationClass.getName());
}
@Nullable
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<>();
// Direct annotation present?
addAttributesIfNotNull(result, metadata.getAnnotationAttributes(annotationClassName, false));
// Container annotation present?
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 merged result
return Collections.unmodifiableSet(result);
}
private static void addAttributesIfNotNull(
Set<AnnotationAttributes> result, @Nullable Map<String, Object> attributes) {
if (attributes != null) {
result.add(AnnotationAttributes.fromMap(attributes));
}
}
}
4、使用:
package com.yuntu.manager.base.test;
import com.yuntu.manager.base.annotation.RemoteService;
import com.yuntu.manager.base.annotation.RmiServiceProperty;
import org.springframework.stereotype.Service;
/**
* Created by niuzy on 2018-09-19.
*/
@RemoteService(serviceInterface=RemoteServiceTest.class)
@RmiServiceProperty(registryPort = 1234)
@Service
public class RemoteServiceTestImpl implements RemoteServiceTest {
public String say(String word) throws Exception {
return word;
}
}
RMI 客户端
1、原理:
模仿 spring-mybatis 的 mapperscan 方式实现包扫描和 rmi 客户端自动代理
2、spring 代理 rmi 服务的代码:
RmiProxyFactoryBean bean = new RmiProxyFactoryBean();
bean.setServiceUrl(“rmi://”+url+"/"+serviceName);
bean.setServiceInterface(interfaceClass);
bean.afterPropertiesSet();
bean.getObject();
3、实现:
2 个注解类,3 个扫描注册类工厂类 RemoteClient ,注释在需要代理的接口上
package com.yuntu.manager.base.annotation;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
/**
* 使用这个标签的接口将在spring中生成一个rmi代理
* Created by niuzy on 2018-09-19.
*/
@Target({ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface RemoteClient {
}
RemoteClientScan,开启 rmi 客户端扫描功能,主要关注 value,url,basePackages 属性,其他的懒得删除了,没啥用。
package com.yuntu.manager.base.annotation;
import com.yuntu.manager.base.core.MapperScannerRegistrar;
import com.yuntu.manager.base.core.MyRmiProxyFactory;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
@Import(MapperScannerRegistrar.class)
@Target({ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RemoteClientScan {
/**
* Alias for the {@link #basePackages()} attribute. Allows for more concise
* annotation declarations e.g.:
* {@code @EnableMyBatisMapperScanner("org.my.pkg")} instead of {@code
* @EnableMyBatisMapperScanner(basePackages= "org.my.pkg"})}.
*/
String[] value() default {};
String url() default "localhost:1099";
/**
* Base packages to scan for MyBatis interfaces. Note that only interfaces
* with at least one method will be registered; concrete classes will be
* ignored.
*/
String[] basePackages() default {};
/**
* Type-safe alternative to {@link #basePackages()} for specifying the packages
* to scan for annotated components. The package of each class specified will be scanned.
* <p>Consider creating a special no-op marker class or interface in each package
* that serves no purpose other than being referenced by this attribute.
*/
Class<?>[] basePackageClasses() default {};
/**
* The {@link BeanNameGenerator} class to be used for naming detected components
* within the Spring container.
*/
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
/**
* This property specifies the annotation that the scanner will search for.
* <p>
* The scanner will register all interfaces in the base package that also have
* the specified annotation.
* <p>
* Note this can be combined with markerInterface.
*/
Class<? extends Annotation> annotationClass() default Annotation.class;
/**
* Specifies a custom MapperFactoryBean to return a mybatis proxy as spring bean.
*
*/
Class<? extends MyRmiProxyFactory> factoryBean() default MyRmiProxyFactory.class;
}
注册扫描器,MapperScannerRegistrar
package com.yuntu.manager.base.core;
import com.yuntu.manager.base.annotation.RemoteClientScan;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
private ResourceLoader resourceLoader;
/**
* {@inheritDoc}
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(RemoteClientScan.class.getName()));
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
// this check is needed in Spring 3.1
if (resourceLoader != null) {
scanner.setResourceLoader(resourceLoader);
}
Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) {
scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
}
List<String> basePackages = new ArrayList<String>();
for (String pkg : annoAttrs.getStringArray("value")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
String url = annoAttrs.getString("url");
for (String pkg : annoAttrs.getStringArray("basePackages")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
scanner.registerFilters();
scanner.setUrl(url);
scanner.doScan(StringUtils.toStringArray(basePackages));
}
/**
* {@inheritDoc}
*/
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}
真正做扫描工作的类:ClassPathMapperScanner ,重点方法 doScan()
package com.yuntu.manager.base.core;
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.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
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 java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Set;
/**
* 扫描器,通过doScan方法将basePackages中的class,扫描进spring容器中
*/
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
private MyRmiProxyFactory mapperFactoryBean = new MyRmiProxyFactory<Object>();
private Class<?> markerInterface;
private Class<? extends Annotation> annotationClass;
private String url;
public ClassPathMapperScanner(BeanDefinitionRegistry registry) {
super(registry, false);
}
public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
this.annotationClass = annotationClass;
}
public void setUrl(String url) {
this.url = url;
}
/**
* Configures parent scanner to search for the right interfaces. It can search
* for all interfaces or just for those that extends a markerInterface or/and
* those annotated with the annotationClass
*/
public void registerFilters() {
boolean acceptAllInterfaces = true;
// if specified, use the given annotation and / or marker interface
if (this.annotationClass != null) {
addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
acceptAllInterfaces = false;
}
// override AssignableTypeFilter to ignore matches on the actual marker interface
if (this.markerInterface != null) {
addIncludeFilter(new AssignableTypeFilter(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");
}
});
}
/**
* 入口
* Calls the parent search that will search and register all the candidates.
* Then the registered objects are post processed to set them as
* MapperFactoryBeans
*/
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
} else {
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
/**
* 主要方法
* @param beanDefinitions
*/
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
if (logger.isDebugEnabled()) {
logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName()
+ "' and '" + definition.getBeanClassName() + "' mapperInterface");
}
// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
//向mapperFactoryBean的构造器注入参数
definition.getConstructorArgumentValues().addGenericArgumentValue(this.url);
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59
//李代桃僵的重点
definition.setBeanClass(this.mapperFactoryBean.getClass());
if (logger.isDebugEnabled()) {
logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
}
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
/**
* {@inheritDoc}
*/
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
/**
* {@inheritDoc}
*/
@Override
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) {
if (super.checkCandidate(beanName, beanDefinition)) {
return true;
} else {
logger.warn("Skipping MapperFactoryBean with name '" + beanName
+ "' and '" + beanDefinition.getBeanClassName() + "' mapperInterface"
+ ". Bean already defined with the same name!");
return false;
}
}
}
自定义的代理工厂:MyRmiProxyFactory
package com.yuntu.manager.base.core;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.remoting.rmi.RmiProxyFactoryBean;
/**
* 自定义的代理工厂,用于将指定的接口转换为代理实体
* Created by niuzy on 2018-09-19.
*/
public class MyRmiProxyFactory<T> implements FactoryBean<T>,InitializingBean {
private Class<T> interfaceClass;
private String url = "localhost:1099";
public MyRmiProxyFactory() {
}
public MyRmiProxyFactory(Class<T> interfaceClass) {
this.interfaceClass = interfaceClass;
}
public MyRmiProxyFactory(String url,Class<T> interfaceClass) {
this.interfaceClass = interfaceClass;
this.url = url;
}
public T createBean(){
RmiProxyFactoryBean bean = new RmiProxyFactoryBean();
bean.setServiceUrl("rmi://"+url+"/"+interfaceClass.getSimpleName());
bean.setServiceInterface(interfaceClass);
bean.afterPropertiesSet();
return (T)bean.getObject();
}
@Override
public T getObject() throws Exception {
return createBean();
}
@Override
public Class<?> getObjectType() {
return interfaceClass;
}
@Override
public boolean isSingleton() {
return false;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterpropertiesset");
}
}
4、使用:在 spring 中的启动或者配置类上注释:
@RemoteClientScan(value = “com.yuntu.manager.test1.rmi”,url = “localhost:1234”)
需代理的接口需要在上面的配置的包中,然后在需要代理的接口上注释,:
@RemoteClient
然后就可以在任何地方通过 sping 注入代理的实现类。
作者:xiaoniuxqq
来源链接:
https://blog.csdn.net/u011649691/article/details/82794771
https://blog.csdn.net/u011649691/article/details/82894422