美文网首页
spring注解驱动开发(1)——组件注册

spring注解驱动开发(1)——组件注册

作者: KeHaoo | 来源:发表于2020-03-25 13:38 被阅读0次

    给容器中注册组件有以下方法

    1. 包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的类]
    2. @Bean[导入的第三方包里面的组件]
    3. @Import[快速给容器中导入一个组件]
      1. @Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
      2. ImportSelector:返回需要导入的组件的全类名数组;
      3. ImportBeanDefinitionRegistrar:手动注册bean到容器中
    4. 使用Spring提供的 FactoryBean(工厂Bean);
      1. 默认获取到的是工厂bean调用getObject创建的对象
      2. 要获取工厂Bean本身,我们需要给id前面加一个&,具体看后面的例子

    1. @Configuration&@Bean给容器中注册组件

    用一个配置类来代替beans.xml文件

    //MainConfig.java
    @Configuration//代表这个是个配置类
    public class MainConfig {
        @Bean//对函数进行标记 表示该函数用来返回一个Bean
        public Person person(){
            return new Person();
        }
    }
    
    主函数
    public class MainTest {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
            Person person = (Person) context.getBean("person");//利用上面的函数名来获取Bean
            System.out.println(person.toString());
        }
    }
    

    运行结果
    Person{name='null', age=0}

    2. @ComponentScan-自动扫描&指定扫描规则

    在xml中配置自动扫描是在beans.xml文件上的
    所以同理,在注解开发中则将注解标记在配置类上

    
    //配置类==配置文件
    @Configuration  //告诉Spring这是一个配置类
    @ComponentScans(
          value = {
                @ComponentScan(value="com.atguigu",includeFilters = {
                    //按照注解来过滤
                      @Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
                      //按照类型过滤
                      @Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class}),
                },useDefaultFilters = false)   
          }
          )
    //@ComponentScan  value:指定要扫描的包
    //excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
    //includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
    //FilterType.ANNOTATION:按照注解
    //FilterType.ASSIGNABLE_TYPE:按照给定的类型;
    //FilterType.ASPECTJ:使用ASPECTJ表达式
    //FilterType.REGEX:使用正则指定
    //FilterType.CUSTOM:使用自定义规则
    public class MainConfig {
       //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
       @Bean("person")
       public Person person01(){
          return new Person("lisi", 20);
       }
    
    }
    
    @Test
    public void test01(){
        //加载配置
       AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
       String[] definitionNames = applicationContext.getBeanDefinitionNames();
       for (String name : definitionNames) {
          System.out.println(name);
       }
    }
    

    3. 自定义TypeFilter指定过滤规则

    @Configuration  //告诉Spring这是一个配置类
    @ComponentScan(value="com.atguigu",
        includeFilters = {@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})},
        useDefaultFilters = false)   
    //FilterType.CUSTOM:使用自定义规则,MyTypeFilter类里面配置了过滤的方法(match方法)
    public class MainConfig {
       
       //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
       @Bean("person")
       public Person person01(){
          return new Person("lisi", 20);
       }
    
    }
    
    public class MyTypeFilter implements TypeFilter {
       /**
        * metadataReader:读取到的当前正在扫描的类的信息
        * metadataReaderFactory:可以获取到其他任何类信息的
        */
       @Override
       public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
             throws IOException {
          // TODO Auto-generated method stub
          //获取当前类注解的信息
          AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
          //获取当前正在扫描的类的类信息
          ClassMetadata classMetadata = metadataReader.getClassMetadata();
          //获取当前类资源(类的路径)
          Resource resource = metadataReader.getResource();
          
          String className = classMetadata.getClassName();
          System.out.println("--->"+className);
          if(className.contains("er")){//类名里包含er的类
             return true;//返回true会在列表里
          }
          return false;//返回false的Bean会从列表里取出
       }
    
    }
    

    4. @Scope设置组件的作用域

    作用域的概念

    @Scope:调整作用域

    • prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。
      每次获取的时候才会调用方法创建对象;
    • singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。以后每次获取就是直接从容器(map.get())中拿,
    • request:同一次请求创建一个实例
    • session:同一个session创建一个实例

    5. @Lazy懒加载

    单实例bean:默认在容器启动的时候创建对象;
    懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化;

    @Configuration
    public class MainConfig2 {
       
       @Lazy
       @Bean("person")
       public Person person(){
          System.out.println("给容器中添加Person....");
          return new Person("张三", 25);
       }
    }
    

    6. @Conditional按照条件注册Bean

    @Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean

    1. 如果配置在类上则这个配置类只有符合条件的情况下,他里面配置的方法才能生效(里面的bean可以被注册)
    2. 如果配置在方法上,则只有符合条件的情况下,方法才能生效(里面的bean可以被注册)

    7. @Import给容器快速导入一个组件

    import注解的源码:

    public @interface Import {
    
       /**
        * {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
        * or regular component classes to import.
        */
       Class<?>[] value();
    
    }
    

    说明import注解中参数可以是以下几种类型

    1. 配置类(意思就是将其他的配置类在这个配置类上声明,加载了这个配置类就同时将import了的配置类一同加载了)
    2. ImportSelector
    3. ImportBeanDefinitionRegistrar
    4. 组件,即普通的类.class
      @Import导入组件(类:如Color.class))时,id默认是组件的全类名

    eg: 假设Color Red Blue这些类已经存在

    @Configuration
    @Import({Color.class,Red.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
    //@Import导入组件(类:如Color.class)),id默认是组件的全类名
    public class MainConfig2 { 
        //没有写任何内容
    }
    
    //自定义逻辑返回需要导入的组件
    public class MyImportSelector implements ImportSelector {
       //返回值,就是到导入到容器中的组件全类名
       //AnnotationMetadata:当前标注@Import注解的类的所有注解信息
       @Override
       public String[] selectImports(AnnotationMetadata importingClassMetadata) {
         
          //方法不要返回null值
          return new String[]{"com.atguigu.bean.Blue","com.atguigu.bean.Yellow"};
       }
    
    }
    
    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
       /**
        * AnnotationMetadata:当前类的注解信息
        * BeanDefinitionRegistry:BeanDefinition注册类;
        *        把所有需要添加到容器中的bean;调用
        *        BeanDefinitionRegistry.registerBeanDefinition手工注册进来
        */
       @Override
       public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
          
          boolean definition = registry.containsBeanDefinition("com.atguigu.bean.Red");
          boolean definition2 = registry.containsBeanDefinition("com.atguigu.bean.Blue");
          if(definition && definition2){
             //指定Bean定义信息;(Bean的类型,Bean。。。)
             RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
             //注册一个Bean,指定bean名
             registry.registerBeanDefinition("rainBow", beanDefinition);
          }
       }
    
    }
    

    8. 使用Factory Bean注册组件

    1. 写一个工厂类
    public class ColorFactoryBean implements FactoryBean<Color> {
       //返回一个Color对象,这个对象会添加到容器中
       @Override
       public Color getObject() throws Exception {
          System.out.println("ColorFactoryBean...getObject...");
          return new Color();
       }
    
       @Override
       public Class<?> getObjectType() {
          return Color.class;
       }
    
       //是单例?
       //true:这个bean是单实例,在容器中保存一份
       //false:多实例,每次获取都会创建一个新的bean;
       @Override
       public boolean isSingleton() {
          return false;
       }
    
    }
    
    1. 将工厂类注册为Bean
    @Configuration
    //@Import导入组件,id默认是组件的全类名
    public class MainConfig2 {
       @Bean
       public ColorFactoryBean colorFactoryBean(){
          return new ColorFactoryBean();
       }
    }
    

    此时获取这个Bean获取到的并不是工厂类的对象,而是工厂类的getObject方法返回的对象
    如果要获取工厂类对象,则需要在id上加上&

    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    @Test
    public void testImport(){
       Object bean4 = applicationContext.getBean("&colorFactoryBean");
       System.out.println(bean4.getClass());
    }
    

    相关文章

      网友评论

          本文标题:spring注解驱动开发(1)——组件注册

          本文链接:https://www.haomeiwen.com/subject/yabtuhtx.html