一、BeanDefinition 接口
說到BeanDefinition,就要說到java的核心思想了,萬物皆對象。眾所周知,java是面向對象的編程語言,所有的事務都可以用一個對象來描述,jdk提供了用來描述類的類Class,spring為了能更好的描述bean,也提供了一個類,那就是BeanDefinition。簡而言之,BeanDefinition就是用來描述bean的類。
執行時機:讀取bean時,就會使用,生成對應的BeanDefinition對象
/** * * BeanDefinition用來描述bean的類,該實例具有屬性值。 * */ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { /** * 單例 * */ String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; /** * 原型即多例 * */ String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; /** * */ int ROLE_APPLICATION = 0; /** * * ROLE_SUPPORT = 1 表示這個類是用戶本身的,是從配置文件中過來的 */ int ROLE_SUPPORT = 1; /** * * ROLE_INFRASTRUCTURE = 2 表示這個bean是spring自己的 */ int ROLE_INFRASTRUCTURE = 2; /** * 父類的名字 */ void setParentName(@Nullable String parentName); @Nullable String getParentName(); /** * bean 的 class name */ void setBeanClassName(@Nullable String beanClassName); @Nullable String getBeanClassName(); /** * 作用域 */ void setScope(@Nullable String scope); @Nullable String getScope(); /** * 是否懶加載 */ void setLazyInit(boolean lazyInit); boolean isLazyInit(); /** * 依賴 */ void setDependsOn(@Nullable String... dependsOn); @Nullable String[] getDependsOn(); void setAutowireCandidate(boolean autowireCandidate); /** * * 是否啟用自動裝配 */ boolean isAutowireCandidate(); /** * primary標注,表示優先注入,優先使用 */ void setPrimary(boolean primary); boolean isPrimary(); /** * 工廠名字 * */ void setFactoryBeanName(@Nullable String factoryBeanName); @Nullable String getFactoryBeanName(); /** * 工廠方法名字 */ void setFactoryMethodName(@Nullable String factoryMethodName); @Nullable String getFactoryMethodName(); /** * * 返回此bean的構造函數參數值。 */ ConstructorArgumentValues getConstructorArgumentValues(); /** * * 構造方法是否有構造參數 * @since 5.0.2 */ default boolean hasConstructorArgumentValues() { return !getConstructorArgumentValues().isEmpty(); } MutablePropertyValues getPropertyValues(); /** * Return if there are property values values defined for this bean. * @since 5.0.2 */ default boolean hasPropertyValues() { return !getPropertyValues().isEmpty(); } /** * * spring bean初始化完成調用的方法的名字 * */ void setInitMethodName(@Nullable String initMethodName); @Nullable String getInitMethodName(); /** * spring bean銷毀前調用的方法的名字 */ void setDestroyMethodName(@Nullable String destroyMethodName); @Nullable String getDestroyMethodName(); void setRole(int role); int getRole(); /** * * bean 描述 * Set a human-readable description of this bean definition. * @since 5.1 */ void setDescription(@Nullable String description); @Nullable String getDescription(); // Read-only attributes /** * * 是否是單例 */ boolean isSingleton(); /** * 是否是原型 即多例 */ boolean isPrototype(); /** * * 是否是抽象 */ boolean isAbstract(); @Nullable String getResourceDescription(); @Nullable BeanDefinition getOriginatingBeanDefinition(); }
從源碼中可以看出BeanDefinition具有多個屬性,可以用來描述bean,其中beanClassName可以用來存儲bean的class,方便后面通過反射創建對象。scope、lazyInit、autowireCandidate等也都是重要屬性。
- BeanMetadataElement接口:BeanDefinition元數據,返回該Bean的來源
- AttributeAccessor接口:提供對BeanDefinition屬性操作能力,
- AbstractBeanDefinition類:抽象類統一實現了BeanDefinition定義的一部分操作,可以說是定義了BeanDefinition很多默認的屬性。 正是在AbstractBeanDefinition基礎上, Spring衍生出了一些列BeaDefinition。
-
RootBeanDefinition:代表一個xml,java Config來的BeanDefinition
-
ChildBeanDefinition:可以讓子BeanDefinition定義擁有從父母哪里繼承配置的能力
-
GenericBeanDefinition:spring2.5后注冊bean首選的是GenericBeanDefinition。GenericBeanDefinition允許動態的設置父bean.GenericBeanDefinition可以作為RootBeanDefinition與ChildBeanDefinition的替代品。
-
AnnotatedBeanDefinition接口:表示注解類型BeanDefinition。有兩個重要的屬性,AnnotationMetadata,MethodMetadata分別表示BeanDefinition的注解元信息和方法元信息
實現了此接口的BeanDefinition可以獲取到注解元數據和方法元數據。 -
AnnotatedGenericBeanDefinition類:表示@Configuration注解注釋的BeanDefinition類
-
ScannedGenericBeanDefinition類:表示@Component、@Service、@Controller等注解注釋的Bean類
BeanDefinitionRegistry 接口

BeanDefinitionReader接口
既可以使用BeanDefinitionRegistry構造。也可以通過loadBeanDefinitions把配置加載為多個BeanDefinition並注冊到BeanDefinitionRegistry中。可以說是高效版本的BeanDefinitionRegistry。
實現類有
- XmlBeanDefinitionReader從xml中讀取BeanDefinition;
- PropertiesBeanDefinitionReader從Properties文件讀取BeanDefinition
AnnotatedBeanDefinitionReader類
對帶有注解的BeanDefinition進行注冊
ClassPathBeanDefinitionScanner類
可以掃描到@Component @Repository @Service @Controller 的BeanDefinition注冊到容器中。
BeanDefinitionHolder
二、BeanFactory和FactoryBean
有很多人弄不清楚BeanFactory和FactoryBean的區別,BeanFactory是創建bean的工廠,我們常說的spring 容器(存儲spring bean的map)就是在BeanFactory中定義的。而FactoryBean是spring提供的一個特殊的bean,通過FactoryBean我們也可以將一個普通class注冊到spring容器中。
BeanFactory
Object getBean(String name) throws BeansException; <T> T getBean(String name, Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; <T> T getBean(Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
從源碼中可以看出BeanFactory提供了很多getBean方法,這個方法就是根據不同的參數來獲取bean對象。BeanFactory是一個工廠用來存儲和創建bean的。
FactoryBean
FactoryBean是spring提供的一個特殊的bean,實現此接口的bean可以往spring容器中添加一個bean。
@Component("indexFactoryBean") public class IndexFactoryBean implements FactoryBean { @Override public Object getObject() throws Exception { IndexDao indexDao = new IndexDao(); return indexDao; } @Override public Class<?> getObjectType() { return IndexDao.class; } } public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); Object indexFactoryBean = context.getBean("indexFactoryBean"); System.out.println(indexFactoryBean.getClass()); } }
執行結果:
indexDao class com.wangcongming.demo.service.IndexDao
可以發現IndexFactoryBean注冊到spring容器中的對象是IndexDao,這就是spring中FactoryBean提供的功能。FactoryBean中getObject()方法可以返回一個對象,spring容器初始化的過程中會將getObject()返回的對象添加到spring容器中。那么如果想獲取IndexFactoryBean本身的對象怎么辦呢?只需在bean name前加&即可取出
public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); Object indexFactoryBean = context.getBean("indexFactoryBean"); System.out.println(indexFactoryBean.getClass()); Object indexFactoryBean2 = context.getBean("&indexFactoryBean"); System.out.println(indexFactoryBean2.getClass()); } }
執行結果:
indexDao class com.wangcongming.demo.service.IndexDao class com.wangcongming.demo.service.IndexFactoryBean
三、BeanFactoryPostProcessor
執行時機:工廠初始化完成之后,在bean被創建成對象之前執行
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
BeanFactoryPostProcessor 工廠后置處理器,它是在工廠初始化完成之后調用,它可以對bean進行修改,是spring提供的一個擴展點。postProcessBeanFactory()方法將factory傳入進去了,可以通過factory進行操作。
BeanDefinitionRegistryPostProcessor
執行時機:是BeanFactoryPostProcessor的子類,會在BeanFactoryPostProcessor之前進行執行
它是BeanFactoryPostProcessor的擴充接口,他擴充了一個方法:
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
可以看到這個方法將registry傳入進來了,這意味着我們可以通過registry向容器中添加bean
四、BeanPostProcessor
bean后置處理器,會在bean初始化完成之后回調該接口的方法。
執行時機:bean對象創建完成,還未放入容器中時執行
@Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; }
這兩個方法有什么區別呢? postProcessBeforeInitialization方法會在postProcessAfterInitialization之前回調,值得注意的是postProcessAfterInitialization方法的回調是在所有的BeanPostProcessor的postProcessBeforeInitialization方法執行完成之后。
五、InitializingBean
InitializingBean接口為bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是繼承該接口的類,在初始化bean的時候會執行該方法(創建出bean實例后)。
在spring初始化bean的時候,如果該bean是實現了InitializingBean接口,並且同時在配置文件中指定了init-method,系統則是先調用afterPropertiesSet方法,然后在調用init-method中指定的方法。
spring要求這個init-method方法是一個無參數的方法。
注意這個順序:
- @PostConstruct注解標注的方法(JSR250)
- 實現InitializingBean接口的afterPropertiesSet方法(Spring的接口)
- 使用@Bean注解屬性initMethod自定義的方法(Spring提供)
六、DisposableBean
該接口的作用是:允許在容器銷毀該bean的時候獲得一次回調。DisposableBean接口也只規定了一個方法:destroy。
關於在spring 容器初始化 bean 和銷毀前所做的操作定義方式還有以下種:
- 通過@PostConstruct和@PreDestroy注解實現初始化和銷毀bean之前進行的操作。
- 通過在xml中定義init-method和destory-method方法。
注意:
多例bean的生命周期不會由Spring容器來管理,說的簡單一點,多例bean其實就是自生自滅的,和容器沒有關系。 ,這里的DisposableBean中的方法是由Spring容器來調用的,所以如果一個多例實現了DisposableBean是沒有啥意義的,因為相應的方法根本不會被調用,當然在XML配置文件中指定了destroy方法,也是沒有意義的。
七、**Aware接口
Spring框架提供了多個*Aware接口,用於輔助Spring Bean以編程的方式調用Spring容器。通過實現這些接口,可以增強Spring Bean的功能,但是也會造成對Spring容器的綁定。
- ApplicationContextAware:Spring框架啟動時,ApplicationContext初始化實現了該接口的Spring Bean時,會將ApplicationContext的引用作為參數傳遞給創建的Bean實例,創建的Bean實例可以通過ApplicationContext的引用操作Spring框架的各種資源。
- ApplicationEventPublisherAware:應用事件發布器,用於發布事件。
- BeanClassLoaderAware:加載Spring Bean的類加載器。
- BeanFactoryAware:獲得當前bean Factory,從而調用容器的服務
- BootstrapContextAware:資源適配器BootstrapContext,如JCA,CCI
- BeanNameAware:獲得到容器中Bean的名稱
- EmbeddedValueResolverAware:通過 EmbeddedValueResolverAware 接口可以獲取spring容器加載的一些屬性值。
- EnvironmentAware:獲取Environment對象。Environment是Spring的核心組件之一,可以理解為ApplicationContext的運行時環境,從中我們可以獲取操作系統信息、配置文件(application.properties等)中定義的屬性信息等。
- ImportAware:可以獲取到導入該配置類接口的數據配置,是需要與@Import一起使用的。
- MessageSourceAware:得到message source從而得到文本信息
- NotificationPublisherAware:JMX通知
- ResourceLoaderAware:獲取資源加載器,可以獲得外部資源文件
- ServletConfigAware:獲取ServletConfig
- ServletContextAware:獲取ServletContext
ApplicationContextAware
1、為什么需要ApplicationContextAware?
在某些類中我們經常需要通過ApplicationContext來獲取需要的bean,但每一次使用new ClassPathXmlApplicationContext()都會重新裝配文件並實例化上下文bean,這樣肯定是很麻煩的,此時ApplicationContextAware接口的作用就體現出來了——spring會給實現此接口的類注入ApplicationContext對象
2、如何使用?
通常我們是寫一個AppContextUtil工具類
mport org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class AppContextUtil implements ApplicationContextAware { // 定義靜態ApplicationContext private static ApplicationContext applicationContext = null; /** * 重寫接口的方法,該方法的參數為框架自動加載的IOC容器對象 * 該方法在啟動項目的時候會自動執行,前提是該類上有IOC相關注解,例如@Component * @param applicationContext ioc容器 * @throws BeansException e */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // 將框架加載的ioc賦值給全局靜態ioc AppContextUtil.applicationContext = applicationContext; log.info("==================ApplicationContext加載成功=================="); } // 獲取applicationContext public static ApplicationContext getApplicationContext() { return applicationContext; } // 通過name獲取 Bean. public static Object getBean(String name) { return getApplicationContext().getBean(name); } // 通過class獲取Bean. public static <T> T getBean(Class<T> clazz) { return getApplicationContext().getBean(clazz); } // 通過name,以及Clazz返回指定的Bean public static <T> T getBean(String name, Class<T> clazz) { return getApplicationContext().getBean(name, clazz); } }
3、spring何時注入上下文?
通過源碼跟蹤了解到AbstractApplicationContext.class下的refresh()方法中的prepareBeanFactory這句跟Aware有關,我們還可以看到:ApplicationContextAware是在spring初始化完bean后才注入上下文的
prepareBeanFactory方法中涉及到上圖紅圈圈這個類,此類中的方法postProcessBeforeInitialization調用了此類中的invokeAwareInterfaces方法:
看到沒,上圖畫圈圈的地方就是spring對實現ApplicationContextAware接口的類調用setApplicationContext進行上下文注入
八、ApplicationEvent抽象類
是個抽象類,里面只有一個構造函數和一個長整型的timestamp。
spring事件使用步驟如下:
- 自定義事件:實現ApplicationEvent。
- 定義監聽器:實現 ApplicationListener
- 使用容器對事件進行發布
1、自定義事件
public class TestEvent extends ApplicationEvent { private String name; private String msg; public TestEvent(Object source){ super(source); } public TestEvent(Object source, String name, String msg) { super(source); this.name = name; this.msg = msg; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
2、定義監聽器
@Component public class TestEventListener implements ApplicationListener<TestEvent> { @Override public void onApplicationEvent(TestEvent testEvent) { System.out.println("姓名:"+testEvent.getName()+"得到消息:"+testEvent.getMsg()); } }
3、使用容器發布事件
@Component public class TestEventPublisher { @Autowired private ApplicationContext applicationContext; public void pushlish(String name, String msg){ applicationContext.publishEvent(new TestEvent(this, name,msg)); } }
九、ApplicationListener接口
是一個接口,里面只有一個onApplicationEvent方法。所以自己的類在實現該接口的時候,要實現該方法。
十、Enable***
- @EnableAspectJAutoProxy:開啟對AspectJ自動代理的支持。
- @EnableAsync:開啟異步方法支持。
- @EnableScheduling:開啟計划任務
- @EnableWebMvc:開啟Web Mvc配置功能