FactoryBean探究

HeJin大约 2 分钟源码解析bean的注入

应用场景

一些对象的创建比较复杂,这时候就可以使用FactoryBean,Spring容器在创建Bean的时候调用FactoryBean实现创建。尤其是一些动态代理对象的创建。

基本使用

实现FactoryBean接口:

public class SimpleFactoryBean implements FactoryBean<Dog> {
    @Override
    public Dog getObject() throws Exception {
        return new Dog("大黄", 3);
    }

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

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

由于这个类没有在主启动类所在的包下,不能被默认扫描(也可以放到默认扫描的包下,使用注解把类交给Spring管理)。我们在配置类中使用@Bean注入bean。

@SpringBootApplication
public class SpringBootAnalysisApp {
    private static final Logger logger = LoggerFactory.getLogger(SpringBootAnalysisApp.class);

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringBootAnalysisApp.class, args);
        Dog dog = applicationContext.getBean(Dog.class);
        logger.info("dog: {}", dog);
    }

    @Bean
    public SimpleFactoryBean simpleFactoryBean(){
        return new SimpleFactoryBean();
    }
}

可以看到Dog对象的确被注入到Spring容器了。

com.sanfen.SpringBootAnalysisApp         : dog: Dog{name='大黄', age=3}

进阶使用

创建FactoryBean,可以生成任意接口的动态代理对象。其实就是对mybatis的简单模拟实现。

  • 指定接口。
  • 通过动态代理创建对象返回。
  • getObjectType()返回接口的字节码对象。

实现FactoryBean接口:

public class MyMapperFactoryBean implements FactoryBean {
    Logger logger = LoggerFactory.getLogger(MyMapperFactoryBean.class);

    private final Class clazz;

    public MyMapperFactoryBean(Class clazz) {
        this.clazz = clazz;
    }

    @Override
    public Object getObject() throws Exception {
        return Proxy.newProxyInstance(MyMapperFactoryBean.class.getClassLoader(),
                new Class[]{clazz}, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if("select".equals(method.getName())){
                            logger.info("[{}]的动态代理对象的select被执行了", clazz.getName());
                        }
                        if("update".equals(method.getName())){
                            logger.info("[{}]的动态代理对象的update被执行了", clazz.getName());
                        }
                        return null;
                    }
                }
        );
    }

    @Override
    public Class<?> getObjectType() {
        return clazz;
    }

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

FactoryBean实现类注入Spring容器中,并传入一个mapper接口:

@SpringBootApplication
public class SpringBootAnalysisApp {
    private static final Logger logger = LoggerFactory.getLogger(SpringBootAnalysisApp.class);

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringBootAnalysisApp.class, args);
        UserMapper userMapper = applicationContext.getBean(UserMapper.class);
        userMapper.select();
    }

    @Bean
    MyMapperFactoryBean myMapperFactoryBean(){
        return new MyMapperFactoryBean(UserMapper.class);
    }
}

结果:

com.registrar.MyMapperFactoryBean        : [com.registrar.UserMapper]的动态代理对象的select被执行了