Spring 之容器注册组件

概述

给容器中注册组件一共有 4 种方法

  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

一、@Configuration @Bean 给容器注册组件

传统的 XML 配置方式

在src 下定义类 Person
public class Person {

    private String name;
    private Integer age;

    // 省略无参构造,有参构造,getter/setter,toString 方法
}
resource/beans.xml 里定义 bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="person" class="cn.duniqb.bean.Person">
        <property name="age" value="18"/>
        <property name="name" value="zs"/>
    </bean>
</beans>
测试
public class MainTest {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Person person = (Person) applicationContext.getBean("person");
        System.out.println(person);
    }
}
输出
Person{name='zs', age=18}

使用配置类

创建配置类

使用 @Bean 注解,可以显式地指定 id

/**
 * 配置类等同于配置文件
 * 标识这是一个配置类
 */
@Configuration
public class MainConfig {
    /**
     * 给容器注册一个 Bean
     * @return 类型是返回值的类型,id 默认用方法名为 id
     */
    @Bean("person")
    public Person person01() {
        return new Person("ls", 20);
    }
}
测试
public class MainTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        Person bean = applicationContext.getBean(Person.class);
        System.out.println(bean);
        // 查看 bean 的id
        String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
        for (String s : namesForType) {
            System.out.println(s);
        }
    }
}
输出
Person{name='ls', age=20}
person

二、组件扫描 @ComponentScan

以下会扫描出在 cn.duniqb 下的所有类

/**
 * 配置类等同于配置文件
 * 标识这是一个配置类
 */
@Configuration
@ComponentScan(value = "cn.duniqb")
public class MainConfig {

    /**
     * 给容器注册一个 Bean
     *
     * @return 类型是返回值的类型,id 默认用方法名为 id
     */
    @Bean("person")
    public Person person01() {
        return new Person("ls", 20);
    }
}
排除指定注解

指定扫描的时候按照什么规则排除那些组件,默认是空

Filter[] excludeFilters() default {};

以下会排除带有 @Controller 与 @Service 的组件

@Configuration
@ComponentScan(value = "cn.duniqb", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
})
public class MainConfig {

    /**
     * 给容器注册一个 Bean
     *
     * @return 类型是返回值的类型,id 默认用方法名为 id
     */
    @Bean("person")
    public Person person01() {
        return new Person("ls", 20);
    }
}
包含指定注解
@Configuration
@ComponentScan(value = "cn.duniqb", includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
}, useDefaultFilters = false)
public class MainConfig {
    /**
     * 给容器注册一个 Bean
     *
     * @return 类型是返回值的类型,id 默认用方法名为 id
     */
    @Bean("person")
    public Person person01() {
        return new Person("ls", 20);
    }
}

三、@Scope 设置组件作用域

通过源码看出,Scope 有 4 个取值,分别是多实例,单实例,Web 环境下的单请求,Web 环境下的Session

单实例是默认值, ioc 容器会启动调用方法创建对象放到 ioc 容器中,以后每次获取都是从容器中拿取。

多实例时,每次获取时候才会调用方法创建对象。

/**
 * Specifies the name of the scope to use for the annotated component/bean.
 * <p>Defaults to an empty string ({@code ""}) which implies
 * {@link ConfigurableBeanFactory#SCOPE_SINGLETON SCOPE_SINGLETON}.
 * @since 4.2
 * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE
 * @see ConfigurableBeanFactory#SCOPE_SINGLETON
 * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
 * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
 * @see #value
 */
@AliasFor("value")
String scopeName() default "";
默认是是单实例的
@Configuration
public class MainConfig2 {
    @Scope
    @Bean("person")
    public Person person() {
        return new Person("zs", 25);
    }
}
添加后是多实例
@Configuration
public class MainConfig2 {
    @Scope("prototype")
    @Bean("person")
    public Person person() {
        return new Person("zs", 25);
    }
}

懒加载 @Lazy

单实例 bean,默认在容器启动时创建对象,懒加载是容器启动时不创建对象,在第一次获取时创建对象,并初始化,此时还是单实例。

@Configuration
public class MainConfig2 {
    @Scope("prototype")
    @Bean("person")
    @Lazy
    public Person person() {
        return new Person("zs", 25);
    }
}

四、按条件注册@Conditional

/**
 * Conditional
 * @return
 */
@Conditional({WindowsCondition.class})
@Bean("bill")
public Person person01() {
    return new Person("Bill Gates", 62);
}

只有下面情况 true 时才会加载

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;
    }
}

快速导入 @Import

在配置类上加注解即可实现注册

@Configuration
@Import(Color.class)
public class MainConfig2 {

}

没有修不好的电脑
原文地址:https://www.cnblogs.com/duniqb/p/12702442.html