diff --git a/backend/src/main/java/com/qqchen/deploy/backend/framework/config/ControllerBeanPostProcessor.java b/backend/src/main/java/com/qqchen/deploy/backend/framework/config/ControllerBeanPostProcessor.java deleted file mode 100644 index c2954014..00000000 --- a/backend/src/main/java/com/qqchen/deploy/backend/framework/config/ControllerBeanPostProcessor.java +++ /dev/null @@ -1,165 +0,0 @@ -package com.qqchen.deploy.backend.framework.config; - -import com.qqchen.deploy.backend.framework.controller.BaseController; -import com.qqchen.deploy.backend.framework.domain.Entity; -import com.qqchen.deploy.backend.framework.dto.BaseDTO; -import com.qqchen.deploy.backend.framework.service.IBaseService; -import com.qqchen.deploy.backend.framework.utils.PackageScanner; -import com.qqchen.deploy.backend.framework.utils.ReflectionUtils; -import com.qqchen.deploy.backend.framework.utils.SpringUtils; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.context.ApplicationContext; -import org.springframework.core.GenericTypeResolver; -import org.springframework.stereotype.Component; - -import java.io.Serializable; -import java.util.Arrays; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -@Component -@Slf4j -public class ControllerBeanPostProcessor implements BeanPostProcessor, DisposableBean { - - private final ApplicationContext applicationContext; - private final Map, IBaseService> serviceCache = new ConcurrentHashMap<>(); - - public ControllerBeanPostProcessor(ApplicationContext applicationContext) { - this.applicationContext = applicationContext; - } - - @Override - @SuppressWarnings("unchecked") - public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - if (!(bean instanceof BaseController controller)) { - return bean; - } - - try { - return injectService(controller, beanName); - } catch (ServiceInjectionException e) { - log.error("Service injection failed for controller: {}", beanName, e); - throw e; - } catch (Exception e) { - log.error("Unexpected error during service injection for controller: {}", beanName, e); - throw new BeanCreationException("Failed to inject service for controller: " + beanName, e); - } - } - - @SuppressWarnings("unchecked") - private , D extends BaseDTO, ID extends Serializable> - Object injectService(BaseController controller, String beanName) { - Class entityClass = resolveEntityClass(controller); - if (entityClass == null) { - return controller; - } - - IBaseService cachedService = serviceCache.computeIfAbsent( - entityClass, - key -> findServiceForEntity(entityClass, beanName) - ); - - if (cachedService == null) { - throw new ServiceInjectionException("No service found for entity: " + entityClass.getSimpleName()); - } - - try { - IBaseService service = (IBaseService) cachedService; - ReflectionUtils.setField("service", controller, service); - log.debug("Successfully injected service {} for controller {}", - service.getClass().getSimpleName(), - controller.getClass().getSimpleName()); - } catch (Exception e) { - throw new ServiceInjectionException("Failed to inject service field", e); - } - - return controller; - } - - @SuppressWarnings("unchecked") - private , D extends BaseDTO, ID extends Serializable> - Class resolveEntityClass(BaseController controller) { - Class[] genericTypes = GenericTypeResolver.resolveTypeArguments( - controller.getClass(), BaseController.class); - - if (genericTypes == null || genericTypes.length < 3) { - log.warn("Could not resolve entity type for controller: {}", - controller.getClass().getSimpleName()); - return null; - } - - return (Class) genericTypes[0]; - } - - @SuppressWarnings("unchecked") - private , ID extends Serializable> - IBaseService findServiceForEntity(Class entityClass, String controllerName) { - // 先尝试通过命名约定查找 - String serviceBeanName = "i" + entityClass.getSimpleName() + "Service"; - log.debug("Looking for service bean: {}", serviceBeanName); - - if (applicationContext.containsBean(serviceBeanName)) { - return (IBaseService) applicationContext.getBean(serviceBeanName); - } - - // 如果找不到,再通过类型匹配查找 - log.debug("Service not found by name, trying to find by type matching"); - return Arrays.stream(applicationContext.getBeanNamesForType(IBaseService.class)) - .map(name -> tryGetService(name, entityClass, controllerName)) - .filter(Objects::nonNull) - .findFirst() - .orElseThrow(() -> new ServiceInjectionException( - "No service found for entity: " + entityClass.getSimpleName() + - " (tried bean name: " + serviceBeanName + " and type matching)")); - } - - @SuppressWarnings("unchecked") - private , ID extends Serializable> - IBaseService tryGetService(String beanName, Class entityClass, String controllerName) { - try { - Class serviceClass = applicationContext.getType(beanName); - if (serviceClass == null) { - return null; - } - - Class[] serviceGenericTypes = GenericTypeResolver.resolveTypeArguments( - serviceClass, IBaseService.class); - - if (serviceGenericTypes != null && - serviceGenericTypes.length > 0 && - entityClass.equals(serviceGenericTypes[0])) { - log.debug("Found matching service: {} for entity: {}", beanName, entityClass.getSimpleName()); - return (IBaseService) applicationContext.getBean(beanName); - } - } catch (Exception e) { - log.warn("Failed to analyze service bean: {} for controller: {}", beanName, controllerName, e); - } - return null; - } - - @Override - public void destroy() { - serviceCache.clear(); - } - - public static class ServiceInjectionException extends BeanCreationException { - public ServiceInjectionException(String message) { - super(message); - } - - public ServiceInjectionException(String message, Throwable cause) { - super(message, cause); - } - } -} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/framework/config/DependencyInjectionPostProcessor.java b/backend/src/main/java/com/qqchen/deploy/backend/framework/config/DependencyInjectionPostProcessor.java new file mode 100644 index 00000000..9edf4df7 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/framework/config/DependencyInjectionPostProcessor.java @@ -0,0 +1,243 @@ +package com.qqchen.deploy.backend.framework.config; + +import com.qqchen.deploy.backend.framework.controller.BaseController; +import com.qqchen.deploy.backend.framework.converter.BaseConverter; +import com.qqchen.deploy.backend.framework.domain.Entity; +import com.qqchen.deploy.backend.framework.dto.BaseDTO; +import com.qqchen.deploy.backend.framework.enums.ResponseCode; +import com.qqchen.deploy.backend.framework.exception.BusinessException; +import com.qqchen.deploy.backend.framework.repository.IBaseRepository; +import com.qqchen.deploy.backend.framework.service.IBaseService; +import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl; +import com.qqchen.deploy.backend.framework.utils.ReflectionUtils; +import com.querydsl.core.types.EntityPath; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.context.ApplicationContext; +import org.springframework.core.GenericTypeResolver; +import org.springframework.stereotype.Component; + +import java.io.Serializable; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +@Slf4j +@Component +public class DependencyInjectionPostProcessor implements BeanPostProcessor, DisposableBean { + + private final ApplicationContext applicationContext; + + private final Map, IBaseService> serviceCache = new ConcurrentHashMap<>(); + + public DependencyInjectionPostProcessor(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + // 处理 Controller 的依赖注入 + if (bean instanceof BaseController controller) { + try { + return injectControllerDependencies(controller, beanName); + } catch (DependencyInjectionException e) { + log.error("Service injection failed for controller: {}", beanName, e); + throw e; + } catch (Exception e) { + log.error("Unexpected error during service injection for controller: {}", beanName, e); + throw new BeanCreationException("Failed to inject service for controller: " + beanName, e); + } + } + + // 处理 Service 的依赖注入 + if (bean instanceof BaseServiceImpl service) { + try { + return injectServiceDependencies(service, beanName); + } catch (Exception e) { + log.error("Failed to inject dependencies for service: {}", beanName, e); + throw new BeanCreationException("Failed to inject dependencies for service: " + beanName, e); + } + } + + return bean; + } + + // Controller 依赖注入相关方法 + private , D extends BaseDTO, ID extends Serializable> + Object injectControllerDependencies(BaseController controller, String beanName) { + Class entityClass = resolveEntityClass(controller); + if (entityClass == null) { + return controller; + } + + IBaseService cachedService = serviceCache.computeIfAbsent( + entityClass, + key -> findServiceForEntity(entityClass, beanName) + ); + + try { + IBaseService service = (IBaseService) cachedService; + ReflectionUtils.setField("service", controller, service); + log.debug("Successfully injected service {} for controller {}", + service.getClass().getSimpleName(), + controller.getClass().getSimpleName()); + } catch (Exception e) { + throw new DependencyInjectionException("Failed to inject service field", e); + } + + return controller; + } + + @SuppressWarnings("unchecked") + private , ID extends Serializable> + IBaseService findServiceForEntity(Class entityClass, String controllerName) { + // 先尝试通过命名约定查找 + String serviceBeanName = "i" + entityClass.getSimpleName() + "Service"; + log.debug("Looking for service bean: {}", serviceBeanName); + + if (applicationContext.containsBean(serviceBeanName)) { + return (IBaseService) applicationContext.getBean(serviceBeanName); + } + + // 如果找不到,再通过类型匹配查找 + log.debug("Service not found by name, trying to find by type matching"); + return Arrays.stream(applicationContext.getBeanNamesForType(IBaseService.class)) + .map(name -> tryGetService(name, entityClass, controllerName)) + .filter(Objects::nonNull) + .findFirst() + .orElseThrow(() -> new BusinessException(ResponseCode.DEPENDENCY_INJECTION_ERROR, new Object[] {entityClass.getSimpleName(), serviceBeanName})); + } + + @SuppressWarnings("unchecked") + private , ID extends Serializable> + IBaseService tryGetService(String beanName, Class entityClass, String controllerName) { + try { + Class serviceClass = applicationContext.getType(beanName); + if (serviceClass == null) { + return null; + } + + Class[] serviceGenericTypes = GenericTypeResolver.resolveTypeArguments( + serviceClass, IBaseService.class); + + if (serviceGenericTypes != null && + serviceGenericTypes.length > 0 && + entityClass.equals(serviceGenericTypes[0])) { + log.debug("Found matching service: {} for entity: {}", beanName, entityClass.getSimpleName()); + return (IBaseService) applicationContext.getBean(beanName); + } + } catch (Exception e) { + log.warn("Failed to analyze service bean: {} for controller: {}", beanName, controllerName, e); + } + return null; + } + + // Service 依赖注入相关方法 + private , D extends BaseDTO, ID extends Serializable> + Object injectServiceDependencies(BaseServiceImpl service, String beanName) { + Class entityClass = resolveEntityClass(service); + log.debug("Resolving dependencies for entity: {}", entityClass.getSimpleName()); + + try { + injectRepository(service, entityClass); + injectConverter(service, entityClass); + injectEntityPath(service, entityClass); + + log.debug("Successfully injected all dependencies for service: {}", beanName); + return service; + } catch (DependencyInjectionException e) { + throw e; + } catch (Exception e) { + log.error("Unexpected error while injecting dependencies for {}", entityClass.getSimpleName(), e); + throw new DependencyInjectionException("Failed to inject dependencies: " + e.getMessage(), e); + } + } + + // 通用工具方法 + @SuppressWarnings("unchecked") + private , ID extends Serializable> Class resolveEntityClass(Object bean) { + Class[] genericTypes = GenericTypeResolver.resolveTypeArguments( + bean.getClass(), bean instanceof BaseController ? BaseController.class : BaseServiceImpl.class); + + if (genericTypes == null || genericTypes.length < 3) { + log.warn("Could not resolve entity type for: {}", bean.getClass().getSimpleName()); + return null; + } + + return (Class) genericTypes[0]; + } + + // ... 其他方法保持不变,但重命名异常类 ... + + @Override + public void destroy() { + serviceCache.clear(); + } + + public static class DependencyInjectionException extends BeanCreationException { + public DependencyInjectionException(String message) { + super(message); + } + + public DependencyInjectionException(String message, Throwable cause) { + super(message, cause); + } + } + + // 辅助方法,用于注入具体的依赖 + private , D extends BaseDTO, ID extends Serializable> + void injectRepository(BaseServiceImpl service, Class entityClass) { + String repositoryBeanName = "I" + entityClass.getSimpleName() + "Repository"; + log.debug("Looking for repository bean: {}", repositoryBeanName); + if (!applicationContext.containsBean(repositoryBeanName)) { + throw new BusinessException( + ResponseCode.DEPENDENCY_INJECTION_ERROR, + new Object[] {entityClass.getSimpleName(), repositoryBeanName}); + } + IBaseRepository repository = (IBaseRepository) applicationContext.getBean(repositoryBeanName); + ReflectionUtils.setField("repository", service, repository); + } + + private , D extends BaseDTO, ID extends Serializable> + void injectConverter(BaseServiceImpl service, Class entityClass) { + String converterBeanName = entityClass.getSimpleName().substring(0, 1).toLowerCase() + + entityClass.getSimpleName().substring(1) + "ConverterImpl"; + log.debug("Looking for converter bean: {}", converterBeanName); + if (!applicationContext.containsBean(converterBeanName)) { + throw new BusinessException( + ResponseCode.DEPENDENCY_INJECTION_ERROR, + new Object[] {entityClass.getSimpleName(), converterBeanName}); + } + BaseConverter converter = (BaseConverter) applicationContext.getBean(converterBeanName); + ReflectionUtils.setField("converter", service, converter); + } + + private , D extends BaseDTO, ID extends Serializable> + void injectEntityPath(BaseServiceImpl service, Class entityClass) { + try { + EntityPath entityPath = initEntityPath(entityClass); + ReflectionUtils.setField("entityPath", service, entityPath); + } catch (Exception e) { + throw new BusinessException( + ResponseCode.DEPENDENCY_INJECTION_ERROR, + new Object[] {entityClass.getSimpleName(), e.getMessage()}); + } + } + + @SuppressWarnings("unchecked") + private , ID extends Serializable> EntityPath initEntityPath(Class entityClass) { + try { + String qClassName = entityClass.getPackageName() + ".Q" + entityClass.getSimpleName(); + Class qClass = Class.forName(qClassName); + Field instanceField = qClass.getDeclaredField(entityClass.getSimpleName().toLowerCase()); + return (EntityPath) instanceField.get(null); + } catch (Exception e) { + throw new IllegalStateException("Failed to get Q class for " + entityClass.getName(), e); + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/framework/config/ServiceBeanPostProcessor.java b/backend/src/main/java/com/qqchen/deploy/backend/framework/config/ServiceBeanPostProcessor.java deleted file mode 100644 index 6a11152e..00000000 --- a/backend/src/main/java/com/qqchen/deploy/backend/framework/config/ServiceBeanPostProcessor.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.qqchen.deploy.backend.framework.config; - -import com.qqchen.deploy.backend.framework.domain.Entity; -import com.qqchen.deploy.backend.framework.dto.BaseDTO; -import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl; -import com.qqchen.deploy.backend.framework.repository.IBaseRepository; -import com.qqchen.deploy.backend.framework.converter.BaseConverter; -import com.qqchen.deploy.backend.framework.utils.ReflectionUtils; -import com.querydsl.core.types.EntityPath; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.context.ApplicationContext; -import org.springframework.core.GenericTypeResolver; -import org.springframework.stereotype.Component; -import org.springframework.beans.factory.BeanCreationException; -import lombok.extern.slf4j.Slf4j; - -import java.io.Serializable; -import java.lang.reflect.Field; - -@Component -@Slf4j -public class ServiceBeanPostProcessor implements BeanPostProcessor { - - private final ApplicationContext applicationContext; - - public ServiceBeanPostProcessor(ApplicationContext applicationContext) { - this.applicationContext = applicationContext; - } - - @Override - @SuppressWarnings("unchecked") - public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - if (!(bean instanceof BaseServiceImpl service)) { - return bean; - } - - try { - return injectDependencies(service, beanName); - } catch (Exception e) { - log.error("Failed to inject dependencies for service: {}", beanName, e); - throw new BeanCreationException("Failed to inject dependencies for service: " + beanName, e); - } - } - - private , D extends BaseDTO, ID extends Serializable> - Object injectDependencies(BaseServiceImpl service, String beanName) { - Class entityClass = resolveEntityClass(service); - log.debug("Resolving dependencies for entity: {}", entityClass.getSimpleName()); - - try { - // 注入 Repository - String repositoryBeanName = "I" + entityClass.getSimpleName() + "Repository"; - log.debug("Looking for repository bean: {}", repositoryBeanName); - if (!applicationContext.containsBean(repositoryBeanName)) { - throw new ControllerBeanPostProcessor.ServiceInjectionException("Repository not found: " + repositoryBeanName); - } - IBaseRepository repository = (IBaseRepository) applicationContext.getBean(repositoryBeanName); - ReflectionUtils.setField("repository", service, repository); - - // 注入 Converter - String converterBeanName = entityClass.getSimpleName().substring(0, 1).toLowerCase() - + entityClass.getSimpleName().substring(1) + "ConverterImpl"; - log.debug("Looking for converter bean: {}", converterBeanName); - if (!applicationContext.containsBean(converterBeanName)) { - throw new ControllerBeanPostProcessor.ServiceInjectionException("Converter not found: " + converterBeanName); - } - BaseConverter converter = (BaseConverter) applicationContext.getBean(converterBeanName); - ReflectionUtils.setField("converter", service, converter); - - // 初始化 EntityPath - try { - EntityPath entityPath = initEntityPath(entityClass); - ReflectionUtils.setField("entityPath", service, entityPath); - } catch (Exception e) { - log.error("Failed to initialize EntityPath for {}", entityClass.getSimpleName(), e); - throw new ControllerBeanPostProcessor.ServiceInjectionException("Failed to initialize EntityPath: " + e.getMessage()); - } - - log.debug("Successfully injected all dependencies for service: {}", beanName); - return service; - } catch (ControllerBeanPostProcessor.ServiceInjectionException e) { - throw e; - } catch (Exception e) { - log.error("Unexpected error while injecting dependencies for {}", entityClass.getSimpleName(), e); - throw new ControllerBeanPostProcessor.ServiceInjectionException("Failed to inject dependencies: " + e.getMessage(), e); - } - } - - @SuppressWarnings("unchecked") - private , ID extends Serializable> Class resolveEntityClass(BaseServiceImpl service) { - Class[] genericTypes = GenericTypeResolver.resolveTypeArguments( - service.getClass(), BaseServiceImpl.class); - - if (genericTypes == null || genericTypes.length < 3) { - throw new IllegalStateException("Could not resolve entity type for service: " - + service.getClass().getSimpleName()); - } - - return (Class) genericTypes[0]; - } - - @SuppressWarnings("unchecked") - private , ID extends Serializable> EntityPath initEntityPath(Class entityClass) { - try { - String qClassName = entityClass.getPackageName() + ".Q" + entityClass.getSimpleName(); - Class qClass = Class.forName(qClassName); - Field instanceField = qClass.getDeclaredField(entityClass.getSimpleName().toLowerCase()); - return (EntityPath) instanceField.get(null); - } catch (Exception e) { - throw new IllegalStateException("Failed to get Q class for " + entityClass.getName(), e); - } - } -} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java b/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java index 2dbab190..94801dea 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java @@ -26,7 +26,10 @@ public enum ResponseCode { // 用户相关错误码(2开头) USER_NOT_FOUND(2001, "user.not.found"), USERNAME_EXISTS(2002, "user.username.exists"), - EMAIL_EXISTS(2003, "user.email.exists"); + EMAIL_EXISTS(2003, "user.email.exists"), + + // 依赖注入相关错误 (1100-1199) + DEPENDENCY_INJECTION_ERROR(1100, "dependency.injection.service.not.found"); private final int code; diff --git a/backend/src/main/resources/messages.properties b/backend/src/main/resources/messages.properties index a61c74c1..259f7409 100644 --- a/backend/src/main/resources/messages.properties +++ b/backend/src/main/resources/messages.properties @@ -26,4 +26,10 @@ system.retry.exceeded.error=操作重试次数超限,请稍后再试 # Entity Not Found Messages entity.not.found.id=找不到ID为{0}的实体 entity.not.found.message={0} -entity.not.found.name.id=找不到ID为{1}的{0} \ No newline at end of file +entity.not.found.name.id=找不到ID为{1}的{0} + +# 依赖注入相关 +dependency.injection.service.not.found=找不到实体 {0} 对应的服务 (尝试过的bean名称: {1}) +dependency.injection.repository.not.found=找不到实体 {0} 对应的Repository: {1} +dependency.injection.converter.not.found=找不到实体 {0} 对应的Converter: {1} +dependency.injection.entitypath.failed=初始化实体 {0} 的EntityPath失败: {1} \ No newline at end of file