Mybatis-Spring之灵异事件

MyBatis-Spring的源代码里有这么一个类,它的代码如下


public class MapperScannerConfigurer implements BeanFactoryPostProcessor, InitializingBean {

private String basePackage;

private boolean addToConfig = true;

private SqlSessionFactory sqlSessionFactory;

private SqlSessionTemplate sqlSessionTemplate;

private Class<? extends Annotation> annotationClass;

private Class<?> markerInterface;

/**
* Calls the parent search that will search and register all the candidates. Then the
* registered objects are post processed to set them as MapperFactoryBeans
*/

@[author]Override[/author]
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);

if (beanDefinitions.isEmpty()) {
logger.warn(
"No MyBatis mapper was found in '" + MapperScannerConfigurer.this.basePackage
+
"' package. Please check your configuration.");
} else {
for (BeanDefinitionHolder holder : beanDefinitions) {
GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();

if (logger.isDebugEnabled()) {
logger.debug(
"Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '"
+ definition.getBeanClassName() +
"' mapperInterface");
}

// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
definition.getPropertyValues().add(
"mapperInterface", definition.getBeanClassName());
definition.setBeanClass(MapperFactoryBean.class);

definition.getPropertyValues().add(
"addToConfig", MapperScannerConfigurer.this.addToConfig);

if (MapperScannerConfigurer.this.sqlSessionFactory != null) {
definition.getPropertyValues().add(
"sqlSessionFactory",
MapperScannerConfigurer.this.sqlSessionFactory);
}

if (MapperScannerConfigurer.this.sqlSessionTemplate != null) {
definition.getPropertyValues().add(
"sqlSessionTemplate",
MapperScannerConfigurer.this.sqlSessionTemplate);
}
}
}

return beanDefinitions;
}

@[author]Override[/author]
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return (beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent());
}

@[author]Override[/author]
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
if (super.checkCandidate(beanName, beanDefinition)) {
return true;
} else {
logger.warn(
"Skipping MapperFactoryBean with name '" + beanName + "' and '"
+ beanDefinition.getBeanClassName() +
"' mapperInterface"
+
". Bean already defined with the same name!");
return false;
}
}
}

}

这个类实现了Spring的两个接口,这两个接口代码如下


public interface InitializingBean {

/**
* Invoked by a BeanFactory after it has set all bean properties supplied
* (and satisfied BeanFactoryAware and ApplicationContextAware).
* <p>This method allows the bean instance to perform initialization only
* possible when all bean properties have been set and to throw an
* exception in the event of misconfiguration.
* @throws Exception in the event of misconfiguration (such
* as failure to set an essential property) or if initialization fails.
*/

void afterPropertiesSet() throws Exception;

}


public interface BeanFactoryPostProcessor {

/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
* @param beanFactory the bean factory used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

灵异事件发生:

在MapperScannerConfigurer类的方法中有logger.warn("No MyBatis mapper was found in '" + MapperScannerConfigurer.this.basePackage
+ "' package. Please check your configuration.");而在类属性里却没定义logger属性,程序运行时会抛出NoSuchFieldError:logger,跑出异常是肯定的,我在想MyBatis团队是怎么编译过这个类还打进Jar的呢?

修改Javac?
修改Spring源码?

这似乎都不太可能?你能想到吗?

[该贴被oojdon于2011-04-18 23:40修改过]

哈哈,搞起Spring3了,我发现你涉足开源框架非常广泛,你开发的基于JF的JdonMVC现在看看还是很有前瞻性的,如果能和Spring MVC有一拼就更好了,现在Spring用得多的主要是因为Spring MVC,和RoR以及Grails有一争。

当初淘宝没有收纳你是一大损失啊,他们虽然在Jdon宣传招人,可惜叶公好龙啊,我知道说这话把淘宝又得罪了,哈哈。

自己编译能通过不?不能说明是特殊的编译器了。或者···是生成出来的?

2011年04月19日 11:15 "@SpeedVan"的内容
自己编译能通过不?不能说明是特殊的编译器了。或者···是生成出来的? ...

肯定通不过,我修改了它的源码然后手动覆盖maven仓库才跑起了我的项目,他的class肯定是对应那个源文件,我反编译出来也是在方法里有logger而且属性里没有。

2011年04月19日 12:20 "@oojdon"的内容
手动覆盖maven仓库才跑起了我的项目 ...

Spring 3全部依靠Maven,虽然很自动化,非常方便,但是必须有两个条件,随时在线联网,其次依赖包缺省落地在C盘,而一般我们C盘经常一键恢复的,每个项目有自己的依赖包,病毒扫描起来很长时间,当然,这些都可以通过配置解决,可这样不是又不方便了?

Spring 3的petclinic项目Maven下载10M带宽,也要等待好多分钟,真是崩溃啊,Java走到这个份上,让我老泪纵横啊。怪不得Spring3的下载包里现在不带example案例了,带了也白带,Maven还是要从网上下载Spring的jar,此地银子不算数,但愿是我搞错了。

看看Spring 3案例,现在奇异现象是:Java代码简单,神出鬼没,就那么几句代码,后面hook弯道道多了去了,就象白话文变成文言文,几句话,很精简,很轻量,可是没看懂永远不会看懂。Maven下载等待和配置时间超过代码编写时间。

话写这么多,Maven 10M带宽下载还没完,再去看几个贴。
[该贴被banq于2011-04-21 15:15修改过]

super.doScan(basePackages)
中的super是ClassPathBeanDefinitionScanner.java而其又extends ClassPathScanningCandidateComponentProvider.java

ClassPathScanningCandidateComponentProvider中有logger啊。

如果如Banq所述,那么Spring3也被入歧途了。好的软件不应该是难懂的,也没有这样的必要。

spring兴起地时候我在项目里遇到了一个大大问题,猛然间console上得到一个异常,但是无论如何也无法直接看到哪里错了,必须要深入的研究配置所组合起来的代码。

现在代码配置化有一个很重要的问题:当配置地信息过于丰富地时候软件本身的可读性将非常巨大地下降,维护难度将非常巨大的提升。

曾经用java写出优美地代码,很重要的感觉是它可以脱掉繁文缛节,优雅的描述你到底需要什么。