一次使用模板方法模式,刷刷刷两个类写好
@Component
public abstract class SceneRunAbstractHandler {
/**
* 获取当前类型的执行
*
* @return 类型标识如custom_run,env_run
*/
public abstract String getType();
public abstract void customRunConf(SceneRunQueryDto sceneRunQueryDto);
/**
* 执行
*/
public void run(SceneRunQueryDto sceneRunQueryDto) {
}
/**
* 后置处理
* @param sceneRunQueryDto
*/
public abstract void postProcess(SceneRunQueryDto sceneRunQueryDto);
@Component
public abstract class ConfSceneRunHandler extends SceneRunAbstractHandler {
/**
* 获取当前类型的执行
*
* @return 类型标识如custom_run, env_run
*/
@Override
public String getType() {
return SceneRunTypeEnum.CONF_RUN.getCode();
}
/**
* @param sceneRunQueryDto
*/
@Override
public void customRunConf(SceneRunQueryDto sceneRunQueryDto) {
}
/**
* 后置处理
*
* @param sceneRunQueryDto
*/
@Override
public void postProcess(SceneRunQueryDto sceneRunQueryDto) {
}
在使用类的时候怎么都无法从容器中获取,发现spring容器中连类的beanDefnition都没有,心想不至于啊,稍微搜索了一下,网上都是说什么类型重复了啥的,一搜索并没有,只能自己动手丰衣足食了
首先我们稍微理一下spring的bean生命周期,
当我们配置@ComponentScan后,spring就会按照正则匹配,从target目录下扫描class文件,然后读取class文件解析成MetadataReader,然后对MetadataReader进行分析,过滤,然后生成BeanDefinition。
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
//这里处理ComponentScan的include和exclude
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
//这里可以看到解析成类的云数据后,我们要判断类是否有正确的注解
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
}
我们再看看我们类被过滤的代码块
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
//isConcrete这个方法主要校验当前类或者其子类是否是具体的类,非抽象,非接口
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}
仔细看看我们的代码,我们的子类继承了抽象类,然后它自己也是abstract的,所以直接被过滤,终于就找到原因了。
总结:复制黏贴害人不浅