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();
}