這篇文章主要針對Spring核心註解進行分析linux
Condition 是在spring4.0 增長的條件註解,經過這個能夠功能能夠實現選擇性的注入Bean操做,接下來先學習下Condition是如何使用的,而後分析spring源碼瞭解其中的實現原理。spring
實現案例:設計模式
在Spring容器加載中,若是當前環境是WIN7操做系統就裝配win7實體類、其餘系統就不裝配。安全
@Configuration public class MyConfig { /** * Import做用主要將外部的jar包注入到springioc容器中 @Import(Win7Entity.class) 等於與@Bean * Import註冊的bean對象 id爲當前類全路徑 */ @Bean public Win7Entity win7Entity() { return new Win7Entity(); }
public class V1Spring { public static void main(String[] args) { // 1.基於註解方式實現啓動 ApplicationContext annotationApplicationContext = new AnnotationConfigApplicationContext(MyConfig.class); Win7Entity win7Entity = (Win7Entity) annotationApplicationContext.getBean("win7Entity"); System.out.println(win7Entity);
輸出結果工具
com.mayikt.v1.entity.Win7Entity@5606c0b學習
MyConditionui
public class MyCondition implements Condition { /** * @param context 獲取到當前的上下文 * @param metadata 獲取當前註解的細心 * @return */ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 1.獲取當前的環境 Environment environment = context.getEnvironment(); // win7 linux win8 win10 蘋果系統MAC String osName = environment.getProperty("os.name"); if (osName.equals("Windows 10")) { // 能夠註冊該對象 return true; } // 不能註冊該對象 return false; } }
@Configuration public class MyConfig { /** * Import做用主要將外部的jar包注入到springioc容器中 @Import(Win7Entity.class) 等於與@Bean * Import註冊的bean對象 id爲當前類全路徑 */ @Bean @Conditional(MyCondition.class) public Win7Entity win7Entity() { return new Win7Entity(); }
輸出:this
com.mayikt.v1.entity.Win7Entity@64d7f7e0spa
1.爲何要使用@Import註解?Import註解的主要做用的將外部的jar包注入到springioc容器中操作系統
2.@Bean註解應用場景是什麼?註冊加載外部jar包
@Configuration @Import(Win7Entity.class) public class MyConfig { /** * Import做用主要將外部的jar包注入到springioc容器中 @Import(Win7Entity.class) 等同於@Bean * Import註冊的bean對象 id爲當前類全路徑 */ /* @Bean @Conditional(MyCondition.class) public Win7Entity win7Entity() { return new Win7Entity(); }*/
public class V1Spring { public static void main(String[] args) { // 1.基於註解方式實現啓動 ApplicationContext annotationApplicationContext = new AnnotationConfigApplicationContext(MyConfig.class); Win7Entity win7Entity = (Win7Entity) annotationApplicationContext.getBean("com.mayikt.v1.entity.Win7Entity");//這裏當前類Win7Entity的全路徑 System.out.println(win7Entity);
結果:
com.mayikt.v1.entity.Win7Entity@f4168b8
public class V1Spring { public static void main(String[] args) { // 1.基於註解方式實現啓動 ApplicationContext annotationApplicationContext = new AnnotationConfigApplicationContext(MyConfig.class); Win7Entity win7Entity = (Win7Entity) annotationApplicationContext.getBean("com.mayikt.v1.entity.Win7Entity"); System.out.println(win7Entity); String[] beanDefinitionNames = annotationApplicationContext.getBeanDefinitionNames(); for (int i = 0; i < beanDefinitionNames.length; i++) { System.out.println(beanDefinitionNames[i]); }
結果
com.mayikt.v1.entity.Win7Entity@f4168b8 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 myConfig com.mayikt.v1.entity.Win7Entity
總結下:@Bean註解與@Import註解的區別?
@Bean註解註冊的bean的id是以方法名稱來做爲beanid ,
@Import註解以當前類的完整路徑地址註冊 ,相比來講@Import注入類更加簡單
應用場景都是引入外部jar包
配合@Configuration使用,包括 @EnableAsync, @EnableScheduling, @EnableTransactionManagement, @EnableAspectJAutoProxy, @EnableWebMvc。
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import({PayEntity.class,MyPayEntity.class}) //引入@Import註解 public @interface EnablePayEntity { // 只要啓動的時候 加入該EnablePayEntity 就會將PayEntity實體類注入到spruingioc容器 // Enable註解的話 底層 實際上在調用@Import(PayEntity.class) }
@Configuration @Import(Win7Entity.class) @EnablePayEntity //配置類加上這個註解 public class MyConfig { /** * Import做用主要將外部的jar包注入到springioc容器中 @Import(Win7Entity.class) 等於與@Bean * Import註冊的bean對象 id爲當前類全路徑 */
程序輸出結果
com.mayikt.v1.entity.Win7Entity@130f889 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 myConfig com.mayikt.v1.entity.PayEntity com.mayikt.v1.entity.MyPayEntity com.mayikt.v1.entity.Win7Entity
@EnableXXX註解的實現原理:底層實際上仍是調用@Import註解
public class MyImportSelector implements ImportSelector { /** * 註解信息 * @param importingClassMetadata * @return */ public String[] selectImports(AnnotationMetadata importingClassMetadata) { //注入多個對象,類的完整路徑 return new String[]{"com.mayikt.v1.entity.MemberEntity","com.mayikt.v1.entity.MsEntity"}; } }
@Configuration @Import({Win7Entity.class,MyImportSelector.class}) @EnablePayEntity public class MyConfig { /** * Import做用主要將外部的jar包注入到springioc容器中 @Import(Win7Entity.class) 等於與@Bean * Import註冊的bean對象 id爲當前類全路徑 */
輸出結果
com.mayikt.v1.entity.Win7Entity@16267862 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 myConfig com.mayikt.v1.entity.PayEntity com.mayikt.v1.entity.MyPayEntity com.mayikt.v1.entity.Win7Entity com.mayikt.v1.entity.MemberEntity com.mayikt.v1.entity.MsEntity
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * AnnotationMetadata 註解的信息 * @param importingClassMetadata * @param registry */ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // spring容器中 bean 的信息 Bean Definition描述 手動註冊到ioc容器中 RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(SmsEntity.class); registry.registerBeanDefinition("smsEntity", rootBeanDefinition); // 底層源碼:springioc 底層經過beanDefinitionMap存放 線程是安全的 } //FactoryBean (往IOC容器存儲對象 注入對象) BeanFactory(從ioc工廠獲取bean對象) }
this.beanDefinitionMap.put(beanName, beanDefinition);
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256)
底層經過一個ConcurrentHashMap保存起來的。
@Configuration @Import({Win7Entity.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class}) @EnablePayEntity public class MyConfig { /** * Import做用主要將外部的jar包注入到springioc容器中 @Import(Win7Entity.class) 等於與@Bean * Import註冊的bean對象 id爲當前類全路徑 */
輸出結果
myConfig com.mayikt.v1.entity.PayEntity com.mayikt.v1.entity.MyPayEntity com.mayikt.v1.entity.Win7Entity com.mayikt.v1.entity.MemberEntity com.mayikt.v1.entity.MsEntity smsEntity
public class MyFactoryBean implements FactoryBean<MyEntity> { public MyEntity getObject() throws Exception { return new MyEntity(); } public Class<?> getObjectType() { return MyEntity.class; } //往IOC容器中注入對象 public boolean isSingleton() { // 默認的狀況下就是爲true true表示爲單例 false 表示爲多例 return false; } }
@Configuration @Import({Win7Entity.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class,MyFactoryBean.class}) @EnablePayEntity public class MyConfig { /** * Import做用主要將外部的jar包注入到springioc容器中 @Import(Win7Entity.class) 等於與@Bean * Import註冊的bean對象 id爲當前類全路徑 */
輸出結果
myConfig com.mayikt.v1.entity.PayEntity com.mayikt.v1.entity.MyPayEntity com.mayikt.v1.entity.Win7Entity com.mayikt.v1.entity.MemberEntity com.mayikt.v1.entity.MsEntity com.mayikt.v2.config.MyFactoryBean smsEntity
BeanFactory是個Factory,也就是IOC容器或對象工廠,FactoryBean是個Bean。在Spring中,全部的Bean都是由BeanFactory(也就是IOC容器)來進行管理的。
但對FactoryBean而言,這個Bean不是簡單的Bean,而是一個能生產或者修飾對象生成的工廠Bean,它的實現與設計模式中的工廠模式和修飾器模式相似
底層仍是調用@Compont註解,主要是爲了分類,更好劃分場景,注意要加上掃包範圍
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Mayikt { }
在學習@Autowired的時候咱們已經接觸到了@Qualifier,這節就來詳細學習一下自定義@Qualifier。
例如定義一個交通工具類:Vehicle,以及它的子類Bus和Sedan。
若是用@Autowired來找Vehicle的話,會有兩個匹配的選項Bus和Sedan。爲了限定選項,能夠像下面這樣。
@Autowired @Qualifier("car") private Vehicle vehicle;
若是要頻繁使用@Qualifier("car")而且想讓它變得更有意義,咱們能夠自定義一個@Qualifier。
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface Car{ }
@Autowired @Car private Vehicle vehicle;
@Car public class Sedan implements Vehicle{ }
在一個接口下有兩個實現類使用@Autowired獲取的時候,有什麼問題?
@Autowired默認狀況下使用類型查找,會存在問題。SpringBoot多數據源 設置默認或者優先級。
解決方案:
@Resource按照名稱查找;
@Qualifier指定實現類
@Primary指定實現類的優先級第一,默認獲取
本文參考