FactoryBean注册组件

FactoryBean注册组件

前面我们了解了三种注册组件的方式, 现在又有了一种方式: FactoryBean注册组件:
  1. 包扫描 + 组件标注注解
  2. @Bean注解导入
  3. @Import注解导入
  4. FactoryBean注册组件

1. 创建实体类:

package com.ffyc.spring.model;

public class Dog {
}

2. 自定义一个DogFactoryBean, 实现FactoryBean接口

package com.ffyc.spring.model;

import org.springframework.beans.factory.FactoryBean;

public class DogFactoryBean implements FactoryBean<Dog> {
//    public DogFactoryBean() {
//        System.out.println("哈哈哈");
//    }
    
    //返回一个Dog对象, 这个Dog对象会添加到容器中
    public Dog getObject() throws Exception {
        System.out.println("嘿嘿嘿");
        return new Dog();
    }

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

    //控制bean是否为单例
    /*
    1. true : 是单例, 在容器中保存一份
    2. false : 是多实例的, 每次获取都会创建一个实例(就是调用BeanFactory的getObject()方法)
     */
    public boolean isSingleton() {
        return false;
    }
}

FactoryBean接口的泛型就是我们要创建的Bean的类型

3. 创建一个配置类, 配置类中闯将DogFactoryBean实例

package com.ffyc.spring.config;

import com.ffyc.spring.condition.LinuxCondition;
import com.ffyc.spring.condition.MyImportBeanDefinitionRegister;
import com.ffyc.spring.condition.MyImportSelector;
import com.ffyc.spring.condition.WindowsCondition;
import com.ffyc.spring.controller.MyTypeFilter;
import com.ffyc.spring.model.DogFactoryBean;
import com.ffyc.spring.model.Person;
import com.ffyc.spring.model.Red;
import org.springframework.context.annotation.*;

@Configuration
//@ComponentScan(value = "com.ffyc.spring" , excludeFilters = {
//        @ComponentScan.Filter(classes = Controller.class)
//})
//@ComponentScan(value = "com.ffyc.spring", includeFilters = {
//        @ComponentScan.Filter(classes = Controller.class)
//}, useDefaultFilters = false)
@ComponentScan(value = "com.ffyc.spring")
@Import({Red.class, MyImportSelector.class, MyImportBeanDefinitionRegister.class})
public class PersonConfig {
    @Bean
    public DogFactoryBean dogFactoryBean() {
        return new DogFactoryBean();
    }
}

4. 测试:

package com.ffyc.spring.test;

import com.ffyc.spring.config.PersonConfig;
import com.ffyc.spring.model.Dog;
import com.ffyc.spring.model.DogFactoryBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test5 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(PersonConfig.class);
        System.out.println(annotationConfigApplicationContext.getBean(DogFactoryBean.class));
        System.out.println(annotationConfigApplicationContext.getBean(Dog.class));
        System.out.println(annotationConfigApplicationContext.getBean("dogFactoryBean").getClass());
    }
}

我们虽然在配置类中创建的是DogFactoryBean类型的实例, 但是我们从IOC容器中获取名为dogFactoryBean的实例的时候调用getClass()方法可以发现获取到的该实例却是一个Dog类型对象

其实是会创建DogFactoryBean实例到IOC容器中, 但是我们每次使用IOC容器通过getBean()方法获取的时候如果不加前缀&, 那么就在底层会调用getObject()方法返回一个Dog类型实例, 如果是单例, 那么会在第一次调用getObject()方法之后将该单例放到IOC容器中, 然后下次获取的时候直接从IOC容器的单例Map中获取即可

  • 如果你的FactoryBean中的isSingleton方法返回值为false, 那么就是创建多实例bean, 那么每使用IOC容器获取一次实例, 就创建一个Dog实例

5.测试(扩展 : 获取DogFactoryBean实例)

package com.ffyc.spring.test;

import com.ffyc.spring.config.PersonConfig;
import com.ffyc.spring.model.DogFactoryBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test5 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(PersonConfig.class);
        System.out.println(annotationConfigApplicationContext.getBean(DogFactoryBean.class));
        System.out.println(annotationConfigApplicationContext.getBean("&dogFactoryBean").getClass());
    }
}
分为以下情况: DogFactoryBean implements FactoryBean< Dog>:
  1. getBean(“DogFactoryBean id名”) : 获取到的是Dog类型实例
  2. getBean(Dog.class) : 获取到的是Dog类型实例
  3. getBean(“& + DogFactoryBean id名”) : 获取到的是DogFactoryBean类型实例
  4. getBean(DogFactoryBean.class) : 获取到的是DogFactoryBean类型实例
那么在bean id前面加一个&表示什么?
  • 该符号其实是定义在BeanFactory类源码中的:
public interface BeanFactory {

	/**
	 * Used to dereference a {@link FactoryBean} instance and distinguish it from
	 * beans <i>created</i> by the FactoryBean. For example, if the bean named
	 * {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
	 * will return the factory, not the instance returned by the factory.
	 */
	String FACTORY_BEAN_PREFIX = "&";
    ...
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值