借助@Component
Spring本身的@Component實(shí)現(xiàn)党涕,依賴(lài)于ClassPathScanningCandidateComponentProvider在指定的路徑下進(jìn)行掃描交胚,并且完成自動(dòng)加載。
查看ClassPathScanningCandidateComponentProvider的源碼切蟋,可以看到Spring默認(rèn)加載了一個(gè)注解過(guò)濾器点待,來(lái)過(guò)濾@Component的類(lèi)允乐。
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注解的過(guò)濾器,那@Service滑臊、@Controller這些注解呢?看了下@Service的源碼敌买,就知道了@Service其實(shí)是借助了@Component來(lái)實(shí)現(xiàn)加載的简珠。
@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啟動(dòng)之后聋庵,再把bean拿出來(lái)加工、定制
SpringMVC就是使用這種方式芙粱,在Spring啟動(dòng)之后祭玉,遍歷所有的bean,把帶有@Controller的bean拿出來(lái)春畔,構(gòu)造UrlMapping脱货。比如AbstractDetectingUrlHandlerMapping 岛都。
自定義掃描
BeanFactoryPostProcessor 和ApplicationContextAware。
Spring提供了一些的接口使程序可以嵌入Spring的加載過(guò)程振峻。這個(gè)類(lèi)中的繼承ApplicationContextAware接口臼疫,Spring會(huì)讀取ApplicationContextAware類(lèi)型的的JavaBean,并調(diào)用setApplicationContext(ApplicationContext applicationContext)傳入Spring的applicationContext扣孟。
同樣繼承BeanFactoryPostProcessor接口烫堤,Spring會(huì)在BeanFactory的相關(guān)處理完成后調(diào)用postProcessBeanFactory方法,進(jìn)行定制的功能凤价。
ClassPathBeanDefinitionScanner是Spring提供的一個(gè)ClassPath掃描器鸽斟,其實(shí)也繼承于ClassPathScanningCandidateComponentProvider,只不過(guò)ClassPathBeanDefinitionScanner需要一個(gè)BeanFactory或者ApplicationContext利诺,在掃描到符合要求的類(lèi)富蓄,就會(huì)加入到BeanFactory或者ApplicationContext中。
至此慢逾,完成了自定義掃描功能立倍,但是還沒(méi)有對(duì)bean進(jìn)行加工、定制氛改,還需要使用到FactoryBean帐萎,普通的JavaBean是直接使用類(lèi)的實(shí)例,但是如果一個(gè)Bean繼承了這個(gè)借口胜卤,就可以通過(guò)getObject()方法來(lái)自定義實(shí)例的內(nèi)容疆导,在FactoryBeanTest的getObject()就通過(guò)代理了原始類(lèi)的方法,自定義類(lèi)的方法葛躏。
總結(jié)一下:
- ApplicationContextAware獲取ApplicationContext
- BeanFactoryPostProcessor 獲取BeanFactory
- ClassPathBeanDefinitionScanner提供了自定義掃描的入口(使用ApplicationContext和BeanFactory澈段,并且啟動(dòng)自定義掃描)
- FactoryBean對(duì)自己感興趣的Bean進(jìn)行增強(qiáng)處理