Spring 组件注册

逆流者 2021年04月10日 127次浏览

新建 maven 项目,引入spring 依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.5</version>
</dependency>
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>RELEASE</version>
    <scope>test</scope>
</dependency>

@Bean

配置类:

package top.wushanghui.annotation.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import top.wushanghui.annotation.entity.Person;

/**
 * @author jue
 * @date 2021/4/9 21:54
 * @describe
 */
@Configuration
public class ComponentRegistrationConfig {

    @Bean
    public Person getPerson() {
        return new Person("Jerry", 5);
    }

}

测试类:

package top.wushanghui.annotation;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import top.wushanghui.annotation.config.ComponentRegistrationConfig;
import top.wushanghui.annotation.entity.Person;

/**
 * @author jue
 * @date 2021/4/9 21:51
 * @describe
 */
public class ComponentRegistrationTest {

    private final ApplicationContext context = new AnnotationConfigApplicationContext(ComponentRegistrationConfig.class);


    @Test
    public void testBeanAnnotation() {
        Person person = context.getBean(Person.class);
        System.out.println(person);
        String[] beanNamesForType = context.getBeanNamesForType(Person.class);
        for (String s : beanNamesForType) {
            System.out.println(s);
        }
        System.out.println("================================漂亮的分隔符================================");
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }
}
Person{name='Jerry', age=5}
getPerson
================================漂亮的分隔符================================
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentRegistrationConfig
getPerson

从测试结果可以看出:

  • 容器中的Person对象bean名称是getPerson,是配置类中的方法名。
  • 分隔符后面是打印的Spring IOC 容器的对象,配置类componentRegistrationConfig 和 getPerson 都在容器中

看下Bean注解:

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
    @AliasFor("name")
    String[] value() default {};

    @AliasFor("value")
    String[] name() default {};

    /** @deprecated */
    @Deprecated
    Autowire autowire() default Autowire.NO;

    boolean autowireCandidate() default true;

    String initMethod() default "";

    String destroyMethod() default "(inferred)";
}

可以指定名称:

@Bean(name = "person1")
public Person getPerson() {
    return new Person("Jerry", 5);
}

再测试一下:

Person{name='Jerry', age=5}
person1
================================漂亮的分隔符================================
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentRegistrationConfig
person1

@ComponentScan注解

配置类,使用ComponentScan 来扫描 包top.wushanghui.annotation 下面的标注了@Controller、@Service、@Repository、@Component的注解的类。

@ComponentScan("top.wushanghui.annotation")
@Configuration
public class ComponentRegistrationConfig {

在这里插入图片描述

测试一下:

@Test
public void testComponentScanAnnotation() {
    String[] beanDefinitionNames = context.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
        System.out.println(beanDefinitionName);
    }
}
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentRegistrationConfig
bookController
bookDao
bookService
person1

从打印可以看出以上类都在Spring IOC容器中,前五个是Spring 默认的类,都是全类名的,后面的都是我们自己建的类,都不带包名,从名称可以看出来除了我们上面指定的Person bean 名称为person1 其他的这些自己建的类 beanDefinitionName 都是类名首字母小写的。ComponentScan注解把标注了@Controller、@Service、@Repository 的类扫描进了容器中了。

看下ComponentScan注解源码:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

    String resourcePattern() default "**/*.class";

    boolean useDefaultFilters() default true;

    ComponentScan.Filter[] includeFilters() default {};

    ComponentScan.Filter[] excludeFilters() default {};

    boolean lazyInit() default false;

    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public @interface Filter {
        FilterType type() default FilterType.ANNOTATION;

        @AliasFor("classes")
        Class<?>[] value() default {};

        @AliasFor("value")
        Class<?>[] classes() default {};

        String[] pattern() default {};
    }
}

使用 ComponentScan.Filter[] excludeFilters() 根据FilterType 类型 来排除相应的组件注册到容器中,如下面的例子,排除标注Controller注解的类注册到容器中:

@ComponentScan(value = {"top.wushanghui.annotation"}, excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})})
@Configuration
public class ComponentRegistrationConfig {

测试一下:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentRegistrationConfig
bookDao
bookService
person1

发现 bookController 并不在容器中。

当然也可以配置 ComponentScan.Filter[] includeFilters() default {}; 来指定容器中注册哪些类,但是需要useDefaultFilters = false,因为Spring 默认 boolean useDefaultFilters() default true; 全部注册的。

@ComponentScan(value = {"top.wushanghui.annotation"}, useDefaultFilters = false, includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})})
@Configuration
public class ComponentRegistrationConfig {

可以看到我们注册扫描的类 只有bookController

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentRegistrationConfig
bookController
person1

看一下Spring中给我们提供了哪些过滤规则:

public enum FilterType {

	/**
	 * 过滤标记有给定注解的对象。
	 */
	ANNOTATION,

	/**
	 * 筛选可分配给给定类型的候选。
	 */
	ASSIGNABLE_TYPE,

	/**
	 * 筛选与给定的AspectJ类型模式表达式匹配的候选对象。
	 * @see org.springframework.core.type.filter.AspectJTypeFilter
	 */
	ASPECTJ,

	/**
	 * 筛选与给定正则表达式模式匹配的候选对象。
	 * @see org.springframework.core.type.filter.RegexPatternTypeFilter
	 */
	REGEX,

	/** 使用给定的自定义过滤候选人
	 * {@link org.springframework.core.type.filter.TypeFilter} implementation.
	 */
	CUSTOM

}

下面我们再试一下FilterType.CUSTOM 自定义的方式:

实现 TypeFilter 接口

比如只把包括service 的类名的组件注册道容器中

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();
        System.out.println("--->" + className);
        return className.contains("service");
    }
}
@ComponentScan(value = {"top.wushanghui.annotation"}, useDefaultFilters = false, includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})})
@Configuration
public class ComponentRegistrationConfig {
--->top.wushanghui.annotation.ComponentRegistrationTest
--->top.wushanghui.annotation.controller.BookController
--->top.wushanghui.annotation.dao.BookDao
--->top.wushanghui.annotation.entity.Person
--->top.wushanghui.annotation.fiter.MyTypeFilter
--->top.wushanghui.annotation.service.BookService
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentRegistrationConfig
bookService
person1

看结果只有ComponentScan 扫描的组件 bookService 注册到容器中了。

我们还看到ComponentScan 注解源码中还标注了 @Repeatable(ComponentScans.class),在ComponentScans 注解中可以重复标注ComponentScans注解:

@ComponentScans(value = {
        @ComponentScan(value = {"top.wushanghui.annotation"}, useDefaultFilters = false, includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})}),
        @ComponentScan(value = {"top.wushanghui.annotation"}, useDefaultFilters = false, includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Service.class})})
    }
)
@Configuration
public class ComponentRegistrationConfig {

看上面的配置,把扫描到的Controller和Service注解标注的组件注册到容器中,

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentRegistrationConfig
bookController
bookService
person1

@Scope

@Scope bean作用域:

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

Scope 注解的源码:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {

	/**
	 * Alias for {@link #scopeName}.
	 * @see #scopeName
	 */
	@AliasFor("scopeName")
	String value() default "";

	/**
	 * 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 "";

	/**
	 * Specifies whether a component should be configured as a scoped proxy
	 * and if so, whether the proxy should be interface-based or subclass-based.
	 * <p>Defaults to {@link ScopedProxyMode#DEFAULT}, which typically indicates
	 * that no scoped proxy should be created unless a different default
	 * has been configured at the component-scan instruction level.
	 * <p>Analogous to {@code <aop:scoped-proxy/>} support in Spring XML.
	 * @see ScopedProxyMode
	 */
	ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;

}

大家都知道spring 容器中的对象默认都是单例的,我们看下容器中Bean什么时候创建的:

public Person(String name, Integer age) {
    this.name = name;
    this.age = age;
    System.out.println("Person 对象 构造器初始化");
}

在Person类中打印一下

直接测试:

private final ApplicationContext context = new AnnotationConfigApplicationContext(ComponentRegistrationConfig.class);
@Test
public void testScopeAnnotation() {
    System.out.println("ioc容器创建完成....");
}
Person 对象 构造器初始化
ioc容器创建完成....

发现 Person 在ioc容器创建完成之前就被初始化了,那继续测试一下这个Person是不是单例的呢?

// 配置类中的
@Bean(name = "person1")
public Person getPerson() {
    return new Person("Jerry", 5);
}
// 测试
@Test
public void testScopeAnnotation() {
    System.out.println("ioc容器创建完成....");
    Object bean1 = context.getBean("person1");
    Object bean2 = context.getBean("person1");
    System.out.println(bean1 == bean2);
}
Person 对象 构造器初始化
ioc容器创建完成....
true

使用多实例:

加上多实例

@Scope("prototype")
@Bean(name = "person1")
public Person getPerson() {
    return new Person("Jerry", 5);
}

继续执行testScopeAnnotation 方法测试:

ioc容器创建完成....
Person 对象 构造器初始化
Person 对象 构造器初始化
false

这是我们就发现 :

  • ioc容器创建完成之前并没有初始化Person对象,当我们 context.getBean("person1"); `获取的时候才初始化的;
  • 每次获取的都是不同的bean。

@Lazy

懒加载:

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

未标注懒加载注解,单实例bean:

@Bean(name = "person1")
public Person getPerson() {
    System.out.println("给容器中添加Person....");
    return new Person("Jerry", 5);
}

测试:

@Test
public void testScopeAnnotation() {
    System.out.println("ioc容器创建完成....");
    Object bean1 = context.getBean("person1");
    Object bean2 = context.getBean("person1");
    System.out.println(bean1 == bean2);
}

结果:

给容器中添加Person....
Person 对象 构造器初始化
ioc容器创建完成....
true

标注懒加载注解:

@Lazy
@Bean(name = "person1")
public Person getPerson() {
    System.out.println("给容器中添加Person....");
    return new Person("Jerry", 5);
}

继续执行上面测试:

ioc容器创建完成....
给容器中添加Person....
Person 对象 构造器初始化
true

@Conditional

按照条件注册bean

先定义两个 Condition 的实现类

public class LinuxCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        assert property != null;
        return property.toLowerCase().contains("linux");
    }
}
public class WindowsCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        assert property != null;
        return property.toLowerCase().contains("windows");
    }
}

接口:

public interface ShowCommand {

    /**
     * 显示cmd 命令
     */
    String showCommandInfo();
}

实现类

public class WindowsShowCommand implements ShowCommand {

    @Override
    public String showCommandInfo() {
        return "dir";
    }
}
public class LinuxShowCommand implements ShowCommand {

    @Override
    public String showCommandInfo() {
        return "ls";
    }
}

在配置类中注入bean:

@Bean("showCmd")
@Conditional(WindowsCondition.class)
public ShowCommand winCmd() {
    return new WindowsShowCommand();
}

@Bean("showCmd")
@Conditional(LinuxCondition.class)
public ShowCommand linuxCmd() {
    return new LinuxShowCommand();
}

上面两个类,根据Conditional中指定的Condition 的条件,只会有一个类能注册到容器中。

测试一下:

@Test
public voidtestConditionalAnnotation() {
    Environment environment = context.getEnvironment();
    String osName = environment.getProperty("os.name");
    System.out.println(osName);
    ShowCommand showCmd = (ShowCommand) context.getBean("showCmd");
    System.out.println(showCmd.getClass());
    System.out.println(showCmd.showCommandInfo());
}
Windows 10
class top.wushanghui.annotation.service.impl.WindowsShowCommand
dir

@Import

  • @Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
  • ImportSelector:返回需要导入的组件的全类名数组;
  • ImportBeanDefinitionRegistrar:手动注册bean到容器中

直接导入类

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

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

}

看源码可知:value class数组中可以导入 类 或者 ImportSelector 选择器选择的类 再或者 ImportBeanDefinitionRegistrar 注册的类到容器中。

下面就一步一步来演示:

创建实体类

public class Cat {
}
public class Dog{
}

使用Import 注解直接导入:

@Import({Dog.class})
public class ComponentRegistrationConfig {

测试:

@Test
public void testImportAnnotation() {
    String[] beanDefinitionNames = context.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
        System.out.println(beanDefinitionName);
    }
}
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentRegistrationConfig
bookController
bookService
top.wushanghui.annotation.entity.Dog
person1
showCmd

看到 top.wushanghui.annotation.entity.Dog 在容器中了。

ImportSelector

导入选择器中选择导入Cat类

public class MyImportSelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 千万不能返回空值
        return new String[]{"top.wushanghui.annotation.entity.Cat"};
    }

    @Override
    public Predicate<String> getExclusionFilter() {
        return null;
    }
}

MyImportSelector 选择器加到Import注解上:

@Import({Dog.class, MyImportSelector.class})
public class ComponentRegistrationConfig {

直接测试:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentRegistrationConfig
bookController
bookService
top.wushanghui.annotation.entity.Dog
top.wushanghui.annotation.entity.Cat
person1
showCmd

top.wushanghui.annotation.entity.Cat 也在容器中了。

ImportBeanDefinitionRegistrar

新建一个动物类:

public class Animal {
}

ImportBeanDefinitionRegistrar 的实现类:

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {


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

        boolean definition1 = registry.containsBeanDefinition("top.wushanghui.annotation.entity.Cat");
        boolean definition2 = registry.containsBeanDefinition("top.wushanghui.annotation.entity.Dog");
        if(definition1 && definition2){
            //指定Bean定义信息;(Bean的类型,Bean。。。)
            RootBeanDefinition beanDefinition = new RootBeanDefinition(Animal.class);
            //注册一个Bean,指定bean名
            registry.registerBeanDefinition("animal", beanDefinition);
        }
    }
}

在 registerBeanDefinitions 方法中,如果Cat和Dog 都在容器中的话,我们把animal 注册到容器中。

把 MyImportBeanDefinitionRegistrar 添加到Import 注解中

@Import({Dog.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class ComponentRegistrationConfig {

直接测试:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentRegistrationConfig
bookController
bookService
top.wushanghui.annotation.entity.Dog
top.wushanghui.annotation.entity.Cat
person1
showCmd
animal

animal 已经在容器中了。

用FactoryBean注册组件

public class Color {
}

实现 FactoryBean

public class ColorFactoryBean implements FactoryBean<Color> {

    /**
     * 回一个Color对象,这个对象会添加到容器中
     */
    @Override
    public Color getObject() throws Exception {
        System.out.println("ColorFactoryBean...create object and return obj...");
        return new Color();
    }

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

    // 如果不重写,默认是true,单实例的
    //true:这个bean是单实例,在容器中保存一份
    //false:多实例,每次获取都会创建一个新的bean;
    @Override
    public boolean isSingleton() {
        return false;
    }
}

配置类中添加:

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

测试:

@Test
public void testFactoryBean() {
    String[] beanDefinitionNames = context.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
        System.out.println(beanDefinitionName);
    }
    System.out.println("================================漂亮的分隔符================================");
    Object bean1 = context.getBean("colorFactoryBean");
    Object bean2 = context.getBean("colorFactoryBean");
    Object bean3 = context.getBean("&colorFactoryBean");
    Object bean4 = context.getBean("&colorFactoryBean");
    System.out.println("bean1.getClass(): " + bean1.getClass());
    System.out.println("bean2.getClass(): " + bean2.getClass());
    System.out.println("bean3.getClass(): " + bean3.getClass());
    System.out.println("bean4.getClass(): " + bean4.getClass());
    System.out.println("color 是否是单例的:"+bean1 == bean2);
    System.out.println("FactoryBean 是否是单例的:"+bean3 == bean4);
}

结果:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentRegistrationConfig
bookController
bookService
top.wushanghui.annotation.entity.Dog
top.wushanghui.annotation.entity.Cat
person1
showCmd
colorFactoryBean
animal
================================漂亮的分隔符================================
ColorFactoryBean...create object and return obj...
ColorFactoryBean...create object and return obj...
bean1.getClass(): class top.wushanghui.annotation.entity.Color
bean2.getClass(): class top.wushanghui.annotation.entity.Color
bean3.getClass(): class top.wushanghui.annotation.entity.ColorFactoryBean
bean4.getClass(): class top.wushanghui.annotation.entity.ColorFactoryBean
false
false

从执行结果来看,容器中有我们放入的colorFactoryBean ,但是它的类型却是Color,而不是我们配置到配置类中的ColorFactoryBean。
如果要从容器中工厂bean,名称前加“&”,像这种 context.getBean("&colorFactoryBean")。