阅读此篇建议在阅读springioc之后的基础上阅读,后期会将ioc过程笔记整理在csdn上
MyBatis mapper接口如何被实例化为对象?
通过动态道理的方式:
通过MapperProxy 代理生成了代理对象mapper
public class MapperProxy implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private SqlSession sqlSession;
private <T> MapperProxy(SqlSession sqlSession) {
this.sqlSession = sqlSession;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
final Class<?> declaringInterface = findDeclaringInterface(proxy, method);
final MapperMethod mapperMethod = new MapperMethod(declaringInterface, method, sqlSession);
final Object result = mapperMethod.execute(args);
if (result == null && method.getReturnType().isPrimitive() && !method.getReturnType().equals(Void.TYPE)) {
throw new BindingException("Mapper method '" + method.getName() + "' (" + method.getDeclaringClass() + ") attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
private Class<?> findDeclaringInterface(Object proxy, Method method) {
Class<?> declaringInterface = null;
for (Class<?> iface : proxy.getClass().getInterfaces()) {
try {
Method m = iface.getMethod(method.getName(), method.getParameterTypes());
if (declaringInterface != null) {
throw new BindingException("Ambiguous method mapping. Two mapper interfaces contain the identical method signature for " + method);
} else if (m != null) {
declaringInterface = iface;
}
} catch (Exception e) {
// Intentionally ignore.
// This is using exceptions for flow control,
// but it's definitely faster.
}
}
if (declaringInterface == null) {
throw new BindingException("Could not find interface with the given method " + method);
}
return declaringInterface;
}
@SuppressWarnings("unchecked")
public static <T> T newMapperProxy(Class<T> mapperInterface, SqlSession sqlSession) {
ClassLoader classLoader = mapperInterface.getClassLoader();
Class<?>[] interfaces = new Class[]{mapperInterface};
MapperProxy proxy = new MapperProxy(sqlSession);
return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);
}
}
MapperRegistry 实现了对mapper的管理
public class MapperRegistry {
private Configuration config;
private Set<Class<?>> knownMappers = new HashSet<Class<?>>();
public MapperRegistry(Configuration config) {
this.config = config;
}
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
if (!knownMappers.contains(type))
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
try {
return MapperProxy.newMapperProxy(type, sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
public boolean hasMapper(Class<?> type) {
return knownMappers.contains(type);
}
public void addMapper(Class<?> type) {
if (type.isInterface()) {
if (knownMappers.contains(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
knownMappers.add(type);
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the
// mapper parser. If the type is already known, it won't try.
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
}
第三方对象如何注入到Spring中?
1.@Bean @Component
2.beanFactory.registerSingleton("tDao",tDao);
3.FactoryBean
@Bean @Component
@Bean和@Component有什么不同呢?
@Bean 注解告诉spring这个方法要返回一个对象,这个对象要注册到spring的上下文
@Component 告诉spring要为这个类创建Bean
这里Mybatis 是不能用这个方法的 因为 mapper接口通过动态代理实例化的,这里注释不能加载源码上;
beanFactory.registerSingleton(“tDao”,tDao);
这个方法倒是可行的,但是写在代码中的话当运行到这一行代码,Spring IOC已经初始化完成;
FactoryBean
Mybatis用的就是这一种:
FactoryBean与BeanFactory区别?
*有没有想起 IOC过程中有一步是判断是否为FactoryBean*
BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似
BeanFactory和ApplicationContext就是spring框架的两个IOC容器,现在一般使用ApplicationnContext,其不但包含了BeanFactory的作用,同时还进行更多的扩展。
Mybatis就是通过FactoryBean注入的!
先看下BeanFactory接口
public interface FactoryBean<T> {
/
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
MapperFactoryBean 实现了FactoryBean 返回 代理对象 mapperInterface
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
private Class<T> mapperInterface;
private boolean addToConfig = true;
public void setMapperInterface(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public void setAddToConfig(boolean addToConfig) {
this.addToConfig = addToConfig;
}
/**
* {@inheritDoc}
*/
@Override
protected void checkDaoConfig() {
super.checkDaoConfig();
notNull(this.mapperInterface, "Property 'mapperInterface' is required");
Configuration configuration = getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
configuration.addMapper(this.mapperInterface);
} catch (Throwable t) {
logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", t);
throw new IllegalArgumentException(t);
} finally {
ErrorContext.instance().reset();
}
}
}
/**
* {@inheritDoc}
*/
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
/**
* {@inheritDoc}
*/
public Class<T> getObjectType() {
return this.mapperInterface;
}
/**
* {@inheritDoc}
*/
public boolean isSingleton() {
return true;
}
}
在IOC实例化的方法
instanceWrapper = createBeanInstance(beanName, mbd, args);中instantiateUsingFactoryMethod方法
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
省略
//判断是否通过工厂创建FactoryMethodName
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
省略
return instantiateBean(beanName, mbd);
}
如有通过工厂方法创建的挂进入这个方法
public BeanWrapper instantiateUsingFactoryMethod(
final String beanName, final RootBeanDefinition mbd, final Object[] explicitArgs) {
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
Object factoryBean;
Class<?> factoryClass;
boolean isStatic;
String factoryBeanName = mbd.getFactoryBeanName();
if (factoryBeanName != null) {
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
// 根据factoryBeanName获取factoryBean对象。 这里的factoryBean获取到的就是上面的MapperFactoryBean
factoryBean = this.beanFactory.getBean(factoryBeanName);
if (factoryBean == null) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"factory-bean '" + factoryBeanName + "' returned null");
}
factoryClass = factoryBean.getClass();
isStatic = false;
}else{
省略。。。
}
至此就完成了mapper的实例化