Controller层
1、 接口参数限制为5个,超过5个应用不能启动
2、 接口必须添加swagger注解,不然不能启动
3、 注入的Service bean必须有接口定义
Service层
1、 service层 bean不能在service层实现注入,
2、 service只能实现domain层、infrastructure层、executor、Collavorator、Iadvisor的bean对象注入
3、 service接口、与serviceImpl实现类,method个数必须一致,如果接口需要多方法实现则使用executor实现。防止serviceImpl实现类代码膨胀,超过万行,千行。
4、 service服务类method数量限制为35个
package com.free.more.infrast.config;
import com.free.more.app.AbstractCmdExe;
import com.free.more.app.AbstractQueryExe;
import com.free.more.app.BICollavorator;
import com.free.more.app.HCollavorator;
import com.free.more.app.IAdvisor;
import com.free.more.app.ICollavorator;
import com.free.more.app.IExecutor;
import com.free.more.client.request.Query;
import com.free.more.common.log.LoggerPolicy;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* @Date:2022/12/1
* @Content:
* @date 2022/12/01
*/
public class StandAppRunListener implements SpringApplicationRunListener {
public static final String CMD_EXE = "CmdExe";
public static final String QUERY_EXE = "QueryExe";
public static final String CONTROLLER = "controller";
public static final int METHOD_INT = 35;
private static String[] skipPackage = new String[]{"java.", "javax.", "org.springframework.", "org.slf4j.", "springfox.documentation.", "com.free.more.common.component.",
"com.free.more.component.", "com.free.more.ds.basekv."};
private static String[] visitPackage = new String[]{"com.free.more.domain.", "com.free.more.infrast."};
private static Logger logger = LoggerFactory.getLogger(StandAppRunListener.class);
private Map<Integer, String> errorList = new HashMap<>();
private final SpringApplication application;
private final String[] args;
public StandAppRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
}
@Override
public void starting() {
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
}
/**
* 完成了
*
* @param context 上下文
* @param exception 异常
*/
@Override
public void finished(ConfigurableApplicationContext context, Throwable exception) {
if (!ProfileUtil.isOffline()) {
return;
}
String[] definitionNames = context.getBeanDefinitionNames();
for (String definitionName : definitionNames) {
if (!StringUtils.endsWithIgnoreCase(definitionName, CONTROLLER)) {
continue;
}
RootBeanDefinition rootBeanDefinition = getBeanDefinition(context, definitionName);
processBean(context, rootBeanDefinition, (serviceCls, serviceBeanDef) -> validateService(context, serviceCls, serviceBeanDef));
}
if (CollectionUtils.isNotEmpty(errorList.values())) {
logger.error("\n" + StringUtils.join(errorList.values(), "\n"), LoggerPolicy.PAIN);
throw new RuntimeException("validate Autowired fail");
}
}
/**
* 验证服务
*
* @param context 上下文
* @param serviceCls 服务cls
* @param serviceBeanDef 服务bean def
*/
private void validateService(ConfigurableApplicationContext context, Class serviceCls, RootBeanDefinition serviceBeanDef) {
if (!serviceCls.isInterface()) {
String msg = serviceCls.getName() + ",Class 对象不是一个接口类型";
errorList.put(msg.hashCode(), msg);
return;
}
if (serviceCls.getMethods().length != getImplClassType(serviceBeanDef).getDeclaredMethods().length) {
String msg = getImplClassType(serviceBeanDef).getName() + ",如果有多方法实现的接口请用executor实现,service实现类存在接口未定义的方法";
errorList.put(msg.hashCode(), msg);
return;
}
if (serviceCls.getMethods().length > METHOD_INT) {
String msg = getImplClassType(serviceBeanDef).getName() + ",service方法过多,请注意service的领域,请重新设计service的领域";
errorList.put(msg.hashCode(), msg);
return;
}
processBean(context, serviceBeanDef, (executorCls, executorBeanDef) -> validateExecutor(context, executorCls, executorBeanDef));
}
/**
* 验证执行程序
*
* @param context 上下文
* @param executorCls 执行人cls
* @param executorBeanDef 执行人bean def
*/
private void validateExecutor(ConfigurableApplicationContext context, Class executorCls, RootBeanDefinition executorBeanDef) {
if (IExecutor.class.isAssignableFrom(executorCls) || AbstractCmdExe.class.isAssignableFrom(executorCls) || AbstractQueryExe.class
.isAssignableFrom(executorCls)) {
if (IExecutor.class.isAssignableFrom(executorCls)) {
if (!StringUtils.endsWith(executorCls.getName(), CMD_EXE) && !StringUtils.endsWith(executorCls.getName(), QUERY_EXE)) {
String msg = getImplClassType(executorBeanDef).getName() + ",IExecutor,只能提供标准public方法,非接口方法定义为private,protected";
errorList.put(msg.hashCode(), msg);
return;
}
if (StringUtils.endsWith(executorCls.getName(), CMD_EXE)) {
Method[] methods = executorCls.getDeclaredMethods();
for (Method method : methods) {
if (method.getModifiers() == 1) {
Class[] parameterTypes = method.getParameterTypes();
for (Class parameterType : parameterTypes) {
if (!Query.class.isAssignableFrom(parameterType)) {
String msg = getImplClassType(executorBeanDef).getName() + ",CmdExe,execute方法形参需继承com.free.more.client.DTO.Command抽象类";
errorList.put(msg.hashCode(), msg);
}
}
}
}
}
if (StringUtils.endsWith(executorCls.getName(), QUERY_EXE)) {
Method[] methods = executorCls.getDeclaredMethods();
for (Method method : methods) {
if (method.getModifiers() == 1) {
Class[] parameterTypes = method.getParameterTypes();
for (Class parameterType : parameterTypes) {
if (!Query.class.isAssignableFrom(parameterType)) {
String msg = getImplClassType(executorBeanDef).getName() + ",QueryExe,execute方法形参需继承com.free.more.client.DTO.Query抽象类";
errorList.put(msg.hashCode(), msg);
}
}
}
}
}
if (validateExecutorMethod(executorCls, 1)) {
String msg = getImplClassType(executorBeanDef).getName() + ",IExecutor,只能提供标准public方法,非接口方法定义为private,protected";
errorList.put(msg.hashCode(), msg);
return;
}
}
if (AbstractCmdExe.class.isAssignableFrom(executorCls) && validateExecutorMethod(executorCls, 3)) {
String msg = getImplClassType(executorBeanDef).getName() + ",AbstractCmdExe,只能提供抽象类标准public方法,非接口方法定义为private,protected";
errorList.put(msg.hashCode(), msg);
return;
}
if (AbstractQueryExe.class.isAssignableFrom(executorCls) && validateExecutorMethod(executorCls, 4)) {
String msg = getImplClassType(executorBeanDef).getName() + ",AbstractQueryExe,只能提供抽象类标准public方法,非接口方法定义为private,protected";
errorList.put(msg.hashCode(), msg);
return;
}
processBean(context, executorBeanDef, (collCls, collBeanDef) -> validateCollavorator(context, collCls, collBeanDef));
} else if (ICollavorator.class.isAssignableFrom(executorCls) || HCollavorator.class.isAssignableFrom(executorCls) || BICollavorator.class
.isAssignableFrom(executorCls) || IAdvisor.class.isAssignableFrom(executorCls)) {
processBean(context, executorBeanDef, (attrCls, attrBeanDef) -> validateAttr(attrCls, attrBeanDef));
} else if (StringUtils.startsWithAny(getImplClassType(executorBeanDef).getName(), visitPackage)) {
//service可以访问domain层,service层
} else {
String msg = getImplClassType(executorBeanDef).getName() + ",请用executor执行者解决,未实现Executor,Collavorator接口,同时也不是domainservice或者gateway层bean,app service不能循环调用";
errorList.put(msg.hashCode(), msg);
return;
}
}
private boolean validateExecutorMethod(Class executorCls, int maxCount) {
Method[] methods = executorCls.getDeclaredMethods();
int count = 0;
for (Method method : methods) {
if (method.getModifiers() == 1) {
count++;
}
}
if (count > maxCount) {
return true;
}
return false;
}
/**
* 验证collavorator
*
* @param context 上下文
* @param collCls 科尔cls
* @param collBeanDef 科尔宾def
*/
private void validateCollavorator(ConfigurableApplicationContext context, Class collCls, RootBeanDefinition collBeanDef) {
if (IExecutor.class.isAssignableFrom(collCls) || AbstractCmdExe.class.isAssignableFrom(collCls) || AbstractQueryExe.class.isAssignableFrom(collCls)) {
String msg = collCls.getName() + ",请用Collavorator协作者解决,不能被 executor call,executor 不能循环调用";
errorList.put(msg.hashCode(), msg);
return;
} else if (ICollavorator.class.isAssignableFrom(collCls) || HCollavorator.class.isAssignableFrom(collCls) || BICollavorator.class
.isAssignableFrom(collCls) || IAdvisor.class.isAssignableFrom(collCls)) {
processBean(context, collBeanDef, (attrCls, attrBeanDef) -> validateAttr(attrCls, attrBeanDef));
} else if (StringUtils.startsWithAny(collCls.getName(), visitPackage)) {
//IExecutor可以访问domain层,service层
}
}
/**
* 验证attr
*
* @param attrCls attr cls
*/
private void validateAttr(Class attrCls, RootBeanDefinition attrBeanDef) {
if (StringUtils.startsWithAny(getImplClassType(attrBeanDef).getName(), skipPackage)) {
return;
}
if (!StringUtils.startsWithAny(attrCls.getName(), visitPackage)) {
String msg = attrCls.getName() + ",Collavorator,IAdvisor只能调用gateway,domainService层";
errorList.put(msg.hashCode(), msg);
return;
}
}
/**
* process bean
*
* @param context 上下文
* @param rootBeanDefinition 根bean定义
* @param consumer 消费者
*/
private void processBean(ConfigurableApplicationContext context, RootBeanDefinition rootBeanDefinition, BiConsumer<Class, RootBeanDefinition> consumer) {
if (StringUtils.startsWithAny(getImplClassType(rootBeanDefinition).getName(), skipPackage)) {
return;
}
try {
Set<Member> set = getSetMember(rootBeanDefinition);
if (set == null) {
return;
}
for (Member member : set) {
Class cls = ((Field) member).getType();
if (cls.isArray()) {
cls = cls.getComponentType();
}
Map<String, Object> beans = context.getBeansOfType(cls);
for (String beanName : beans.keySet()) {
RootBeanDefinition rootBeanDefinition1 = getBeanDefinition(context, beanName);
consumer.accept(cls, rootBeanDefinition1);
}
}
} catch (IllegalAccessException e) {
logger.warn("IllegalAccessException", e);
}
}
/**
* 得到bean定义
*
* @param context 上下文
* @param beanName bean名字
* @return {@link RootBeanDefinition}
*/
private RootBeanDefinition getBeanDefinition(ConfigurableApplicationContext context, String beanName) {
ConfigurableListableBeanFactory configurableListableBeanFactory = context.getBeanFactory();
return (RootBeanDefinition) configurableListableBeanFactory.getMergedBeanDefinition(beanName);
}
/**
* 预备Member
*
* @param beanDefinition bean定义
* @return {@link Set}<{@link Member}>
* @throws IllegalAccessException 非法访问异常
*/
private Set<Member> getSetMember(RootBeanDefinition beanDefinition) throws IllegalAccessException {
Field[] fields = RootBeanDefinition.class.getDeclaredFields();
Field field = null;
for (Field temp : fields) {
if (StringUtils.equals(temp.getName(), "externallyManagedConfigMembers")) {
temp.setAccessible(true);
field = temp;
}
}
Set<Member> externallyManagedConfigMembers = (Set<Member>) field.get(beanDefinition);
return externallyManagedConfigMembers;
}
/**
* 得到impl类类型
*
* @param beanDefinition bean定义
* @return {@link Class}
*/
private Class getImplClassType(RootBeanDefinition beanDefinition) {
try {
return beanDefinition.getBeanClass();
} catch (Exception e) {
return beanDefinition.getTargetType();
}
}
}