如何在运行时从多个实现生成服务实现



假设我有以下接口:

public interface FindExtension {
void findById(long id);
void findAll();
}
public interface SaveExtension {
void save();
}
public interface DeleteExtension {
void deleteById(long id);
}

我有以下实现:

public class FindExtensionImpl implements FindExtension {
@Override
public void findById(long id) {
System.out.println("FindExtensionImpl::findById(" + id + ")");
}
@Override
public void findAll() {
System.out.println("FindExtensionImpl::findAll()");
}
}
public class SaveExtensionImpl implements SaveExtension {
@Override
public void save() {
System.out.println("SaveExtensionImpl::save()");
}
}
public class DeleteExtensionImpl implements DeleteExtension {
@Override
public void deleteById(long id) {
System.out.println("DeleteExtensionImpl::deleteById(" + id + ")");
}
}

现在我想混合这些实现,假设我想要这个服务:

public interface MyService extends FindExtension, SaveExtension, DeleteExtension {
}

现在,在我的Spring Boot应用程序中,我想将MyService实现注入到我的一个控制器中。通常我会创建MyServiceImpl类,实现接口方法,并用@Service进行注释。这样,SpringBoot就会扫描我的代码,创建这个服务的实例,并在我需要的时候提供给我

然而,我不想创建MyServiceImpl,而是希望它在运行时由框架生成,换句话说,由小块组成。如何告诉Spring Boot自动执行此操作?或者我需要创建自己的Annotation和Annotation Processor来生成实现吗?

这类似于Spring Boot存储库,在那里我会有这样的接口:

@Repository
interface IPostRepository implements JpaRepository<Post,Long>, QuerydslPredicateExecutor<Post>, PostCustomRepositoryExtension { }

而Spring Boot将";神奇地";创建这个接口的实现,并从JpaRepository、QuerydslPredicateExecutor和我自己的PostCustomRepositoryExtension注入方法。。。

由于Spring Boot已经做了与我类似的逻辑,我想知道我可以重用它吗?如何重用它?

免责声明

我不是Spring的专家,尤其是在创建bean等方面,所以对以下方法持保留态度。不过,你的问题让我思考了一下,所以我和Spring一起玩,可以想出以下基本方法。

请注意,这只是为了让你开始,还远远没有做好生产准备。还需要更多的研究,其他人甚至可能会进来证明这是一种错误的方法。

方法

现在的方法是:

  • 创建一个自定义注释来标记您感兴趣的接口
  • 注册为这些接口创建代理的工厂方法。这些代理将把呼叫委托给相应的"代理";片段";实现
  • 在应用程序类上使用注释启用所有内容

代码(仅附加相关部分(

接口注释:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CompositeService {}

启用注释:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import({CompositeServiceFactoryRegistrar.class})
public @interface EnableCompositeServices {}

主要工厂注册商(带内联注释(:

@Component
public class CompositeServiceFactoryRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private Map<Class<?>, Supplier<Object>> fragmentFactories = new HashMap<>();
private Environment environment;

public CompositeServiceFactoryRegistrar() {
//hard coded fragment registration, you'll probably want to do a lookup of all interfaces and their implementation on the classpath instead
fragmentFactories.put(SaveExtension.class, () -> new SaveExtensionImpl());
fragmentFactories.put(DeleteExtension.class, () -> new DeleteExtensionImpl());      
fragmentFactories.put(FindExtension.class, () -> new FindExtensionImpl());
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {

//get the enablement annotation and set up package scan
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(EnableCompositeServices.class.getCanonicalName());
if (annotationAttributes != null) {
String[] basePackages = (String[]) annotationAttributes.get("value");
if (basePackages == null || basePackages.length == 0) {
// If value attribute is not set, fallback to the package of the annotated class
basePackages = new String[] {
((StandardAnnotationMetadata) metadata).getIntrospectedClass().getPackage().getName() };
}
// using these packages, scan for interface annotated with MyCustomBean
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(
false, environment) {
// Override isCandidateComponent to only scan for interface
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
return metadata.isIndependent() && metadata.isInterface();
}
};
provider.addIncludeFilter(new AnnotationTypeFilter(CompositeService.class));
// Scan all packages
for (String basePackage : basePackages) {
for (BeanDefinition beanDefinition : provider.findCandidateComponents(basePackage)) {                   
GenericBeanDefinition genericDef = new GenericBeanDefinition(beanDefinition);

//resolve the interface class if not done yet
if( !genericDef.hasBeanClass()) {
try {
genericDef.resolveBeanClass(getClassLoader());
} catch(ClassNotFoundException e) {
//simple logging, replace that with something more appropriate
e.printStackTrace();
}
}

Class<?> interfaceType = genericDef.getBeanClass();                                 
//add the factory to the bean definition and then register it
genericDef.setInstanceSupplier(() -> createProxy(interfaceType) );                  
registry.registerBeanDefinition(interfaceType.getSimpleName(), genericDef);
}
}
}
}
/*
* Main factory method
*/
@SuppressWarnings("unchecked")
private <T> T createProxy(Class<T> type) {
//create the factory and set the interface type
ProxyFactory factory = new ProxyFactory();
factory.setInterfaces(type);
//add the advice that actually delegates to the fragments
factory.addAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Method invokedMethod = invocation.getMethod();
Class<?> invokedClass = invokedMethod.getDeclaringClass();
if (invokedClass.isInterface()) {
//create the fragment for this method, if not possible continue with the next interceptor
Supplier<Object> supplier = fragmentFactories.get(invokedClass);
if (supplier == null) {
return invocation.proceed();
}
Object fragment = supplier.get();
//get the fragment method and invoke it
Method targetMethod = fragment.getClass().getDeclaredMethod(invokedMethod.getName(),
invokedMethod.getParameterTypes());
return targetMethod.invoke(fragment, invocation.getArguments());
} else {
return invocation.proceed();
}
}
});
return (T) factory.getProxy(getClassLoader());
}

private ClassLoader getClassLoader() {
return getClass().getClassLoader();
}
}

请注意,这是一个非常简单的实现,并且有几个缺点,例如

  • 它不处理重载和参数转换
  • 它可能在覆盖方面有困难->需要更多的反射魔法
  • 碎片是硬编码的
  • (我怀疑还有更多(

最简单的方法是将所有接口放在一个接口中:

public interface CommonService<T, Z> {
void findById(long id);
void findAll();
void save();
void deleteById(long id);
}

然后使您的服务扩展CommonService

public interface ObjectService extends CommonService<Object, long> {
}

最后,您可以制作实现ObjectService 的impl

public class ObjectImpl implements ObjectService {
@Override
public void findById(long id) {
System.out.println("ObjectImpl::findById(" + id + ")");
}
@Override
public void findAll() {
System.out.println("ObjectImpl::findAll()");
}
@Override
public void save() {
System.out.println("ObjectImpl::save()");
}
@Override
public void deleteById(long id) {
System.out.println("ObjectImpl::deleteById(" + id + ")");
}
}

最新更新