轉載:http://blog.csdn.net/caihaijiang/article/details/35552859
BeanFactoryPostProcessor和BeanPostProcessor,這兩個接口,都是spring初始化bean時對外暴露的擴展點。兩個接口名稱看起來很相似,但作用及使用場景卻不同,分析如下:
1、BeanFactoryPostProcessor接口
該接口的定義如下:
-
public interface BeanFactoryPostProcessor {
-
-
-
-
-
-
-
-
-
-
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
-
-
}
實現該接口,可以在spring的bean創建之前,修改bean的定義屬性。也就是說,Spring允許BeanFactoryPostProcessor在容器實例化任何其它bean之前讀取配置元數據,並可以根據需要進行修改,例如可以把bean的scope從singleton改爲prototype,也可以把property的值給修改掉。可以同時配置多個BeanFactoryPostProcessor,並通過設置'order'屬性來控制各個BeanFactoryPostProcessor的執行次序。
注意:BeanFactoryPostProcessor是在spring容器加載了bean的定義文件之後,在bean實例化之前執行的。接口方法的入參是ConfigurrableListableBeanFactory,使用該參數,可以獲取到相關bean的定義信息,例子:
1)spring bean的定義:
-
<?xml version="1.0" encoding="UTF-8" ?>
-
<beans xmlns="http://www.springframework.org/schema/beans"
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
-
xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
-
xmlns:aop="http://www.springframework.org/schema/aop"
-
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
-
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
-
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
-
default-autowire="byName">
-
-
<bean id="myJavaBean" class="com.ali.caihj.postprocessor.MyJavaBean">
-
<property name="desc" value="測試一下啦" />
-
<property name="remark" value="這是備註信息啦啦啦" />
-
</bean>
-
<bean id="myBeanFactoryPostProcessor" class="com.ali.caihj.postprocessor.MyBeanFactoryPostProcessor" />
-
</beans>
2)自定義的BeanFactoryPostProcessor:
-
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
-
-
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
-
System.out.println("調用MyBeanFactoryPostProcessor的postProcessBeanFactory");
-
BeanDefinition bd = beanFactory.getBeanDefinition("myJavaBean");
-
System.out.println("屬性值============" + bd.getPropertyValues().toString());
-
MutablePropertyValues pv = bd.getPropertyValues();
-
if (pv.contains("remark")) {
-
pv.addPropertyValue("remark", "把備註信息修改一下");
-
}
-
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
-
}
-
-
}
spring中,有內置的一些BeanFactoryPostProcessor實現類,常用的有:
- org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
- org.springframework.beans.factory.config.PropertyOverrideConfigurer
- org.springframework.beans.factory.config.CustomEditorConfigurer:用來註冊自定義的屬性編輯器
2、BeanPostProcessor接口
該接口的定義如下:
-
public interface BeanPostProcessor {
-
-
-
-
-
-
-
-
-
-
-
-
-
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
-
-
}
BeanPostProcessor,可以在spring容器實例化bean之後,在執行bean的初始化方法前後,添加一些自己的處理邏輯。這裏說的初始化方法,指的是下面兩種:
1)bean實現了InitializingBean接口,對應的方法爲afterPropertiesSet
2)在bean定義的時候,通過init-method設置的方法
注意:BeanPostProcessor是在spring容器加載了bean的定義文件並且實例化bean之後執行的。BeanPostProcessor的執行順序是在BeanFactoryPostProcessor之後。
spring中,有內置的一些BeanPostProcessor實現類,例如:
- org.springframework.context.annotation.CommonAnnotationBeanPostProcessor:支持@Resource註解的注入
- org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor:支持@Required註解的注入
- org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor:支持@Autowired註解的注入
- org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor:支持@PersistenceUnit和@PersistenceContext註解的注入
- org.springframework.context.support.ApplicationContextAwareProcessor:用來爲bean注入ApplicationContext等容器對象
這些註解類的BeanPostProcessor,在spring配置文件中,可以通過這樣的配置 <context:component-scan base-package="*.*" /> ,自動進行註冊。(spring通過ComponentScanBeanDefinitionParser類來解析該標籤)
3、下面通過完整的一個例子,來加深理解
1)定義一個JavaBean
-
public class MyJavaBean implements InitializingBean {
-
private String desc;
-
private String remark;
-
-
public MyJavaBean() {
-
System.out.println("MyJavaBean的構造函數被執行啦");
-
}
-
public String getDesc() {
-
return desc;
-
}
-
public void setDesc(String desc) {
-
System.out.println("調用setDesc方法");
-
this.desc = desc;
-
}
-
public String getRemark() {
-
return remark;
-
}
-
public void setRemark(String remark) {
-
System.out.println("調用setRemark方法");
-
this.remark = remark;
-
}
-
public void afterPropertiesSet() throws Exception {
-
System.out.println("調用afterPropertiesSet方法");
-
this.desc = "在初始化方法中修改之後的描述信息";
-
}
-
public void initMethod() {
-
System.out.println("調用initMethod方法");
-
}
-
public String toString() {
-
StringBuilder builder = new StringBuilder();
-
builder.append("[描述:").append(desc);
-
builder.append(", 備註:").append(remark).append("]");
-
return builder.toString();
-
}
-
}
2)定義一個BeanFactoryPostProcessor
-
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
-
-
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
-
System.out.println("調用MyBeanFactoryPostProcessor的postProcessBeanFactory");
-
BeanDefinition bd = beanFactory.getBeanDefinition("myJavaBean");
-
MutablePropertyValues pv = bd.getPropertyValues();
-
if (pv.contains("remark")) {
-
pv.addPropertyValue("remark", "在BeanFactoryPostProcessor中修改之後的備忘信息");
-
}
-
}
-
-
}
3)定義一個BeanPostProcessor
-
public class MyBeanPostProcessor implements BeanPostProcessor {
-
-
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
-
System.out.println("BeanPostProcessor,對象" + beanName + "調用初始化方法之前的數據: " + bean.toString());
-
return bean;
-
}
-
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
-
System.out.println("BeanPostProcessor,對象" + beanName + "調用初始化方法之後的數據:" + bean.toString());
-
return bean;
-
}
-
}
4)spring的配置
-
<?xml version="1.0" encoding="UTF-8" ?>
-
<beans xmlns="http://www.springframework.org/schema/beans"
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
-
xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
-
xmlns:aop="http://www.springframework.org/schema/aop"
-
xsi:schemaLocation="http:
-
http:
-
http:
-
default-autowire="byName">
-
-
<bean id="myJavaBean" class="com.ali.caihj.postprocessor.MyJavaBean" init-method="initMethod">
-
<property name="desc" value="原始的描述信息" />
-
<property name="remark" value="原始的備註信息" />
-
</bean>
-
-
<bean id="myBeanPostProcessor" class="com.ali.caihj.postprocessor.MyBeanPostProcessor" />
-
<bean id="myBeanFactoryPostProcessor" class="com.ali.caihj.postprocessor.MyBeanFactoryPostProcessor" />
-
</beans>
5)測試類
-
public class PostProcessorMain {
-
public static void main(String[] args) {
-
ApplicationContext context = new ClassPathXmlApplicationContext("config/postprocessor.xml");
-
MyJavaBean bean = (MyJavaBean) context.getBean("myJavaBean");
-
System.out.println("===============下面輸出結果============");
-
System.out.println("描述:" + bean.getDesc());
-
System.out.println("備註:" + bean.getRemark());
-
-
}
-
}
6)運行結果如下:
7)分析
從上面的結果可以看出,BeanFactoryPostProcessor在bean實例化之前執行,之後實例化bean(調用構造函數,並調用set方法注入屬性值),然後在調用兩個初始化方法前後,執行了BeanPostProcessor。初始化方法的執行順序是,先執行afterPropertiesSet,再執行init-method。
4、進一步深入分析
在使用ApplicationContext啓動spring容器的時候,在AbstractApplicationContext.refresh()方法中,完成相關初始化工作:
1)BeanFactoryPostProcessor.postProcessBeanFactory,是在第5步執行的,invokeBeanFactoryPostProcessors方法實現如下:
-
-
-
-
-
-
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
-
-
for (Iterator it = getBeanFactoryPostProcessors().iterator(); it.hasNext();) {
-
BeanFactoryPostProcessor factoryProcessor = (BeanFactoryPostProcessor) it.next();
-
factoryProcessor.postProcessBeanFactory(beanFactory);
-
}
-
-
-
-
String[] postProcessorNames =
-
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
-
-
-
-
List priorityOrderedPostProcessors = new ArrayList();
-
List orderedPostProcessorNames = new ArrayList();
-
List nonOrderedPostProcessorNames = new ArrayList();
-
for (int i = 0; i < postProcessorNames.length; i++) {
-
if (isTypeMatch(postProcessorNames[i], PriorityOrdered.class)) {
-
priorityOrderedPostProcessors.add(beanFactory.getBean(postProcessorNames[i]));
-
}
-
else if (isTypeMatch(postProcessorNames[i], Ordered.class)) {
-
orderedPostProcessorNames.add(postProcessorNames[i]);
-
}
-
else {
-
nonOrderedPostProcessorNames.add(postProcessorNames[i]);
-
}
-
}
-
-
-
Collections.sort(priorityOrderedPostProcessors, new OrderComparator());
-
invokeBeanFactoryPostProcessors(beanFactory, priorityOrderedPostProcessors);
-
-
-
List orderedPostProcessors = new ArrayList();
-
for (Iterator it = orderedPostProcessorNames.iterator(); it.hasNext();) {
-
String postProcessorName = (String) it.next();
-
orderedPostProcessors.add(getBean(postProcessorName));
-
}
-
Collections.sort(orderedPostProcessors, new OrderComparator());
-
invokeBeanFactoryPostProcessors(beanFactory, orderedPostProcessors);
-
-
-
List nonOrderedPostProcessors = new ArrayList();
-
for (Iterator it = nonOrderedPostProcessorNames.iterator(); it.hasNext();) {
-
String postProcessorName = (String) it.next();
-
nonOrderedPostProcessors.add(getBean(postProcessorName));
-
}
-
invokeBeanFactoryPostProcessors(beanFactory, nonOrderedPostProcessors);
-
}
-
-
-
-
-
private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List postProcessors) {
-
for (Iterator it = postProcessors.iterator(); it.hasNext();) {
-
BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor) it.next();
-
postProcessor.postProcessBeanFactory(beanFactory);
-
}
-
}
通過beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false),獲取spring配置文件中定義的所有實現BeanFactoryPostProcessor接口的bean,然後根據優先級進行排序,之後對於每個BeanFactoryPostProcessor,調用postProcessBeanFactory方法。
2)而BeanPostProcessor的執行,取決於配置文件中bean的定義,如果定義的bean是singleton並且不是抽象類,也不延遲初始化,則BeanPostProcessor是在第11步中執行;而對於prototype的bean,BeanPostProcessor是在程序getBean的時候執行的。在第6步中,調用registerBeanPostProcessors方法,註冊所有實現BeanPostProcessor接口的bean,該方法的實現如下:
-
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
-
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
-
-
-
-
-
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
-
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
-
-
-
-
List priorityOrderedPostProcessors = new ArrayList();
-
List orderedPostProcessorNames = new ArrayList();
-
List nonOrderedPostProcessorNames = new ArrayList();
-
for (int i = 0; i < postProcessorNames.length; i++) {
-
if (isTypeMatch(postProcessorNames[i], PriorityOrdered.class)) {
-
priorityOrderedPostProcessors.add(beanFactory.getBean(postProcessorNames[i]));
-
}
-
else if (isTypeMatch(postProcessorNames[i], Ordered.class)) {
-
orderedPostProcessorNames.add(postProcessorNames[i]);
-
}
-
else {
-
nonOrderedPostProcessorNames.add(postProcessorNames[i]);
-
}
-
}
-
-
-
Collections.sort(priorityOrderedPostProcessors, new OrderComparator());
-
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
-
-
-
List orderedPostProcessors = new ArrayList();
-
for (Iterator it = orderedPostProcessorNames.iterator(); it.hasNext();) {
-
String postProcessorName = (String) it.next();
-
orderedPostProcessors.add(getBean(postProcessorName));
-
}
-
Collections.sort(orderedPostProcessors, new OrderComparator());
-
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
-
-
-
List nonOrderedPostProcessors = new ArrayList();
-
for (Iterator it = nonOrderedPostProcessorNames.iterator(); it.hasNext();) {
-
String postProcessorName = (String) it.next();
-
nonOrderedPostProcessors.add(getBean(postProcessorName));
-
}
-
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
-
}
在第11步中,調用finishBeanFactoryInitialization方法,該方法通過調用DefaultListableBeanFactory.preInstantiateSingletons(),進行相關初始化工作:
從上面的代碼可以看出,對於非抽象類、非延遲初始化的單例bean,在spring容器啓動的時候調用getBean方法來實例化bean,並進行相關初始化工作,getBean方法最終調用AbstractAutowireCapableBeanFactory.doCreateBean方法,該方法的實現如下:
-
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
-
-
BeanWrapper instanceWrapper = null;
-
if (mbd.isSingleton()) {
-
instanceWrapper = (BeanWrapper) this.factoryBeanInstanceCache.remove(beanName);
-
}
-
if (instanceWrapper == null) {
-
instanceWrapper = createBeanInstance(beanName, mbd, args);
-
}
-
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
-
Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
-
-
-
synchronized (mbd.postProcessingLock) {
-
if (!mbd.postProcessed) {
-
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
-
mbd.postProcessed = true;
-
}
-
}
-
-
-
-
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
-
isSingletonCurrentlyInCreation(beanName));
-
if (earlySingletonExposure) {
-
if (logger.isDebugEnabled()) {
-
logger.debug("Eagerly caching bean '" + beanName +
-
"' to allow for resolving potential circular references");
-
}
-
addSingletonFactory(beanName, new ObjectFactory() {
-
public Object getObject() throws BeansException {
-
return getEarlyBeanReference(beanName, mbd, bean);
-
}
-
});
-
}
-
-
-
Object exposedObject = bean;
-
try {
-
populateBean(beanName, mbd, instanceWrapper);
-
exposedObject = initializeBean(beanName, exposedObject, mbd);
-
}
-
catch (Throwable ex) {
-
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
-
throw (BeanCreationException) ex;
-
}
-
else {
-
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
-
}
-
}
-
-
if (earlySingletonExposure) {
-
Object earlySingletonReference = getSingleton(beanName, false);
-
if (earlySingletonReference != null) {
-
if (exposedObject == bean) {
-
exposedObject = earlySingletonReference;
-
}
-
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
-
String[] dependentBeans = getDependentBeans(beanName);
-
Set actualDependentBeans = new LinkedHashSet(dependentBeans.length);
-
for (int i = 0; i < dependentBeans.length; i++) {
-
String dependentBean = dependentBeans[i];
-
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
-
actualDependentBeans.add(dependentBean);
-
}
-
}
-
if (!actualDependentBeans.isEmpty()) {
-
throw new BeanCurrentlyInCreationException(beanName,
-
"Bean with name '" + beanName + "' has been injected into other beans [" +
-
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
-
"] in its raw version as part of a circular reference, but has eventually been " +
-
"wrapped. This means that said other beans do not use the final version of the " +
-
"bean. This is often the result of over-eager type matching - consider using " +
-
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
-
}
-
}
-
}
-
}
-
-
-
registerDisposableBeanIfNecessary(beanName, bean, mbd);
-
-
return exposedObject;
-
}
在該方法中,首先調用createBeanInstance方法,創建bean實例對象(這個時候執行bean的構造方法),然後調用populateBean方法,對bean進行填充,注入相關依賴,之後再調用方法initializeBean,進行相關初始化工作,initializeBean方法的實現如下:
-
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
-
if (bean instanceof BeanNameAware) {
-
((BeanNameAware) bean).setBeanName(beanName);
-
}
-
-
if (bean instanceof BeanClassLoaderAware) {
-
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
-
}
-
-
if (bean instanceof BeanFactoryAware) {
-
((BeanFactoryAware) bean).setBeanFactory(this);
-
}
-
-
Object wrappedBean = bean;
-
if (mbd == null || !mbd.isSynthetic()) {
-
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
-
}
-
-
try {
-
invokeInitMethods(beanName, wrappedBean, mbd);
-
}
-
catch (Throwable ex) {
-
throw new BeanCreationException(
-
(mbd != null ? mbd.getResourceDescription() : null),
-
beanName, "Invocation of init method failed", ex);
-
}
-
-
if (mbd == null || !mbd.isSynthetic()) {
-
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
-
}
-
return wrappedBean;
-
}
從上面的實現可以看出,先調用applyBeanPostProcessorsBeforeInitialization方法,執行每個BeanPostProcessor的postProcessBeforeInitialization,然後調用invokeInitMethods方法,執行bean的初始化方法,最後調用applyBeanPostProcessorsAfterInitialization方法,執行每個BeanPostProcessor的postProcessAfterInitialization方法。這三個方法的實現如下:
-
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
-
throws BeansException {
-
-
Object result = existingBean;
-
for (Iterator it = getBeanPostProcessors().iterator(); it.hasNext();) {
-
BeanPostProcessor beanProcessor = (BeanPostProcessor) it.next();
-
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
-
}
-
return result;
-
}
-
-
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
-
throws BeansException {
-
-
Object result = existingBean;
-
for (Iterator it = getBeanPostProcessors().iterator(); it.hasNext();) {
-
BeanPostProcessor beanProcessor = (BeanPostProcessor) it.next();
-
result = beanProcessor.postProcessAfterInitialization(result, beanName);
-
}
-
return result;
-
}
-
protected void invokeInitMethods(String beanName, Object bean, RootBeanDefinition mbd)
-
throws Throwable {
-
-
boolean isInitializingBean = (bean instanceof InitializingBean);
-
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
-
if (logger.isDebugEnabled()) {
-
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
-
}
-
((InitializingBean) bean).afterPropertiesSet();
-
}
-
-
String initMethodName = (mbd != null ? mbd.getInitMethodName() : null);
-
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
-
!mbd.isExternallyManagedInitMethod(initMethodName)) {
-
invokeCustomInitMethod(beanName, bean, initMethodName, mbd.isEnforceInitMethod());
-
}
-
}
從invokeInitMethods方法的實現可以看出,先執行afterPropertiesSet方法,然後再通過反射,執行init-method指定的方法。
http://jinnianshilongnian.iteye.com/blog/1762632
問題
如下方式可以成功掃描到@Controller註解的Bean,不會掃描@Service/@Repository的Bean。正確
-
<context:component-scan base-package="org.bdp.system.test.controller">
-
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
-
</context:component-scan>
但是如下方式,不僅僅掃描@Controller,還掃描@Service/@Repository的Bean,可能造成一些問題
-
<context:component-scan base-package="org.bdp">
-
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
-
</context:component-scan>
這個尤其在springmvc+spring+hibernate等集成時最容易出問題的地,最典型的錯誤就是:
事務不起作用
這是什麼問題呢?
分析
1、<context:component-scan>會交給org.springframework.context.config.ContextNamespaceHandler處理;
-
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
2、ComponentScanBeanDefinitionParser會讀取配置文件信息並組裝成org.springframework.context.annotation.ClassPathBeanDefinitionScanner進行處理;
3、如果沒有配置<context:component-scan>的use-default-filters屬性,則默認爲true,在創建ClassPathBeanDefinitionScanner時會根據use-default-filters是否爲true來調用如下代碼:
-
protected void registerDefaultFilters() {
-
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
-
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
-
try {
-
this.includeFilters.add(new AnnotationTypeFilter(
-
((Class<? extends Annotation>) cl.loadClass("javax.annotation.ManagedBean")), false));
-
logger.info("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
-
}
-
catch (ClassNotFoundException ex) {
-
-
}
-
try {
-
this.includeFilters.add(new AnnotationTypeFilter(
-
((Class<? extends Annotation>) cl.loadClass("javax.inject.Named")), false));
-
logger.info("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
-
}
-
catch (ClassNotFoundException ex) {
-
-
}
可以看到默認ClassPathBeanDefinitionScanner會自動註冊對@Component、@ManagedBean、@Named註解的Bean進行掃描。如果細心,到此我們就找到問題根源了。
4、在進行掃描時會通過include-filter/exclude-filter來判斷你的Bean類是否是合法的:
-
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
-
for (TypeFilter tf : this.excludeFilters) {
-
if (tf.match(metadataReader, this.metadataReaderFactory)) {
-
return false;
-
}
-
}
-
for (TypeFilter tf : this.includeFilters) {
-
if (tf.match(metadataReader, this.metadataReaderFactory)) {
-
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
-
if (!metadata.isAnnotated(Profile.class.getName())) {
-
return true;
-
}
-
AnnotationAttributes profile = MetadataUtils.attributesFor(metadata, Profile.class);
-
return this.environment.acceptsProfiles(profile.getStringArray("value"));
-
}
-
}
-
return false;
-
}
即
首先通過exclude-filter 進行黑名單過濾;
然後通過include-filter 進行白名單過濾;
否則默認排除。
結論
-
<context:component-scan base-package="org.bdp">
-
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
-
</context:component-scan>
爲什麼這段代碼不僅僅掃描@Controller註解的Bean,而且還掃描了@Component的子註解@Service、@Reposity。因爲use-default-filters默認爲true。所以如果不需要默認的,則use-default-filters=“false”禁用掉。
請參考
《SpringMVC + spring3.1.1 + hibernate4.1.0 集成及常見問題總結》
《第三章 DispatcherServlet詳解 ——跟開濤學SpringMVC》中的ContextLoaderListener初始化的上下文和DispatcherServlet初始化的上下文關係。
Spring源碼解析之初始化 http://blog.csdn.net/pcceo1/article/details/50921162
如果在springmvc配置文件,不使用cn.javass.demo.web.controller前綴,而是使用cn.javass.demo,則service、dao層的bean可能也重新加載了,但事務的AOP代理沒有配置在springmvc配置文件中,從而造成新加載的bean覆蓋了老的bean,造成事務失效。只要使用use-default-filters=“false”禁用掉默認的行爲就可以了。