动态注入Controller、Service所需的类
This commit is contained in:
parent
1afd981805
commit
3e577cac5c
@ -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<Class<?>, 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 <T extends Entity<ID>, D extends BaseDTO, ID extends Serializable>
|
|
||||||
Object injectService(BaseController<T, D, ID, ?> controller, String beanName) {
|
|
||||||
Class<T> 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<T, D, ID> service = (IBaseService<T, D, ID>) 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 <T extends Entity<ID>, D extends BaseDTO, ID extends Serializable>
|
|
||||||
Class<T> resolveEntityClass(BaseController<T, D, ID, ?> 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<T>) genericTypes[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private <T extends Entity<ID>, ID extends Serializable>
|
|
||||||
IBaseService<?, ?, ?> findServiceForEntity(Class<T> 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 <T extends Entity<ID>, ID extends Serializable>
|
|
||||||
IBaseService<?, ?, ?> tryGetService(String beanName, Class<T> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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<Class<?>, 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 <T extends Entity<ID>, D extends BaseDTO, ID extends Serializable>
|
||||||
|
Object injectControllerDependencies(BaseController<T, D, ID, ?> controller, String beanName) {
|
||||||
|
Class<T> entityClass = resolveEntityClass(controller);
|
||||||
|
if (entityClass == null) {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
IBaseService<?, ?, ?> cachedService = serviceCache.computeIfAbsent(
|
||||||
|
entityClass,
|
||||||
|
key -> findServiceForEntity(entityClass, beanName)
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
IBaseService<T, D, ID> service = (IBaseService<T, D, ID>) 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 <T extends Entity<ID>, ID extends Serializable>
|
||||||
|
IBaseService<?, ?, ?> findServiceForEntity(Class<T> 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 <T extends Entity<ID>, ID extends Serializable>
|
||||||
|
IBaseService<?, ?, ?> tryGetService(String beanName, Class<T> 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 <T extends Entity<ID>, D extends BaseDTO, ID extends Serializable>
|
||||||
|
Object injectServiceDependencies(BaseServiceImpl<T, D, ID> service, String beanName) {
|
||||||
|
Class<T> 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 <T extends Entity<ID>, ID extends Serializable> Class<T> 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<T>) 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 <T extends Entity<ID>, D extends BaseDTO, ID extends Serializable>
|
||||||
|
void injectRepository(BaseServiceImpl<T, D, ID> service, Class<T> 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<T, ID> repository = (IBaseRepository<T, ID>) applicationContext.getBean(repositoryBeanName);
|
||||||
|
ReflectionUtils.setField("repository", service, repository);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Entity<ID>, D extends BaseDTO, ID extends Serializable>
|
||||||
|
void injectConverter(BaseServiceImpl<T, D, ID> service, Class<T> 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<T, D> converter = (BaseConverter<T, D>) applicationContext.getBean(converterBeanName);
|
||||||
|
ReflectionUtils.setField("converter", service, converter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Entity<ID>, D extends BaseDTO, ID extends Serializable>
|
||||||
|
void injectEntityPath(BaseServiceImpl<T, D, ID> service, Class<T> entityClass) {
|
||||||
|
try {
|
||||||
|
EntityPath<T> 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 <T extends Entity<ID>, ID extends Serializable> EntityPath<T> initEntityPath(Class<T> entityClass) {
|
||||||
|
try {
|
||||||
|
String qClassName = entityClass.getPackageName() + ".Q" + entityClass.getSimpleName();
|
||||||
|
Class<?> qClass = Class.forName(qClassName);
|
||||||
|
Field instanceField = qClass.getDeclaredField(entityClass.getSimpleName().toLowerCase());
|
||||||
|
return (EntityPath<T>) instanceField.get(null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalStateException("Failed to get Q class for " + entityClass.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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 <T extends Entity<ID>, D extends BaseDTO, ID extends Serializable>
|
|
||||||
Object injectDependencies(BaseServiceImpl<T, D, ID> service, String beanName) {
|
|
||||||
Class<T> 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<T, ID> repository = (IBaseRepository<T, ID>) 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<T, D> converter = (BaseConverter<T, D>) applicationContext.getBean(converterBeanName);
|
|
||||||
ReflectionUtils.setField("converter", service, converter);
|
|
||||||
|
|
||||||
// 初始化 EntityPath
|
|
||||||
try {
|
|
||||||
EntityPath<T> 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 <T extends Entity<ID>, ID extends Serializable> Class<T> resolveEntityClass(BaseServiceImpl<T, ?, ID> 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<T>) genericTypes[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private <T extends Entity<ID>, ID extends Serializable> EntityPath<T> initEntityPath(Class<T> entityClass) {
|
|
||||||
try {
|
|
||||||
String qClassName = entityClass.getPackageName() + ".Q" + entityClass.getSimpleName();
|
|
||||||
Class<?> qClass = Class.forName(qClassName);
|
|
||||||
Field instanceField = qClass.getDeclaredField(entityClass.getSimpleName().toLowerCase());
|
|
||||||
return (EntityPath<T>) instanceField.get(null);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IllegalStateException("Failed to get Q class for " + entityClass.getName(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -26,7 +26,10 @@ public enum ResponseCode {
|
|||||||
// 用户相关错误码(2开头)
|
// 用户相关错误码(2开头)
|
||||||
USER_NOT_FOUND(2001, "user.not.found"),
|
USER_NOT_FOUND(2001, "user.not.found"),
|
||||||
USERNAME_EXISTS(2002, "user.username.exists"),
|
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;
|
private final int code;
|
||||||
|
|
||||||
|
|||||||
@ -26,4 +26,10 @@ system.retry.exceeded.error=操作重试次数超限,请稍后再试
|
|||||||
# Entity Not Found Messages
|
# Entity Not Found Messages
|
||||||
entity.not.found.id=找不到ID为{0}的实体
|
entity.not.found.id=找不到ID为{0}的实体
|
||||||
entity.not.found.message={0}
|
entity.not.found.message={0}
|
||||||
entity.not.found.name.id=找不到ID为{1}的{0}
|
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}
|
||||||
Loading…
Reference in New Issue
Block a user