Spring自定义扩展

借助@Component

Spring本身的@Component实现,依赖于ClassPathScanningCandidateComponentProvider在指定的路径下进行扫描,并且完成自动加载。
查看ClassPathScanningCandidateComponentProvider的源码,可以看到Spring默认加载了一个注解过滤器,来过滤@Component的类。

protected void registerDefaultFilters() {   
   this.includeFilters.add(new AnnotationTypeFilter(Component.class));
   ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
   try {    
      this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false)); 
      logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning"); 
   }   catch (ClassNotFoundException ex) {     
     // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.   
   }   
   try {      
      this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));      
      logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");   
   }  
   catch (ClassNotFoundException ex) {     
   // JSR-330 API not available - simply skip.  
   }
}

这里只加载了@Component注解的过滤器,那@Service、@Controller这些注解呢?看了下@Service的源码,就知道了@Service其实是借助了@Component来实现加载的。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {

    /**
     * The value may indicate a suggestion for a logical component name,
     * to be turned into a Spring bean in case of an autodetected component.
     * @return the suggested component name, if any
     */
    String value() default "";

}

这种方式比较局限,不能做一些定制。

Spring启动之后,再把bean拿出来加工、定制

SpringMVC就是使用这种方式,在Spring启动之后,遍历所有的bean,把带有@Controller的bean拿出来,构造UrlMapping。比如AbstractDetectingUrlHandlerMapping 。

自定义扫描

BeanFactoryPostProcessor 和ApplicationContextAware。
Spring提供了一些的接口使程序可以嵌入Spring的加载过程。这个类中的继承ApplicationContextAware接口,Spring会读取ApplicationContextAware类型的的JavaBean,并调用setApplicationContext(ApplicationContext applicationContext)传入Spring的applicationContext。
同样继承BeanFactoryPostProcessor接口,Spring会在BeanFactory的相关处理完成后调用postProcessBeanFactory方法,进行定制的功能。

ClassPathBeanDefinitionScanner是Spring提供的一个ClassPath扫描器,其实也继承于ClassPathScanningCandidateComponentProvider,只不过ClassPathBeanDefinitionScanner需要一个BeanFactory或者ApplicationContext,在扫描到符合要求的类,就会加入到BeanFactory或者ApplicationContext中。

至此,完成了自定义扫描功能,但是还没有对bean进行加工、定制,还需要使用到FactoryBean,普通的JavaBean是直接使用类的实例,但是如果一个Bean继承了这个借口,就可以通过getObject()方法来自定义实例的内容,在FactoryBeanTest的getObject()就通过代理了原始类的方法,自定义类的方法。

总结一下:

  • ApplicationContextAware获取ApplicationContext
  • BeanFactoryPostProcessor 获取BeanFactory
  • ClassPathBeanDefinitionScanner提供了自定义扫描的入口(使用ApplicationContext和BeanFactory,并且启动自定义扫描)
  • FactoryBean对自己感兴趣的Bean进行增强处理
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,967评论 19 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,958评论 6 342
  • 1- IOC的概念 IOC:也即控制反转,DI即依赖注入,控制反转IOC和依赖注入DI其实就是同个概念的两个不同...
    zhanglbjames阅读 3,041评论 1 3
  • 毕业之后,才明白别人嘴里说的大学生活多美好,每当工作不顺心时,总是会想起在大学的快乐时光。那些陪你一起疯一起笑的朋...
    鲸与树阅读 705评论 3 6
  • 精进:如何成为一个厉害的人 1.时间分配的重心为长半衰,当下收益-半衰期图。当下好处的半衰期短,则只有通过持续做而...
    hanalt阅读 170评论 0 0