FactoryBean

FactoryBean

FactoryBean是一个工厂bean

public interface FactoryBean<T> {

	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
	/**
	当我们在依赖注入的时候,spring会根据beanName向容器中查找当前beanName对应的bean
	若发找到的这个bean是工厂bean,那么就会调用getObject()方法,也就会说我们依赖注入的这个bean其实就是
	注入的getObject()方法的返回值对象,其实mybatis整合spring就是这么搞的
	**/
	@Nullable
	T getObject() throws Exception;
	@Nullable
	Class<?> getObjectType();
	default boolean isSingleton() {
		return true;
	}

}

废话不多说直接上案例(本案例是模仿mybatis整合spring)

准备2个mapper接口

public interface OrderMapper {

    public String orderHandler();
}
public interface UserMappper {

    public String userHandler();
}

因为要代理mapper接口,所以就需要一个代理类


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MapperProxy<T> implements InvocationHandler {
    private Class<T> mapperClass;

    public MapperProxy(Class<T> mapperClass) {
        this.mapperClass = mapperClass;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(mapperClass.getName());
        return mapperClass.getName();
    }
}

spring是无法注册一个接口到容器中的

那我们该怎么办呢?也是借鉴mybatis整合spring的源码使用FactoryBean来解决这个问题。
spring无法注册接口这是事实,但是mybatis在执行数据库操作的时候又依赖mapper接口。
因此就有了中间的一层MapperFactoryBean,每一个mapper接口都对应一个MapperFactoryBean对象,MapperFactoryBean中聚合了mapperInterface属性,只需要把MapperFactoryBean注册到spring就行了

/**
 * MapperFactoryBean实现FactoryBean接口
 * spring不注册接口到容器中,而是每个mapper接口都对应一个MapperFactoryBean对象
 * 只需要把MapperFactoryBean注册到容器中即可,
 * 因为MapperFactoryBean通过mapperInterface和mapper接口进行建立连接的
 */
public class MapperFactoryBean<T> implements FactoryBean<T> {

    /**
     * mapper接口的大Class
     */
    private Class<T> mapperInterface;

    /**
    有参构造器,指定在创建bean的时候,要调用这个构造器
    **/
    public MapperFactoryBean(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    /**
     * 重写getObject方法,返回Mapper接口的代理对象
     */
    @Override
    public T getObject(){
        return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(),new Class[]{mapperInterface},new MapperProxy<T>(mapperInterface));
    }

    @Override
    public Class<T> getObjectType() {
        return this.mapperInterface;
    }
}

怎么把MapperFactoryBean注册到spring容器中呢?

看看上面的MapperFactoryBean类,是没有@Componet元注解的,此处也是模拟mybatis整合spring的方法进行注册,只不过我这里是硬编码写出来的,mybatis是自己实现了一个ClassPathMapperScanner资源加载器
通过MapperScannerConfigurer完成MapperFactoryBean的注册

/**
 * 实现BeanDefinitionRegistryPostProcessor接口,那么该类就有注册beanDefinitioin的能力了
 */
@Component
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        /**
         * 创建orderBeanDefinition对象,并设置beanClass
         */
        AbstractBeanDefinition orderBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(MapperFactoryBean.class).getBeanDefinition();
        //指定创建MapperFactoryBean对应bean的时候要调用的构造方法,可以看出这里指定的是一个Class类型的构造方法
        ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
        constructorArgumentValues.addGenericArgumentValue(OrderMapper.class);
        orderBeanDefinition.setConstructorArgumentValues(constructorArgumentValues);
        /**
         * 创建UserMappper
         */
        AbstractBeanDefinition userBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(MapperFactoryBean.class).getBeanDefinition();
        ConstructorArgumentValues constructorArgumentValues2 = new ConstructorArgumentValues();
        constructorArgumentValues2.addGenericArgumentValue(UserMappper.class);
        userBeanDefinition.setConstructorArgumentValues(constructorArgumentValues2);
        /**
         * 执行这2个beanDefinition的注册
         * uncapitalize():是把首字母小写
         */
        beanDefinitionRegistry.registerBeanDefinition(WordUtils.uncapitalize(OrderMapper.class.getSimpleName()),orderBeanDefinition);
        beanDefinitionRegistry.registerBeanDefinition(WordUtils.uncapitalize(UserMappper.class.getSimpleName()),userBeanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}

编写一个调用者进行测试

@Service
public class FactoryBeanService {
     
 /**
  1:依赖注入:重点看beanName---->orderMapper
  2:其实orderMapper在容器中对应的bean对象是MapperFactoryBean对象,spring先得到MapperFactoryBean对象
  3:奈何MapperFactoryBean是beanFactory工厂,所以spring在对bean工厂处理依赖注入的时候,会调用
     getObject()方法,因此这里的@Autowired注入的实际上是getObject()方法返回的值
     而getObject()方法返回的正是mapperInterface接口的代理对象,所以这里注入的就是mapper接口的代理对象
  4:当代理对象调用其方法的时候,就会执行MapperProxy类中的invok方法
 **/
    @Autowired
    OrderMapper orderMapper;

    @Autowired
    UserMappper userMappper;

    public String orderMapperHandler(){
        return orderMapper.orderHandler();
    }
    public String userMappperHandler(){
        return userMappper.userHandler();
    }
}
@RestController
@RequestMapping(value = "/BeanFactoryPostProcessor")
@ApiSort(3)
@Api(tags = {"FactoryBean"})
public class FactoryBeanController {

    @Autowired
    FactoryBeanService FactoryBeanService;


    @ApiOperation("测试OrderMapper")
    @GetMapping(value = "/orderMapperHandler")
    public String orderMapperHandler(){
        return FactoryBeanService.orderMapperHandler();
    }
    @ApiOperation("测试UserMappper")
    @GetMapping(value = "/userMappperHandler")
    public String userMappperHandler(){
        return FactoryBeanService.userMappperHandler();
    }
}

在这里插入图片描述
在这里插入图片描述

上面的案例是有难度的,下面来个简单的吧

/**
 * User类
 */
public class User {
    public void userT(){
        System.out.println(":userT");
    }
}

@Component
public class FactoryBeanUser implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new User();
    }

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

    @Autowired
    User user;
    
    @ApiOperation("测试user")
    @GetMapping(value = "/user")
    public void user(){
        user.userT();
    }

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值