public interface BeanFactoryPostProcessor { void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; }
實現該接口,能夠在spring的bean建立以前,修改bean的定義屬性。也就是說,Spring容許BeanFactoryPostProcessor在容器實例化任何其它bean以前讀取配置元數據,並能夠根據須要進行修改,例如能夠把bean的scope從singleton改成prototype,也能夠把property的值給修改掉。能夠同時配置多個BeanFactoryPostProcessor,實現類能夠經過實現PriorityOrdered接口來控制各個BeanFactoryPostProcessor的執行次序。 java
public MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throw BeansException { BeanDefinition bd = beanFactory.getBeanDefinition("myJavaBean"); MutablePropertyValues mpv = bd.getPropertyValues(); mpv.addPropertyValue("propertyName", "newValue"); } }xml中配置一下:
<bean class="com.test.MyBeanFactoryPostProcessor" />2.BeanPostProcessor
public interface BeanPostProcessor { Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.containsKey(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (beanName != null && this.targetSourcedBeans.containsKey(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } protected Object createProxy( Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) { ProxyFactory proxyFactory = new ProxyFactory(); // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig. proxyFactory.copyFrom(this); if (!shouldProxyTargetClass(beanClass, beanName)) { // Must allow for introductions; can't just set interfaces to // the target's interfaces only. Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader); for (Class<?> targetInterface : targetInterfaces) { proxyFactory.addInterface(targetInterface); } } Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); for (Advisor advisor : advisors) { proxyFactory.addAdvisor(advisor); } proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } return proxyFactory.getProxy(this.proxyClassLoader); } [proxyFactory] public Object getProxy(ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); } [JdkDynamicAopProxy] public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }若是你有一些其餘獨特的需求也能夠仿照上面的方式本身寫一個BeanPostProcessor註冊到容器中。
咱們看下代碼: spring
protected void invokeInitMethods(String beanName, final 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 + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { ((InitializingBean) bean).afterPropertiesSet(); return null; } }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { ((InitializingBean) bean).afterPropertiesSet(); } } if (mbd != null) { String initMethodName = mbd.getInitMethodName(); if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { invokeCustomInitMethod(beanName, bean, mbd); } } }可是invokeInitMethods方法又是在哪裏調用的呢?是同一個類中的initializeBean方法調用的,代碼以下:
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { invokeAwareMethods(beanName, bean); return null; } }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } 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; }咱們能夠看到這裏首先調用了bean的Aware接口的一些相關方法,而後是調用BeanPostProcessor接口的前置處理, 而後調用上面的bean初始化方法,而後是BeanPostProcessor的後置處理,這正好符合了上圖中描述的調用順序。 其中Aware有不少子接口,像BeanNameAware,BeanClassLoaderAware,BeanFactoryAware等等,用戶能夠編寫實現 了這些接口的bean,這樣在spring回調aware相關接口的時候獲取到一些容器的相關信息。 下面簡單說下使用InitializingBean和init-method方法初始化bean的區別: 1.實現InitializingBean接口是直接調用afterPropertiesSet方法,比經過反射調用init-method指定的方法效率相對來講要高點。 可是init-method方式消除了對spring的依賴 2:若是調用afterPropertiesSet方法時出錯,則不調用init-method指定的方法。