Spring注解驱动——组件注册系列

1.@Configuration

  从Spring3.0,@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。

  用法:

@Configuration
public class TestConfiguration {
    public TestConfiguration() {
        System.out.println("TestConfiguration容器启动初始化。。。");
    }
}

 

2.@Bean

  给IOC容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id。 相当于<bean></bean>

  用法:

    Bean类:

package com.springs.entity;


import org.springframework.beans.factory.annotation.Value;

public class Person {

    private String name;
    private Integer age;
    private String nickName;
     
    
    public String getNickName() {
        return nickName;
    }
    public void setNickName(String nickName) {
        this.nickName = nickName;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    
    public Person(String name, Integer age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Person() {
        super();
        // TODO Auto-generated constructor stub
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", nickName=" + nickName + "]";
    }

    Bean注入:

@Configuration//告诉Spring这是一个配置类

public class MainConfig {

    //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
    @Bean("person")
    public Person person01(){
        return new Person("lisi", 20);
    }
}

  

3.@ComponentScan

  在配置类上添加 @ComponentScan 注解。该注解默认会扫描该类所在的包下所有的配置类,相当于之前的 <context:component-scan>。

  3.1 基本使用

@Configuration//告诉Spring这是一个配置类
@ComponentScan(value = "com.springs")

public class MainConfig {

    //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
    @Bean("person")
    public Person person01(){
        return new Person("lisi", 20);
    }
}

  3.2 excludeFilters 和 includeFilters 的使用

  •   excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
  •   includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件

      excludeFilters 和 includeFilters 的参数是一个 Filter[] 数组,然而每一个Filter也是一个注解,打开filter来看,我们知道需要设置一个过滤类型和使用的类

    

//FilterType.ANNOTATION:按照注解
//FilterType.ASSIGNABLE_TYPE:按照给定的类型;
//FilterType.ASPECTJ:使用ASPECTJ表达式
//FilterType.REGEX:使用正则指定
//FilterType.CUSTOM:使用自定义规则

    3.2.1 使用(一):注解过滤的使用

@Configuration//告诉Spring这是一个配置类
@ComponentScan(value = "com.springs",includeFilters = {
        @ComponentScan.Filter(type= FilterType.ANNOTATION,classes={Controller.class})},useDefaultFilters = false)

//excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
//includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
//FilterType.ANNOTATION:按照注解
//FilterType.ASSIGNABLE_TYPE:按照给定的类型;
//FilterType.ASPECTJ:使用ASPECTJ表达式
//FilterType.REGEX:使用正则指定
//FilterType.CUSTOM:使用自定义规则
public class MainConfig {

    }
}

    这里涉及到 @ComponentScan 的一个 useDefaultFilters 属性的用法,该属性默认值为 true,也就是说 spring 默认会自动发现被 @Component 、@Repository、@Service 和 @Controller 标注的类,并注册进容器中。要达到只包含某些包的扫描效果,就必须将这个默认行为给禁用掉(在 @ComponentScan 中将 useDefaultFilters 设为 false 即可)

    3.2.2 使用(二):自定义过滤规则

      实现TypeFilter类:

public class MyTypeFilter implements TypeFilter {
    /**
     * metadataReader:读取到的当前正在扫描的类的信息
     * metadataReaderFactory:可以获取到其他任何类信息的
     */
    @Override
    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();

        if(className.contains("er")){
            return true;
        }
        return false;
    }

}

      使用自动规则:

@Configuration//告诉Spring这是一个配置类
@ComponentScan(value = "com.springs",includeFilters = {
        @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class})
},useDefaultFilters = false)

public class MainConfig {


}

  3.3 添加多种扫描规则

     如果使用的 jdk8,则可以直接添加多个 @ComponentScan 来添加多个扫描规则

    可以使用 @ComponentScans 来添加多个 @ComponentScan,从而实现添加多个扫描规则

@Configuration//告诉Spring这是一个配置类
@ComponentScan(value = "com.springs",includeFilters = {
        @ComponentScan.Filter(type= FilterType.ANNOTATION,classes={Controller.class}),
        @ComponentScan.Filter(type =FilterType.ASSIGNABLE_TYPE,classes = {MainService.class}),
        @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class})
},useDefaultFilters = false)


//@ComponentScan  value:指定要扫描的包
//@ComponentScans({@ComponentScan(),@ComponentScan()})  定义多个扫描规则
//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);
    }
}

 

4.@Scope

  用来调整作用域,默认是单例模式,即scope="singleton"。另外scope还有prototype、request、session、global session作用域。

  •   prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。每次获取的时候才会调用方法创建对象;
  •   singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。以后每次获取就是直接从容器(map.get())中拿,
  •   request:同一次请求创建一个实例
  •   session:同一个session创建一个实例
    @Scope("prototype")
    @Bean("person")
    public Person person(){
        System.out.println("给容器中添加Person....");
        return new Person("张三", 25);
    }

 

5.@lazy

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

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

 

6.@Conditional

  @Conditional是Spring4新提供的注解,它的作用是根据某个条件创建特定的Bean,通过实现Condition接口,并重写matches接口来构造判断条件。

  既可以用在类上(满足当前条件,这个类中配置的所有bean注册才能生效;),也可以用在方法上

  用法:

    linux系统条件

/**
     * ConditionContext:判断条件能使用的上下文(环境)
     * AnnotatedTypeMetadata:注释信息
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // TODO是否linux系统
        //1、能获取到ioc使用的beanfactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //2、获取类加载器
        ClassLoader classLoader = context.getClassLoader();
        //3、获取当前环境信息
        Environment environment = context.getEnvironment();
        //4、获取到bean定义的注册类
        BeanDefinitionRegistry registry = context.getRegistry();

        String property = environment.getProperty("os.name");

        //可以判断容器中的bean注册情况,也可以给容器中注册bean
        boolean definition = registry.containsBeanDefinition("person");
        if(property.contains("linux")){
            return true;
        }

        return false;
    }

    Windows系统条件:

public class WindowsCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        if(property.contains("Windows")){
            return true;
        }
        return false;
    }

}

    配置类:

 /**
     * @Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean
     *
     * 如果系统是windows,给容器中注册("bill")
     * 如果是linux系统,给容器中注册("linus")
     */
    @Conditional({WindowsCondition.class})
    @Bean("bill")
    public Person person01(){
        return new Person("Bill Gates",62);
    }

    @Conditional(LinuxCondition.class)
    @Bean("linus")
    public Person person02(){
        return new Person("linus", 48);
    }

  

7.@import

  有时没有把某个类注入到IOC容器中,但在运用的时候需要获取该类对应的bean,此时就需要用到@Import注解。id默认是组件的全类名

  7.1 基本用法:

    创建一个类:

package com.springs.entity;
public class Color {

}

    使用import导入

@Import({Color.class})
//@Import导入组件,id默认是组件的全类名
public class TwoConfig {
}

  7.2 ImportSelector

    返回需要导入的组件的全类名数组;

//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {

    //返回值,就是到导入到容器中的组件全类名
    //AnnotationMetadata:当前标注@Import注解的类的所有注解信息
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // TODO Auto-generated method stub
        //importingClassMetadata
        //方法不要返回null值
        return new String[]{"com.springs.entity.Blue","com.springs.entity.Yellow"};
    }

}

  7.3 ImportBeanDefinitionRegistrar

    手动注册bean到容器中,可以指定其注入名称

ublic class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * AnnotationMetadata:当前类的注解信息
     * BeanDefinitionRegistry:BeanDefinition注册类;
     *         把所有需要添加到容器中的bean;调用
     *         BeanDefinitionRegistry.registerBeanDefinition手工注册进来
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        boolean definition = registry.containsBeanDefinition("com.springs.entity.Red");
        boolean definition2 = registry.containsBeanDefinition("com.springs.entity.Blue");
        if(definition && definition2){
            //指定Bean定义信息;(Bean的类型,Bean。。。)
            RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
            //注册一个Bean,指定bean名
            registry.registerBeanDefinition("rainBow", beanDefinition);
        }
    }

}

 

8.使用Spring提供的 FactoryBean(工厂Bean)注册组件

  •   默认获取到的是工厂bean调用getObject创建的对象
  •   要获取工厂Bean本身,我们需要给id前面加一个& :&colorFactoryBean
//创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {

    //返回一个Color对象,这个对象会添加到容器中
    @Override
    public Color getObject() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("ColorFactoryBean...getObject...");
        return new Color();
    }

    @Override
    public Class<?> getObjectType() {
        // TODO Auto-generated method stub
        return Color.class;
    }

    //是单例?
    //true:这个bean是单实例,在容器中保存一份
    //false:多实例,每次获取都会创建一个新的bean;
    @Override
    public boolean isSingleton() {
        // TODO Auto-generated method stub
        return false;
    }

}
    @Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }

 

10.总结:

 /**
     * 给容器中注册组件;
     * 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前面加一个&
     *             &colorFactoryBean
     */
posted @ 2019-12-18 22:56  萧然成长记  阅读(233)  评论(0编辑  收藏  举报