Java教程

spring系列-注解驱动原理及源码-bean组件注册

本文主要是介绍spring系列-注解驱动原理及源码-bean组件注册,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

目录

一、环境初始化

1、环境准备

二、bean的手动注入

1、xml方式注入bean

2、使用@Configuration&@Bean方式注入bean

三、自动扫描注册组件及bean

1、使用xml方式扫描包

2、使用@ComponentScan扫描

3、包扫描的排除

四、组件注册用到的其他注解

1、使用@Scope-设置组件作用域

2、@Lazy-bean懒加载

3、@Conditional-按照条件注册bean

五、使用@Import给容器中快速导入一个组件

1、@Import导入组件

2、使用ImportSelector来导入bean

3、使用ImportBeanDefinitionRegistrar来导入bean

六、使用FactoryBean创建bean

1、使用FactoryBean创建bean

七、bean组件注册小结


友情提示:此系列文档不适宜springboot零基础的同学~

一、环境初始化

1、环境准备

(1)新建maven项目。

(2)pom导入spring-bean有关的包,以及junit测试

<!--引入spring-bean有关的包-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.12.RELEASE</version>
</dependency>
<!--junit测试-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

(3)环境包如下

 

二、bean的手动注入

1、xml方式注入bean

(1)定义Person类

package com.xiang.spring.bean;

public class Person {

    private String name;
    private Integer age;

        ……get set toString……
}

(2)在resources目录下创建beans.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--使用xml配置bean-->
    <bean id="person" class="com.xiang.spring.bean.Person">
        <property name="age" value="18"></property>
        <property name="name" value="lisi"></property>
    </bean>
</beans>

(3)创建main方法来获取ioc中的bean

package com.xiang.spring;

import com.xiang.spring.bean.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainTest {

    public static void main(String[] args) {

        // 使用xml配置文件获取容器中的bean
        ApplicationContext applicationContextXml = new ClassPathXmlApplicationContext("beans.xml");
        Person xmlPerson = (Person) applicationContextXml.getBean("person");
        System.out.println(xmlPerson);
    }
}

2、使用@Configuration&@Bean方式注入bean

(1)定义Person类

同上

(2)创建配置类

package com.xiang.spring.config;

import com.xiang.spring.bean.Person;
import org.springframework.context.annotation.Bean;

// 告诉spring这是一个配置类
@Configuration
public class MainConfig {

    /**
     * 给容器中注册一个bean,类型为返回值的类型,默认是用方法名作为id名称
     * 使用@Bean("person") 可以给bean指定名称,而不用方法名
     */
    //@Bean
    @Bean("person")
    public Person person01() {
        return new Person("zhangsan", 20);
    }

}

(3)创建main方法来获取ioc中的bean

package com.xiang.spring;

import com.xiang.spring.bean.Person;
import com.xiang.spring.config.MainConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainTest {

    public static void main(String[] args) {

        // 使用xml配置文件获取容器中的bean
        ApplicationContext applicationContextXml = new ClassPathXmlApplicationContext("beans.xml");
        Person xmlPerson = (Person) applicationContextXml.getBean("person");
        System.out.println(xmlPerson);
        System.out.println("------------------------");
        // 创建IOC容器,加载配置类,获取到容器中的Person
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        // 多种方式获取容器中的bean
        Person bean = applicationContext.getBean(Person.class);
        Person bean2 = applicationContext.getBean("person", Person.class);
        System.out.println(bean);
        System.out.println(bean2);
        // 获取指定class类型的bean的名字(默认为bean的方法名)
        String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
        for (String s : beanNamesForType) {
            System.out.println(s);
        }
    }
}

// 运行结果
Person{name='lisi', age=18}
------------------------
Person{name='zhangsan', age=20}
Person{name='zhangsan', age=20}
person

三、自动扫描注册组件及bean

1、使用xml方式扫描包

(1)在beans.xml添加以下内容

<!--包扫描,只要标注了@Controller、@Service、@Repository、@Component的bean都会创建到容器中-->
<!--use-default-filters禁用默认规则,才可以继续设置扫描过滤规则-->
<context:component-scan base-package="com.xiang.spring" use-default-filters="false"></context:component-scan>

2、使用@ComponentScan扫描

(1)定义Controller、Service、Dao类

package com.xiang.spring.controller;
import org.springframework.stereotype.Controller;
@Controller
public class BookController {
}

package com.xiang.spring.service;
import org.springframework.stereotype.Service;
@Service
public class BookService {
}

package com.xiang.spring.dao;
import org.springframework.stereotype.Repository;
@Repository
public class BookDao {
}

(2)设置配置类

package com.xiang.spring.config;


import com.xiang.spring.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;


// 告诉spring这是一个配置类
@Configuration
@ComponentScan(value = "com.xiang.spring")
public class MainConfig {

    /**
     * 给容器中注册一个bean,类型为返回值的类型,默认是用方法名作为id名称
     * 使用@Bean("person") 可以给bean指定名称,而不用方法名
     */
    //@Bean
    @Bean("person")
    public Person person01() {
        return new Person("zhangsan", 20);
    }
}

(3)写测试类获取ioc容器中所有注册的bean

package com.xiang.spring.test;

import com.xiang.spring.config.MainConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IOCTest {

    @Test
    public void test01(){
        // 获取IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        // 获取容器中的所有bean名称
        String[] definitionNames = applicationContext.getBeanDefinitionNames();
        for (String definitionName : definitionNames) {
            System.out.println(definitionName);
        }
    }
}

// 运行结果
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookController
bookDao
bookService
person

3、包扫描的排除

(1)excludeFilters排除需要扫描的组件

修改配置类

package com.xiang.spring.config;

import com.xiang.spring.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;

// 告诉spring这是一个配置类
@Configuration
/**
* 包扫描,只要标注了@Controller、@Service、@Repository、@Component的bean都会创建到容器中
* @ComponentScan :value:指定要扫描的包;
*                   excludeFilters = Filter[]: 指定扫描的时候按照什么规则排除哪些组件
*                   includeFilters = Filter[]: 指定扫描的时候只需要包含哪些组件,还需要加useDefaultFilters = false
*      jdk8以上可以写多个@ComponentScan,非jdk8以上也可以用@ComponentScans = {@ComponentScan},用来指定多个扫描的包
*/
@ComponentScan(value = "com.xiang.spring", excludeFilters = {
        @Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class}) // 根据注解排除,排除Controller、Service
})
public class MainConfig {

    /**
     * 给容器中注册一个bean,类型为返回值的类型,默认是用方法名作为id名称
     * 使用@Bean("person") 可以给bean指定名称,而不用方法名
     */
    //@Bean
    @Bean("person")
    public Person person01() {
        return new Person("zhangsan", 20);
    }
}


// 运行结果
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookDao
person

(2)includeFilters只需要包含哪些组件

修改配置类

package com.xiang.spring.config;

import com.xiang.spring.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;

// 告诉spring这是一个配置类
@Configuration
/**
* 包扫描,只要标注了@Controller、@Service、@Repository、@Component的bean都会创建到容器中
* @ComponentScan :value:指定要扫描的包;
*                   excludeFilters = Filter[]: 指定扫描的时候按照什么规则排除哪些组件
*                   includeFilters = Filter[]: 指定扫描的时候只需要包含哪些组件,还需要加useDefaultFilters = false
*      jdk8以上可以写多个@ComponentScan,非jdk8以上也可以用@ComponentScans = {@ComponentScan},用来指定多个扫描的包
*/
@ComponentScan(value = "com.xiang.spring", includeFilters = {
        @Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class}) // 需要包含哪些组件:Controller、Service
}, useDefaultFilters = false)
public class MainConfig {

    /**
     * 给容器中注册一个bean,类型为返回值的类型,默认是用方法名作为id名称
     * 使用@Bean("person") 可以给bean指定名称,而不用方法名
     */
    //@Bean
    @Bean("person")
    public Person person01() {
        return new Person("zhangsan", 20);
    }
}

// 运行结果
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookController
bookService
person

(3)包扫描排除的枚举类型详解

public enum FilterType {
    ANNOTATION, // 注解类型
    ASSIGNABLE_TYPE, // 按照指定的类型
    ASPECTJ, // 按照Aspectj的表达式,基本不会用到
    REGEX, // 按照正则表达式
    CUSTOM; // 自定义规则

    private FilterType() {
    }
}

(4)按照指定的类型排除

在配置类中配置:

@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = BookService.class) // 排除规则,只有BookService会排除

(5)自定义排除规则

① 写过滤规则类

package com.xiang.spring.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 {

    /**
     * MetadataReader :读取到的当前正在扫描的类的信息
     * MetadataReaderFactory:可以获取到其他任何类的信息
     */
    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;
        }
        // 返回true为匹配成功;返回false为匹配结束
        return false;
    }
}

② 配置类中设置自定义过滤规则

// 告诉spring这是一个配置类
@Configuration
@ComponentScan(value = "com.xiang.spring", includeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = MyTypeFilter.class) // 自定义过滤规则
}, useDefaultFilters = false)
public class MainConfig {

③ 执行test类查看结果

package com.xiang.spring.test;

import com.xiang.spring.config.MainConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IOCTest {

    @Test
    public void test01(){
        // 获取IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        // 获取容器中的所有bean名称
        String[] definitionNames = applicationContext.getBeanDefinitionNames();
        for (String definitionName : definitionNames) {
            System.out.println(definitionName);
        }
    }
}

// 打印结果
----->com.xiang.spring.test.IOCTest
----->com.xiang.spring.bean.Person
----->com.xiang.spring.config.MyTypeFilter
----->com.xiang.spring.controller.BookController
----->com.xiang.spring.dao.BookDao
----->com.xiang.spring.MainTest
----->com.xiang.spring.service.BookService
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
person
myTypeFilter
bookController
bookService

四、组件注册用到的其他注解

1、使用@Scope-设置组件作用域

(1)定义配置类

package com.xiang.spring.config;

import com.xiang.spring.bean.Person;
import org.springframework.context.annotation.*;
import org.springframework.context.annotation.ComponentScan.Filter;

@Configuration
public class MainConfig2 {

    /**
     *  默认是单例的,配置方式有四种(取自@Scope的value的注释)
     * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE
     * @see ConfigurableBeanFactory#SCOPE_SINGLETON
     * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
     * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
     *
     * 解析:
     *  prototype:多实例的:ioc容器启动不会调用方法创建对象,每次获取的时候才会调用方法创建对象,每次获取都会调用方法获取对象。
     *  singleton:单实例的(默认值):ioc容器启动,会调用方法创建对象放到ioc容器中,以后每次取就是直接从容器中拿。
     *  request:同一次请求创建一个实例(web环境可用,但也不常用)
     *  session:同一个session创建一个实例(web环境可用,但也不常用)
     */
    @Scope("prototype")
    @Bean("person2")
    public Person person() {
        System.out.println("给容器中添加Person……");
        return new Person("zhangsan", 22);
    }
}

(2)编写测试方法

@Test
public void test02(){
    // 获取IOC容器
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    // 默认是单实例
    Object obj1 = applicationContext.getBean("person2");
    Object obj2 = applicationContext.getBean("person2");
    System.out.println(obj1 == obj2);
}

// 运行结果
给容器中添加Person……
给容器中添加Person……
false

2、@Lazy-bean懒加载

(1)在bean加上@Lazy注解

/**
* 单实例bean:默认在容器启动的时候创建对象。
* 懒加载:容器启动不创建对象,第一次使用(获取)bean时才创建对象,并初始化。
*
*/
@Lazy
@Bean("person2")
public Person person() {
    System.out.println("给容器中添加Person……");
    return new Person("zhangsan", 22);
}

(2)编写测试方法

@Test
public void test02(){
    // 获取IOC容器
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    // 默认是单实例
    System.out.println("--------------");
    Object obj1 = applicationContext.getBean("person2");
}

// 输出结果
--------------
给容器中添加Person……

3、@Conditional-按照条件注册bean

(1)编写两个Condition

package com.xiang.spring.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
// 判断是否是windows系统
public class WindowsCondition implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 能获取到环境信息
        Environment environment = context.getEnvironment();
        // 获取操作系统
        String osName = environment.getProperty("os.name");
        if(osName.contains("Windows")){
            return true;
        }
        return false;
    }
}

package com.xiang.spring.condition;
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;
// 判断是否是linux系统
public class LinuxCondition implements Condition {
    /**
     * ConditionContext:判断条件能使用的上下文环境
     * AnnotatedTypeMetadata:当前标记了@Conditional的注释信息
     */
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 能获取到ioc使用的beanFactory工厂
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // 能获取到类加载器
        ClassLoader classLoader = context.getClassLoader();
        // 能获取到环境信息
        Environment environment = context.getEnvironment();
        // 获取到bean定义的注册类
        BeanDefinitionRegistry registry = context.getRegistry();
        // 可以判断容器中是否包含bean的定义,也可以给容器中注册bean
        registry.containsBeanDefinition("person");
        // 获取操作系统
        String osName = environment.getProperty("os.name");
        if(osName.contains("linux")){
            return true;
        }
        return false;
    }
}

(2)配置类中添加bean

/**
* @Conditional({}):按照一定的条件进行判断,满足条件给容器中注册bean
* 既可以放在方法上,也可以放在类上进行统一设置
*/
@Conditional({LinuxCondition.class})
@Bean
public Person linux() {
    return new Person("linux", 60);
}
@Conditional({WindowsCondition.class})
@Bean
public Person windows() {
    return new Person("windows", 50);
}

(3)测试方法测试一下

@Test
public void test03(){
    // 获取IOC容器
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    ConfigurableEnvironment environment = applicationContext.getEnvironment();
    System.out.println("当前运行环境" + environment.getProperty("os.name"));
    Map<String, Person> beansOfType = applicationContext.getBeansOfType(Person.class);
    System.out.println(beansOfType);
}

// 运行结果
当前运行环境Windows 10
{windows=Person{name='windows', age=50}}

五、使用@Import给容器中快速导入一个组件

1、@Import导入组件

(1)新增类

public class Color {
}

public class Red {
}

(2)在配置类上添加注解

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

(3)测试方法测试一下

@Test
public void test04(){
    // 获取IOC容器
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    String[] definitionNames = applicationContext.getBeanDefinitionNames();
    for (String name : definitionNames) {
        System.out.println(name);
    }
}

// 运行结果
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig2
com.xiang.spring.bean.Color
com.xiang.spring.bean.Red

2、使用ImportSelector来导入bean

(1)定义bean类

public class Blue {
}

public class Yellow {
}

(2)编写selector

package com.xiang.spring.condition;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

/**
* 自定义返回逻辑需要导入的组件
*/
public class MyImportSelector implements ImportSelector {
    /**
     * 返回值就是导入到容器中的组件全类名
     * AnnotationMetadata:当前标注@Import的类的所有注解信息
     */
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 方法不要返回null值
        return new String[]{"com.xiang.spring.bean.Blue", "com.xiang.spring.bean.Yellow"};
    }
}

(3)配置类添加

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

(4)运行一下看结果

@Test
public void test04(){
    // 获取IOC容器
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    String[] definitionNames = applicationContext.getBeanDefinitionNames();
    for (String name : definitionNames) {
        System.out.println(name);
    }
}

//执行结果
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig2
com.xiang.spring.bean.Color
com.xiang.spring.bean.Red
com.xiang.spring.bean.Blue
com.xiang.spring.bean.Yellow

3、使用ImportBeanDefinitionRegistrar来导入bean

(1)编写bean类

public class RainBow {
}

(2)注册类

package com.xiang.spring.condition;

import com.xiang.spring.bean.RainBow;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * AnnotationMetadata:当前类注解信息
     * BeanDefinitionRegistry:BeanDefinition注册类
     *  把所有需要添加到容器中的bean,调用BeanDefinitionRegistry.registerBeanDefinition手工注册
     */
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean red = registry.containsBeanDefinition("com.xiang.spring.bean.Red");
        boolean blue = registry.containsBeanDefinition("com.xiang.spring.bean.Blue");
        if(red && blue) {
            // 指定bean的定义信息
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RainBow.class);
            // 指定bean名,注册一个bean
            registry.registerBeanDefinition("rainBow", rootBeanDefinition);
        }
    }
}

(3)配置类

@Configuration
@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig2 {

(4)编写测试方法看结果

@Test
public void test04(){
    // 获取IOC容器
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    String[] definitionNames = applicationContext.getBeanDefinitionNames();
    for (String name : definitionNames) {
        System.out.println(name);
    }
}

// 运行结果
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig2
com.xiang.spring.bean.Color
com.xiang.spring.bean.Red
com.xiang.spring.bean.Blue
com.xiang.spring.bean.Yellow
rainBow

六、使用FactoryBean创建bean

1、使用FactoryBean创建bean

(1)定义FactoryBean

package com.xiang.spring.bean;

import org.springframework.beans.factory.FactoryBean;

/**
* 创建一个spring定义的工厂bean
*/
public class ColorFactoryBean implements FactoryBean<Color> {

    /**
     * 返回一个Color对象,这个对象会添加到容器中
     * 假如说不是单例,每次获取bean都会调用getObject方法
     */
    public Color getObject() throws Exception {
        return new Color();
    }

    public Class<?> getObjectType() {
        return Color.class;
    }

    /**
     * 控制是否是单例的
     * true:单例,在容器中保存一份
     * false:不是单例,每次获取都会创建新实例
     */
    public boolean isSingleton() {
        return false;
    }
}

(2)配置类添加FactoryBean

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

(3)测试类查看输出结果

@Test
public void test04(){
    // 获取IOC容器
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    String[] definitionNames = applicationContext.getBeanDefinitionNames();
    for (String name : definitionNames) {
        System.out.println(name);
    }
    // 默认获取到的是工厂bean调用getObject创建的对象
    Object colorFactoryBean = applicationContext.getBean("colorFactoryBean");
    System.out.println("colorFactoryBean的类型:" + colorFactoryBean.getClass());
    // 要获取工厂bean本身,我们需要给id前面加一个&符号:&colorFactoryBean
    Object colorFactoryBean2 = applicationContext.getBean("&colorFactoryBean");
    System.out.println("colorFactoryBean2的类型:" + colorFactoryBean2.getClass());
}

// 输出结果
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig2
colorFactoryBean
colorFactoryBean的类型:class com.xiang.spring.bean.Color
colorFactoryBean2的类型:class com.xiang.spring.bean.ColorFactoryBean

七、bean组件注册小结

给容器中注册组件

(1)、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)

(2)、@Bean[导入第三方包里面的组件]

(3)、@Import[快速给容器中导入一个组件]

     ① @Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名。

     ② ImportSelector:返回需要导入的组件的全类名数组

     ③ ImportBeanDefinitionRegistrar:手动注册bean到容器中

(4)、使用Spring提供的FactoryBean(工厂Bean)

     ① 默认获取到的是工厂bean调用getObject创建的对象

     ② 要获取工厂bean本身,我们需要给id前面加一个&符号:&colorFactoryBean

这篇关于spring系列-注解驱动原理及源码-bean组件注册的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!