Spring的@Import组件可以为Spring导入组件。常用的@EnableXXX,一般底层都会带有@Import注解。
@Import注解加在配置类上时,在配置类解析的时候就会为容器注册导入的类。
详见ConfigurationClassParser类的processImports方法
FactoryBean是一个工厂Bean,可以生成某一个类型Bean实例,它最大的一个作用是:可以让我们自定义Bean的创建过程。(Mapper接口的实现类的动态代理就是通过FactoryBean的getObject为Mapper创建了一个实例化的类),下面看一个简单伪代码实现:
@Component("temp")
public class TempFactoryBean implements FactoryBean {
private Class<T> mapperInterface;
@Override
public Object getObject () throws Exception {
//可以在此处自定义类的生成过程
//伪代码实现
return Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
@Override
public Class<?> getObjectType () {
return Test.class;
}
}
此处Spring容器在获取temp的时候,会调用到TempFactoryBean的getObject ()方法。
如果要获取FactoryBean本身,则需要在获取的BeanName前加上&符号。
Spring中定义了很多PostProcessor,会在容器注册、实例化Bean中穿插起作用。
此处只关注BeanDefinitionRegistryPostProcessor接口。
BeanDefinitionRegistryPostProcessor接口继承自BeanFactoryPostProcessor。在刷新容器—执行invokeBeanFactoryPostProcessors(beanFactory)方法的时候会回调该接口中的方法。
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
//在标准初始化之后,修改应用程序上下文的内部bean定义注册表。
//所有常规bean定义都将被加载,但尚未实例化任何bean。
//在下一阶段开始处理之前,向容器中注册更多的Bean定义信息。
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
InitializingBean接口有一个方法:afterPropertiesSet()
实现了该接口的类,会在创建对象设置完属性后调用该方法。
另,在Java中描述一个类的类为Class,通过Class我们可以了解这个类有什么属性、方法、构造函数等,也可通过Class去获取这个类。在Spring中描述一个Spring管理的Bean的类叫做BeanDefinition,Spring实例化一个交给Spring管理的Bean都是通过BeanDefinition去实例化的。
下面是一个简单的Mybatis-Spring查询功能的实现案例:
配置类:
@Configuration
@ComponentScan("spring.mybatis")
@MapperScan("spring.mybatis.dao")
public class AppConfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactory (DataSource dataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean;
}
@Bean
public DataSource dataSource () {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
driverManagerDataSource.setUrl("jdbc:mysql://localhost:3306/alen?useSSL=false&serverTimezone=GMT%2B8");
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setPassword("123456");
return driverManagerDataSource;
}
}
Mapper接口
@Mapper
public interface UserMapper {
@Select("Select * from user_table where id=#{userID}")
User find (@Param("userID") String userID);
}
服务类:
@Component
public class UserService {
@Resource
UserMapper userMapper;
public void findUser () {
System.out.println(userMapper.find("1"));
}
}
测试类:
public class Test {
public static void main (String[] args) throws Exception {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService service = applicationContext.getBean(UserService.class);
service.findUser();
}
}
该注解类有以下标识:
@Import(MapperScannerRegistrar.class)
说明容器在解析配置类的时候为我们导入了相关的类:
进入该类:
void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
.....................
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
}
可以看到,为我们注册了一个MapperScannerConfigurer类,并将该类交由Spring去管理,
扫描并注册Mapper。
简单看一下该类(此处只说明重要逻辑方法)
public class MapperScannerConfigurer
implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
此类实现了BeanDefinitionRegistryPostProcessor接口和InitializingBean接口。
@Override
public void afterPropertiesSet() throws Exception {
notNull(this.basePackage, "Property 'basePackage' is required");
}
下面看该类的主要处理逻辑:postProcessBeanDefinitionRegistry方法:
在执行容器刷新时,会调用到MapperScannerConfigurer的postProcessBeanDefinitionRegistry方法
最终调用的为ClassPathMapperScanner的doScan方法
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
//调用父类的doScan方法,将扫描的包类符合条件的类转化为BeanDefinition,此处案例只有一个
//name=userMapper
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages)
+ "' package. Please check your configuration.");
} else {
//此处为处理Mapper的具体逻辑实现
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
进入processBeanDefinitions可以看到
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
//获取beanName 案例此处为spring.mybatis.dao.UserMapper
String beanClassName = definition.getBeanClassName();
LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName
+ "' mapperInterface");
// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
//设置构造函数参数为当前的接口spring.mybatis.dao.UserMapper类
/**
* public MapperFactoryBean(Class mapperInterface) {
* this.mapperInterface = mapperInterface;
* }
*/
definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
//设置BeanClass
definition.setBeanClass(this.mapperFactoryBeanClass);
//设置属性addToConfig
definition.getPropertyValues().add("addToConfig", this.addToConfig);
boolean explicitFactoryUsed = false;
。。。。。。。
if (!explicitFactoryUsed) {
LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
//设置注入模式为BY_TYPE,此处会根据set方法去设置属性
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
definition.setLazyInit(lazyInitialization);
}
}
此处将扫描的UserMapper的BeanDefinition修改,
Proxy中的h为MapperProxy
Spring容器先实例化了MapperFactoryBean,再根据MapperFactoryBean的getSqlSession().getObject()方法获取到代理对象。
MapperFactoryBean在实例化的时候会调用到:
AbStractBeanFactory类:
protected Object getObjectForBeanInstance (Object beanInstance, String name, String beanName,
@Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
//如果BeanName是以&开始,则进入下方法
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
//如果获取到的beanInstance不是FactoryBean类型,则抛出错误
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
}
//如果不是工厂Bean或者名字是以&开头直接返回获取到的beanInstance
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
//尝试从缓存中获取Bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
//这里可以肯定beanInstance为FactoryBean类型
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
//检测beanDefinitionMap是否包含beanName
if (mbd == null && containsBeanDefinition(beanName)) {
//合并父子类定义信息
mbd = getMergedLocalBeanDefinition(beanName);
}
//是否使用户定义而不是程序本身定义的,isSynthetic默认为false
boolean synthetic = (mbd != null && mbd.isSynthetic());
//从FactoryBean中获取Bean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
最终调用到FactoryBeanRegistrySupport的doGetObjectFromFactoryBean()方法:
object = factory.getObject();
*******************
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
实际创建逻辑:
MapperRegistry类的
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
*************
return mapperProxyFactory.newInstance(sqlSession);
*************
}
----->
MapperProxyFactory<T>类的:
public T newInstance(SqlSession sqlSession) {
/**
* MapperProxy实现了InvocationHandler接口,最终代理类调用的方法逻辑就在此类中
*/
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
----->
/**
* JDK动态代理逻辑
*/
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
到此处,一个Mapper的接口代理类就创建完成了。