如何在Spring Boot运行时从多个实现生成服务实现?
问题描述
我有以下几个扩展接口:
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 + ")"); } }
我定义了复合服务接口MyService,它继承了所有扩展接口:
public interface MyService extends FindExtension, SaveExtension, DeleteExtension { }
在Spring Boot应用中,我希望直接将MyService的实现注入到控制器里,但不想手动编写MyServiceImpl类,而是让框架在运行时自动把已有扩展的实现组合起来生成MyService的实现。
这和Spring Boot的Repository机制类似:
@Repository interface IPostRepository implements JpaRepository<Post,Long>, QuerydslPredicateExecutor<Post>, PostCustomRepositoryExtension { }
Spring会自动创建这个接口的实现,整合所有父接口的方法。我能不能复用这个机制?具体该怎么做?是否需要自定义注解和注解处理器?
解决方案
完全可以复用Spring的动态代理机制实现需求,无需从零编写注解处理器,核心是参考Spring Data Repository的逻辑,通过FactoryBean和动态代理组装已有实现:
1. 定义自定义注解标记复合接口
创建一个注解标记需要自动生成实现的复合接口,比如@CompositeService:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface CompositeService { }
给MyService添加该注解:
@CompositeService public interface MyService extends FindExtension, SaveExtension, DeleteExtension { }
2. 实现FactoryBean生成动态代理
通过FactoryBean创建MyService的动态代理对象,将方法调用转发到对应扩展实现类:
import org.springframework.beans.factory.FactoryBean; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class CompositeServiceFactoryBean<T> implements FactoryBean<T> { private final Class<T> serviceInterface; private final Map<Class<?>, Object> extensionImpls = new HashMap<>(); public CompositeServiceFactoryBean(Class<T> serviceInterface) { this.serviceInterface = serviceInterface; } // 注入所有扩展接口的实现Bean public void setExtensionImpls(Map<Class<?>, Object> extensionImpls) { this.extensionImpls.putAll(extensionImpls); } @Override public T getObject() throws Exception { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Object.class); enhancer.setInterfaces(new Class[]{serviceInterface}); enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> { // 定位方法所属的扩展接口 Class<?> declaringInterface = method.getDeclaringClass(); if (declaringInterface == Object.class) { return proxy.invokeSuper(obj, args); } // 调用对应实现类的方法 Object impl = extensionImpls.get(declaringInterface); if (impl == null) { throw new IllegalStateException("未找到接口[" + declaringInterface.getName() + "]的实现类"); } return method.invoke(impl, args); }); return (T) enhancer.create(); } @Override public Class<?> getObjectType() { return serviceInterface; } @Override public boolean isSingleton() { return true; } }
3. 注册Bean定义处理器
编写BeanDefinitionRegistryPostProcessor,扫描带@CompositeService的接口,为每个接口注册CompositeServiceFactoryBean并注入扩展实现:
import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.core.type.filter.AnnotationTypeFilter; import java.util.Set; public class CompositeServiceRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { private final String basePackage; public CompositeServiceRegistryPostProcessor(String basePackage) { this.basePackage = basePackage; } @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); scanner.addIncludeFilter(new AnnotationTypeFilter(CompositeService.class)); // 扫描指定包下的复合接口 Set<BeanDefinition> candidates = scanner.findCandidateComponents(basePackage); for (BeanDefinition candidate : candidates) { try { Class<?> serviceInterface = Class.forName(candidate.getBeanClassName()); if (!serviceInterface.isInterface()) { continue; } // 构建FactoryBean的Bean定义 BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CompositeServiceFactoryBean.class); builder.addConstructorArgValue(serviceInterface); // 按类型自动注入所有扩展实现 builder.setAutowireMode(BeanDefinition.AUTOWIRE_BY_TYPE); // 注册Bean,使用接口类名作为Bean名称 registry.registerBeanDefinition(serviceInterface.getSimpleName(), builder.getBeanDefinition()); } catch (ClassNotFoundException e) { throw new RuntimeException("加载复合服务接口失败: " + candidate.getBeanClassName(), e); } } } @Override public void postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory beanFactory) throws BeansException { // 无需额外处理 } }
4. 配置Spring Boot启动类
在启动类中注册处理器,指定扫描包路径:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Bean public CompositeServiceRegistryPostProcessor compositeServiceRegistryPostProcessor() { // 替换为你的复合接口所在包路径 return new CompositeServiceRegistryPostProcessor("com.yourpackage.service"); } }
5. 让扩展实现类被Spring管理
给所有扩展实现类添加@Component注解,让Spring扫描并托管实例:
import org.springframework.stereotype.Component; @Component public class FindExtensionImpl implements FindExtension { // 原有实现代码不变 } @Component public class SaveExtensionImpl implements SaveExtension { // 原有实现代码不变 } @Component public class DeleteExtensionImpl implements DeleteExtension { // 原有实现代码不变 }
验证使用
现在可以直接在控制器中注入MyService使用:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class DemoController { private final MyService myService; public DemoController(MyService myService) { this.myService = myService; } @GetMapping("/find/{id}") public void findById(@PathVariable long id) { myService.findById(id); } @GetMapping("/save") public void save() { myService.save(); } }
原理说明
该实现复用了Spring核心机制:
- 用CGLIB生成接口代理实例(和Spring Data Repository逻辑一致)
FactoryBean负责创建代理并处理方法转发BeanDefinitionRegistryPostProcessor提前扫描自定义注解接口,注册Bean定义- 代理对象根据方法所属接口,自动匹配对应的实现类执行方法,完成多实现的自动组合
内容的提问来源于stack exchange,提问作者clzola
相关产品推荐
相关产品推荐

