摘要:
一、MapperFactoryBean 與MapperCannerConfigurer 配置回顧
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
通過上面的配置在 Service層中就可以直接注入 userMapper這個DAO,MapperFactoryBean內部會調用DefaultSqlSession以動態代理的方式生成DAO接口的實現類。<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="org.mybatis.spring.sample.mapper" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
通過上面的配置在包org.mybaits.spring.sample.mapper中下面對應的DAO接口,便能生成對應的MapperFactoryBean對象,然後被Service層調用。因爲在DefaultSqlSession
二、ClassPathMapperScanner代碼分析
public void registerFilters() {
boolean acceptAllInterfaces = true;
// if specified, use the given annotation and / or marker interface
if (this.annotationClass != null) {
addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
acceptAllInterfaces = false;
}
// override AssignableTypeFilter to ignore matches on the actual marker interface
if (this.markerInterface != null) {
addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {
@Override
protected boolean matchClassName(String className) {
return false;
}
});
acceptAllInterfaces = false;
}
if (acceptAllInterfaces) {
// default include filter that accepts all classes
addIncludeFilter(new TypeFilter() {
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
return true;
}
});
}
// exclude package-info.java
addExcludeFilter(new TypeFilter() {
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
String className = metadataReader.getClassMetadata().getClassName();
return className.endsWith("package-info");
}
});
}
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' 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", this.addToConfig);
boolean explicitFactoryUsed = false;
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
}
if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
if (explicitFactoryUsed) {
logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
if (explicitFactoryUsed) {
logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}
if (!explicitFactoryUsed) {
if (logger.isDebugEnabled()) {
logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
}
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
}
return beanDefinitions;
}
三、通過實現ClassPathBeanDefinitionScanner類自下定義bean註解的掃描
1、定義自己的註解
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomizeComponent {
String value() default "";
}
2、被註解的類
@CustomizeComponent
public class ScanClass1 {
public void print() {
System.out.println("scanClass1");
}
}
3、自定義的BeanScannerConfigurer類
BeanScannerConfigurer用於嵌入到Spring的加載過程的中,這裏用到了BeanFactoryPostProcessor 和 ApplicationContextAware。Spring提供了一些的接口使程序可以嵌入Spring的加載過程。這個類中的繼承ApplicationContextAware接口,Spring會讀取ApplicationContextAware類型的的JavaBean,並調用setApplicationContext(ApplicationContext applicationContext)傳入Spring的applicationContext。同樣繼承BeanFactoryPostProcessor接口,Spring會在BeanFactory的相關處理完成後調用postProcessBeanFactory方法,進行定製的功能。
@Component
public static class BeanScannerConfigurer implements BeanFactoryPostProcessor, ApplicationContextAware {
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Scanner scanner = new Scanner((BeanDefinitionRegistry) beanFactory);
scanner.setResourceLoader(this.applicationContext);
scanner.scan("org.wcong.test.spring.scan");
}
}
4、ClassPathBeanDefinitionScanner實現類Scanner
Scanner繼承的ClassPathBeanDefinitionScanner是Spring內置的Bean定義的掃描器。includeFilter裏定義了類的過濾器,newAnnotationTypeFilter(CustomizeComponent.class)表示只取被CustomizeComponent修飾的類。只掃描我們自已定義的註解。
doScan裏掃面了包底下的讀取到BeanDefinitionHolder,自定義GenericBeanDefinition相關功能。
public final static class Scanner extends ClassPathBeanDefinitionScanner {
public Scanner(BeanDefinitionRegistry registry) {
super(registry);
}
public void registerDefaultFilters() {
this.addIncludeFilter(new AnnotationTypeFilter(CustomizeComponent.class));
}
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
for (BeanDefinitionHolder holder : beanDefinitions) {
GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();
definition.getPropertyValues().add("innerClassName", definition.getBeanClassName());
definition.setBeanClass(FactoryBeanTest.class);
}
return beanDefinitions;
}
public boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return super.isCandidateComponent(beanDefinition) && beanDefinition.getMetadata()
.hasAnnotation(CustomizeComponent.class.getName());
}
}
5、得到我們Bean
FactoryBean是Spring中比較重要的一個類。它的描述如下Interface to be implemented by objects used within a BeanFactory which are themselves factories.
If a bean implements this interface, it is used as a factory for an object to expose, not directly as a bean* instance that will be exposed itself
普通的JavaBean是直接使用類的實例,但是如果一個Bean繼承了這個藉口,就可以通過getObject()方法來自定義實例的內容,在FactoryBeanTest的getObject()就通過代理了原始類的方法,自定義類的方法。
public static class FactoryBeanTest<T> implements InitializingBean, FactoryBean<T> {
private String innerClassName;
public void setInnerClassName(String innerClassName) {
this.innerClassName = innerClassName;
}
public T getObject() throws Exception {
Class innerClass = Class.forName(innerClassName);
if (innerClass.isInterface()) {
return (T) InterfaceProxy.newInstance(innerClass);
} else {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(innerClass);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setCallback(new MethodInterceptorImpl());
return (T) enhancer.create();
}
}
public Class<?> getObjectType() {
try {
return Class.forName(innerClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
public boolean isSingleton() {
return true;
}
public void afterPropertiesSet() throws Exception {
}
}
public static class InterfaceProxy implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("ObjectProxy execute:" + method.getName());
return method.invoke(proxy, args);
}
public static <T> T newInstance(Class<T> innerInterface) {
ClassLoader classLoader = innerInterface.getClassLoader();
Class[] interfaces = new Class[] { innerInterface };
InterfaceProxy proxy = new InterfaceProxy();
return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);
}
}
public static class MethodInterceptorImpl implements MethodInterceptor {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("MethodInterceptorImpl:" + method.getName());
return methodProxy.invokeSuper(o, objects);
}
}
6、main函數
@Configuration
public class CustomizeScanTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(CustomizeScanTest.class);
annotationConfigApplicationContext.refresh();
ScanClass1 injectClass = annotationConfigApplicationContext.getBean(ScanClass1.class);
injectClass.print();
}
}
詳解代碼見https://github.com/wcong/learn-java/blob/master/src/main/java/org/wcong/test/spring/CustomizeScanTest.java