http://blog.youkuaiyun.com/jackyechina/article/details/52980903
http://blog.youkuaiyun.com/purisuit_knowledge/article/details/55195442
http://www.tuicool.com/articles/FFvymu
二、ClassPathMapperScanner代码分析
ClassPathMapperScanner类实现了ClassPathBeanDefinitionScanner并对registerFilters方法与doScan方法进行了重写。
registerFilters方法主要是根据annotationClass或者是markerInterface属性来指定只扫描指定包下面的类带有某个注解的接口或者是为某个接口的子接口的接口。
public void registerFilters() { boolean acceptAllInterfaces = true ; if ( this .annotationClass != null ) { addIncludeFilter(new AnnotationTypeFilter( this .annotationClass)); acceptAllInterfaces = false ; } if ( this .markerInterface != null ) { addIncludeFilter(new AssignableTypeFilter( this .markerInterface) { @Override protected boolean matchClassName(String className) { return false ; } }); acceptAllInterfaces = false ; } if (acceptAllInterfaces) { addIncludeFilter(new TypeFilter() { public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { return true ; } }); } addExcludeFilter(new TypeFilter() { public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { String className = metadataReader.getClassMetadata().getClassName(); return className.endsWith( "package-info" ); } }); }
doScan方法用来将包下面的接口转化为MapperFactoryBean的类。
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" ); } 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、定义自己的注解
这里的注解并没有被@Component注解,而通过ClassPathBeanDefinitionScanner 类实现扫描。
@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