Spring註解(一):組件註冊

  1. @Configuration
  2. @Bean
        //@Bean//給容器注入一個bean,類型爲返回值的類型,id默認方法名就是id
        @Bean("person")//指定id爲person
        public Person person(){
            return new Person("李四",12);
        }
    <!-- 該註解對應的xml實現方式 -->
    <bean id="persion" class="indi.com.bean.Person">
        <property name="name" value="張三"></property>
        <property name="age" value="18"></property>
    </bean>
    
    1. 默認是單例的
    2. 設置爲多實例:@Scope
  3. @Scope
        //@Bean//給容器注入一個bean,類型爲返回值的類型,id默認方法名就是id
        @Scop("prototype")
        @Bean("person")//指定id爲person
        public Person person(){
            return new Person("李四",12);
        }
    <!-- 該註解對應的xml實現方式 -->
    <bean id="persion" class="indi.com.bean.Person" scope="prototype">
        <property name="name" value="張三"></property>
        <property name="age" value="18"></property>
    </bean>
    
    1. singleton:單實例(默認):IOC容器啓動器會調用方法創建對象放到IOC容器中,以後每次使用時都直接從容器(map.get())中拿。
    2. prototype:多實例:IOC容器啓動器時並不會調用方法創建對象放到容器中,每次獲取時纔會調用方法創建對象,每次獲取都會調用方法創建對象。
    3. request:同一次請求創建一個實例
    4. session:同一個session創建一個實例
  4. @Lazy:針對單實例bean
    1. 單實例bean:默認容器加載時創建對象
    2. 使用@Lazy:容器加載時不創建對象,第一次使用(獲取)bean對象時創建對象並初始化
          @Lazy
          @Bean("person")//指定id爲person
          public Person person(){
              return new Person("李四",12);
          }
  5. @Conditional:
    1. 按照一定的條件判斷,滿足條件時給容器註冊bean
    2. 可以放在方法上,也可以放在類上(類中組件統一設置)
    3. 使用方法:
      1. 寫Condition的實現類
        package indi.com.config;
        
        import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
        import org.springframework.beans.factory.support.BeanDefinitionRegistry;
        import org.springframework.context.annotation.Condition;
        import org.springframework.context.annotation.ConditionContext;
        import org.springframework.core.env.Environment;
        import org.springframework.core.type.AnnotatedTypeMetadata;
        
        public class LinuxCondition implements Condition {
        
            /**
             *
             * @param conditionContext:判斷條件使用的上下文(環境)
             * @param annotatedTypeMetadata:註釋信息
             * @return
             */
            public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        
                //獲取IOC使用的beanFactory
                ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
                //獲取類加載器
                ClassLoader classLoader = conditionContext.getClassLoader();
                //獲取當前環境
                Environment environment = conditionContext.getEnvironment();
                //獲取bean定義的註冊類
                BeanDefinitionRegistry registry = conditionContext.getRegistry();
        
                //容器中bean的註冊情況
                boolean person = registry.containsBeanDefinition("person");
                
                //獲取系統信息
                String property = environment.getProperty("os.name");
                if(property.contains("linux")){
                    return true;
                }
        
                return false;
            }
        }
        
      2. 註解

        package indi.com.config;
        
        import indi.com.bean.Person;
        import org.springframework.context.annotation.*;
        import org.springframework.stereotype.Controller;
        import org.springframework.stereotype.Service;
        
        @Configuration
        @ComponentScan(value="indi.com")
        public class BeanConfig {
        
            @Conditional({LinuxCondition.class})
            @Bean("linux")
            public Person linux(){
                return new Person("linux",55);
            }
        
        }
        
  6. @ComponentScan
    1. value:指定要掃描的包
      @ComponentScan(value="indi.com")
      <!-- 該註解對應的xml實現方式 -->
      <context:component-scan base-package="indi.com"></context:component-scan>
    2. excludeFilters = Filter[]:掃描時排除指定的組件
      @ComponentScan(value="indi.com",excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})})
    3. includeFilters=Filter[]:掃描時只需要包含指定的組件
      1. 需要禁用默認的掃描規則:userDefaultFilters=false;
        @ComponentScan(value="indi.com",includeFilters = {@ComponentScan.Filter(type=FilterType.ANNOTATION,classes ={Controller.class})},useDefaultFilters = false)})
        <!-- 該註解對應的xml實現方式 -->
        <context:component-scan base-package="indi.com" use-default-filters="false"></context:component-scan>
        
    4. @Filter
      1. type
        1. FilterType.ANNOTATION:按照註解
          type=FilterType.ANNOTATION
        2. FilterType.ASSIGNABLE_TYPE:按照給定的類型
          type=FilterType.ASSIGNABLE_TYPE
        3. FilterType.ASPECTJ:按照ASPECTJ表達式
        4. FilterType.REGEX:按照正則
        5. FilterType.CUSTOM:自定義規則
          1. 寫一個TypeFilter的實現類:MyTypeFilter
            package indi.com.config;
            
            import org.springframework.core.io.Resource;
            import org.springframework.core.type.AnnotationMetadata;
            import org.springframework.core.type.ClassMetadata;
            import org.springframework.core.type.classreading.MetadataReader;
            import org.springframework.core.type.classreading.MetadataReaderFactory;
            import org.springframework.core.type.filter.TypeFilter;
            
            import java.io.IOException;
            
            public class MyTypeFilter implements TypeFilter {
            
                /**
                 *
                 * @param metadataReader:讀取當前正在掃描的類的信息
                 * @param metadataReaderFactory:可以獲取其他任何類的信息
                 * @return
                 * @throws IOException
                 */
                public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
                    //獲取當前類註解的信息
                    AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
                   //獲取當前正在掃描類的類信息
                    ClassMetadata classMetadata = metadataReader.getClassMetadata();
                    //獲取當前類的資源(類路徑)
                    Resource resource = metadataReader.getResource();
            
                    //類名
                    String className = classMetadata.getClassName();
                    System.out.println(className);
                    if(className.contains("er")){
                       return true;
                    }
                    return false;
                }
            }
            
          2. 配置
            
            @ComponentScan(value="indi.com",@Filter(type=FilterType.CUSTOM,class={MyTypeFilter}))
          3. 注意:根據MyTypeFilter的規則可知,在indi.com包下,所有類名中包含"er"的類(無論該類上是否有註解)都能掃描到
  7. @ComponentScans
  8. @Import
    1. 方式一:
      //id默認是組件的全類名
      @Import(類名.class)或者@Import({類名1.class,類名2.class})
    2. 方式二:
      1. 寫一個類實現ImportSelector
        package indi.com.config;
        
        import org.springframework.context.annotation.ImportSelector;
        import org.springframework.core.type.AnnotationMetadata;
        
        //自定義邏輯返回需要導入的組件
        public class MyImportSelector implements ImportSelector {
        
            /**
             *
             * @param annotationMetadata:當前標註@Import註解的類的所有註解信息
             * @return:導入到容器中的組件全類名
             */
            public String[] selectImports(AnnotationMetadata annotationMetadata) {
                //return new String[0];//默認
                return new String[]{類1的全路徑,類2的全路徑};
            }
        }
        
      2. 配置
        //id默認是組件的全類名
        @Import(類名.class)或者@Import({類名1.class,類名2.class,MyImportSelector.class})
    3. 方式三:
      1. 寫一個類實現ImportBeanDefinitionRegistrar
        package indi.com.config;
        
        import org.springframework.beans.factory.support.BeanDefinitionRegistry;
        import org.springframework.beans.factory.support.RootBeanDefinition;
        import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
        import org.springframework.context.annotation.ImportSelector;
        import org.springframework.core.type.AnnotationMetadata;
        
        
        public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
        
            /**
             *
             * @param annotationMetadata:當前類的註解信息
             * @param beanDefinitionRegistry:beanDefinition註冊類
             *                              將所有需要添加到容器中的bean,
             *                              通過beanDefinitionRegistry.registerBeanDefinition手工註冊進來
             */
            public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
                boolean test = beanDefinitionRegistry.containsBeanDefinition("類的全路徑");
                if(test){
                    RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(類.class);
                    beanDefinitionRegistry.registerBeanDefinition("test",rootBeanDefinition);
                }
            }
        }
        
      2. 配置
        //id默認是組件的全類名
        @Import(類名.class)或者@Import({類名1.class,類名2.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
  9. FactoryBean(工廠Bean)
    1. 創建Spring定義的FactoryBean,實現FactoryBean
    2. 將創建的FactoryBean加入容器中
      1. 注意:工廠Bean獲取的是調用getObject創建的對象
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        Object bean = applicationContext.getBean("工具bean的註冊ID");
      2. 獲取工廠Bean本身:
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        Object bean = applicationContext.getBean("&工具bean的註冊ID");

 

總結:給容器中註冊組件

  • 包掃描+組件標註註解(@Controller、@Service、@Repository、@Component)
  • @Bean:導入第三方包裏面的組件
  • @Import:快速給容器中導入一個組件
    • @Import(類名.class):容器中自動導入這個組件,id默認爲全類名
    • ImportSelector:返回需要導入的組件的全類名數組
    • ImportBeanDefinitionRegistrar:手動註冊bean到容器中
  • 使用Spring提供的FactoryBean
    • 默認獲取的是工廠bean調用的getObject創建的對象
    • 要獲取工廠bean本身,需要給id前面加一個&
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章