咱們通常在項目開發中都是使用這種方式。java
通常導入第三方組件的時候使用,如註冊一個RedisTemplate
:git
@Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); // 設置值(value)的序列化採用KryoRedisSerializer。 redisTemplate.setValueSerializer(fastJsonRedisSerializer); redisTemplate.setHashValueSerializer(fastJsonRedisSerializer); // 設置鍵(key)的序列化採用StringRedisSerializer。 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; }
通常快速導入一批組件時使用,如同時註冊好幾個動物類:github
@Configuration @Import({DogTestBean.class, CatTestBean.class}) public class ImportConfig { @Bean public ImportTestBean importTestBean() { return new ImportTestBean(); } }
容器中的Bean:redis
打印 Spring 容器中的Bean 開始 org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory importConfig com.xiaolyuh.iimport.DogTestBean com.xiaolyuh.iimport.CatTestBean importTestBean 打印 Spring 容器中的Bean 結束
@Configuration @Import({DogTestBean.class, CatTestBean.class, AnimalImportSelector.class}) public class ImportConfig { @Bean public ImportTestBean importTestBean() { return new ImportTestBean(); } } public class AnimalImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { // 不能返回NULL,不然會報空指針異常,打斷點能夠看到源碼 return new String[]{"com.xiaolyuh.iimport.bean.FishTestBean", "com.xiaolyuh.iimport.bean.TigerTestBean" }; } }
打印 Spring 容器中的Bean 開始 org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory importConfig com.xiaolyuh.iimport.bean.DogTestBean com.xiaolyuh.iimport.bean.CatTestBean com.xiaolyuh.iimport.bean.FishTestBean com.xiaolyuh.iimport.bean.TigerTestBean importTestBean 打印 Spring 容器中的Bean 結束
selectImports()
這個方法不能返回NULL,不然會報空指針異常,從源代碼來看是在以下位置報出來的:springprivate Collection<SourceClass> asSourceClasses(String[] > classNames) throws IOException { List<SourceClass> annotatedClasses = new ArrayList<SourceClass>(classNames.length); for (String className : classNames) { annotatedClasses.add(asSourceClass(className)); } return annotatedClasses; }
只有動物園裏面有 貓和狗的時候我麼纔將豬注入進去。ImportBeanDefinitionRegistrar註冊器,在註冊bean的過程當中會在最後執行。緩存
@Configuration @Import({DogTestBean.class, CatTestBean.class, AnimalImportSelector.class, AnimalImportBeanDefinitionRegistrar.class}) public class ImportConfig { @Bean public ImportTestBean importTestBean() { return new ImportTestBean(); } } public class AnimalImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * @param importingClassMetadata 當前類的註解信息 * @param registry 註冊器,經過註冊器將特定類註冊到容器中 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 貓和狗的Bean咱們能夠聲明一個註解,相似Spring Boot的條件註解 boolean isContainsDog = registry.containsBeanDefinition(DogTestBean.class.getName()); boolean isContainsCat = registry.containsBeanDefinition(CatTestBean.class.getName()); if (isContainsDog && isContainsCat) { RootBeanDefinition beanDefinition = new RootBeanDefinition(PigTestBean.class); // 第一個參數是Bean id ,第二個是RootBeanDefinition registry.registerBeanDefinition("pigTestBean", beanDefinition); } } }
打印 Spring 容器中的Bean 開始 org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory importConfig com.xiaolyuh.iimport.bean.DogTestBean com.xiaolyuh.iimport.bean.CatTestBean com.xiaolyuh.iimport.bean.FishTestBean com.xiaolyuh.iimport.bean.TigerTestBean importTestBean pigTestBean 打印 Spring 容器中的Bean 結束
- 經過該方式註冊Bean,必須將Bean封裝成 RootBeanDefinition。
- ImportBeanDefinitionRegistrar註冊器,在註冊bean的過程當中會在最後執行。
- 跟進源碼咱們能夠看到容器就是一個Map,
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
@Configuration @Import({DogTestBean.class, CatTestBean.class, AnimalImportSelector.class, AnimalImportBeanDefinitionRegistrar.class}) public class ImportConfig { @Bean public ImportTestBean importTestBean() { return new ImportTestBean(); } // 最終注入的實際上是 MonkeyTestBean 類 @Bean public AnimalFactoryBean monkeyTestBean() { return new AnimalFactoryBean(); } } public class AnimalFactoryBean implements FactoryBean { /** * 獲取實例 * * @return * @throws Exception */ @Override public MonkeyTestBean getObject() throws Exception { return new MonkeyTestBean(); } /** * 獲取示例類型 * * @return */ @Override public Class<?> getObjectType() { return MonkeyTestBean.class; } /** * 是否單例 * * @return */ @Override public boolean isSingleton() { return true; } }
輸出結果:框架
打印 Spring 容器中的Bean 開始 org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory importConfig com.xiaolyuh.iimport.bean.DogTestBean com.xiaolyuh.iimport.bean.CatTestBean com.xiaolyuh.iimport.bean.FishTestBean com.xiaolyuh.iimport.bean.TigerTestBean importTestBean monkeyTestBean pigTestBean 打印 Spring 容器中的Bean 結束 開始獲取容器中的Bean 14:07:12.533 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'monkeyTestBean' MonkeyTestBean 初始化 14:07:12.534 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'monkeyTestBean' true 我愛吃香蕉
使用該方式會註冊兩個Bean到容器,一個是
FactoryBean
,一個是咱們真實須要註冊的Bean,如demo中的MonkeyTestBean
。 使用該方式無論是不是單例模式下,實例化真實的Bean都是在第一次獲取Bean 的時候。也就是說都是在容器初始化完成以後。 根據名稱獲取Bean的時候,若是在Bean名稱前加一個&
符號表示獲取工廠Bean,不然是獲取咱們真實註冊的Bean。ide
- ‘@Autowired’ 和‘@Inject’他們都是經過‘AutowiredAnnotationBeanPostProcessor’ 類實現的依賴注入,兩者具備可互換性。
- ‘@Resource’經過 ‘CommonAnnotationBeanPostProcessor’ 類實現依賴注入,即使如此他們在依賴注入時的表現仍是極爲相近的。
如下是他們在實現依賴注入時執行順序的歸納:spring-boot
@Autowired and @Injectui
@Resource
https://github.com/wyh-spring-ecosystem-student/spring-boot-student/tree/releases
spring-boot-student-spring 工程
爲監控而生的多級緩存框架 layering-cache這是我開源的一個多級緩存框架的實現,若是有興趣能夠看一下