乐趣区

spring基本组件及注解

spring 基本组件如上图:

spring 配置文件

最初使用 xml 配置文件,然后转向注解。

// 配置类 ==== 配置文件
@Configuration
public class MainConfig {
    // 给容器中注册一个 bean, 类型为返回值的类型, 
    // 注意以 @Bean 注册 bean,Id 默认为方法名, 也可通过 @Bean 注解的值来修改
    @Bean
    public Person person01(){return new Person("username",20);
    }
}



  public class MainTest2 {public static void main(String args[]){
    // 加载注解的配置文件         
        ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);    
        // 从容器中获取 bean
        //Person person = (Person) app.getBean("person01");           
        //System.out.println(person);
        String[] namesForBean = app.getBeanNamesForType(Person.class);
        for(String name:namesForBean){System.out.println(name);
        }
    
    }
}



@ComponentScan 扫描规则

@Configuration
@ComponentScan(value="com.enjoy.cap2", includeFilters={@Filter(type=FilterType.ANNOTATION, classes={Controller.class})        
}, useDefaultFilters=false)   
public class Cap2MainConfig {
    // 给容器中注册一个 bean, 类型为返回值的类型, 
    @Bean
    public Person person01(){return new Person("james",20);
    }
}
  1. value 的值说明是扫描此包下面的所有类
  2. includeFilters 表示使用自定义的过滤器, 此时 useDefaultFilters 应该为 false 屏蔽默认过滤器, 自定义的才生效(demo 中表示只扫描 Controller 类型的类)
  3. 另外的 excludeFilters 就是在默认过滤器下再过滤指定的类,自定义过滤器即可,implements
    TypeFilter 即可自定义

@ComponentScan value: 指定要扫描的包
excludeFilters = Filter[] 指定扫描的时候按照什么规则排除那些组件
includeFilters = Filter[] 指定扫描的时候只需要包含哪些组件
useDefaultFilters = false 默认是 true, 扫描所有组件,要改成 false
----扫描规则如下
FilterType.ANNOTATION:按照注解
FilterType.ASSIGNABLE_TYPE:按照给定的类型;比如按 BookService 类型
FilterType.ASPECTJ:使用 ASPECTJ 表达式
FilterType.REGEX:使用正则指定
FilterType.CUSTOM:使用自定义规则,自已写类,实现 TypeFilter 接口

//FilterType.CUSTOM 的例子, 常用
先新增自定义过滤规则类: TestTypeFilter
@ComponentScan(value=”com.enjoy.cap2″,includeFilters={

    @Filter(type=FilterType.CUSTOM,classes={TestTypeFilter.class})

},useDefaultFilters=false)


@scope 注解

spring 中 bean 默认是单例 singleton,@Scope(“prototype”)为多实例。

// 多实例
@Scope("prototype")
@Bean
public Person person(){return new Person("username",20);
}
  • prototype: 多实例:IOC 容器启动并不会去调用方法创建对象放在容器中,而是
    每次获取的时候才会调用方法创建对象
  • singleton: 单实例(默认):IOC 容器启动会调用方法创建对象放到 IOC 容器中
    以后每交获取就是直接从容器(理解成从 map.get 对象)中拿
  • request: 主要针对 WEB 应用,同一次请求创建一个实例
  • session: 同一个 session 创建一个实例(主要掌握前面 2 个即可, 后面 2 个了解)

lazy 懒加载

@lazy 当加入此注解时,则 getBean 调用的时候才会把实例加载到 IOC 容器。


@Conditional 条件注册 bean

public class WinCondition implements Condition{
    
    /*
    *ConditionContext: 判断条件可以使用的上下文(环境)
    *AnnotatedTypeMetadata: 注解的信息
    *
    */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // TODO 是否为 WINDOW 系统
        // 能获取到 IOC 容器正在使用的 beanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // 获取当前环境变量(包括我们操作系统是 WIN 还是 LINUX??)
        Environment environment = context.getEnvironment();
        String os_name = environment.getProperty("os.name");
        if(os_name.contains("Windows")){return true;}
        return false;
    }
}

// 加入条件注解则会按自定义的逻辑注册,true 时注册到容器
@Conditional(WinCondition.class)
@Bean("lison")
public Person lison(){System.out.println("给容器中添加 lison.......");
    return new Person("Lison",28);
}


@Import 注册 bean

@Import(value = { Dog.class,Cat.class,JamesImportSelector.class,JamesImportBeanDefinitionRegistrar.class})


public class JamesImportSelector implements ImportSelector{
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata){
        // 返回全类名的 bean
        return new String[]{"com.enjoy.cap6.bean.Fish","com.enjoy.cap6.bean.Tiger"};
    }
}

public class JamesImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /*
    *AnnotationMetadata: 当前类的注解信息
    *BeanDefinitionRegistry:BeanDefinition 注册类
    *    把所有需要添加到容器中的 bean 加入;
    *    @Scope
    */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {boolean bean1 = registry.containsBeanDefinition("com.enjoy.cap6.bean.Dog");
        boolean bean2 = registry.containsBeanDefinition("com.enjoy.cap6.bean.Cat");
        // 如果 Dog 和 Cat 同时存在于我们 IOC 容器中, 那么创建 Pig 类, 加入到容器
        // 对于我们要注册的 bean, 给 bean 进行封装,
        if(bean1 && bean2){RootBeanDefinition beanDefinition = new RootBeanDefinition(Pig.class);
            registry.registerBeanDefinition("pig", beanDefinition);
        }
    }

}

给容器中注册组件的方式:

  • 1,@Bean: [导入第三方的类或包的组件], 比如 Person 为第三方的类, 需要在我们的 IOC 容器中使用

  • 2, 包扫描 + 组件的标注注解(@ComponentScan: @Controller, @Service @Reponsitory @
    Componet), 一般是针对 我们自己写的类, 使用这个

  • 3,@Import:[快速给容器导入一个组件] 注意:@Bean 有点简单

    a,@Import(要导入到容器中的组件): 容器会自动注册这个组件,bean 的 id 为全类名
    b,ImportSelector: 是一个接口, 返回需要导入到容器的组件的全类名数组
    c,ImportBeanDefinitionRegistrar: 可以手动添加组件到 IOC 容器, 所有 Bean 的注册可以使用 BeanDifinitionRegistry,写 JamesImportBeanDefinitionRegistrar 实现 ImportBeanDefinitionRegistrar 接口即可

  • 4, 使用 Spring 提供的 FactoryBean(工厂 bean)进行注册,实现 FactoryBean<T> 接口即可,在实现方法 getObject 里可写注册的实例。注意:如 MyFactoryBean 为实现了 FactoryBean<T> 接口,getBean(“myFactoryBean”)获取的实例为实现的 getObject 方法里的实例,getBean(“&myFactoryBean”)则为 MyFactoryBean 实例,具体逻辑查看源码可发现
退出移动版