赞
踩
mybatis 怎么创建mapper的BeanDefinition
为什么要将BeanDefinition的beanClass设置为MapperFactoryBean
mybatis什么时候创建的代理对象
mybatis怎么创建代理对象
代理对象是怎么实现功能增强(具体怎么调用的)
重点看@Import(MapperScannerRegistrar.class),将MapperScannerRegistrar.class引进来
- @Slf4j
- @org.springframework.boot.autoconfigure.SpringBootApplication
- @MapperScan(basePackages = {"com.springboot.study.mapper"})
- public class SpringBootApplication {
- public static void main(String[] args) {
- SpringApplication.run(SpringBootApplication.class, args);
- }
- }
-
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.TYPE)
- @Documented
- @Import(MapperScannerRegistrar.class)
- @Repeatable(MapperScans.class)
- public @interface MapperScan {
- String[] value() default {};
-
- String[] basePackages() default {};
-
- Class<?>[] basePackageClasses() default {};
-
- Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
-
- Class<? extends Annotation> annotationClass() default Annotation.class;
-
- Class<?> markerInterface() default Class.class;
-
- String sqlSessionTemplateRef() default "";
-
- String sqlSessionFactoryRef() default "";
-
- Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;
-
- String lazyInitialization() default "";
-
- String defaultScope() default AbstractBeanDefinition.SCOPE_DEFAULT;
registerBeanDefinitions()扫描@MapperScan注解上面的属性并且构建MapperScannerConfigurer BeanDefinition
- public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
-
- @Override
- @Deprecated
- public void setResourceLoader(ResourceLoader resourceLoader) {
- // NOP
- }
-
- @Override
- public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
- AnnotationAttributes mapperScanAttrs = AnnotationAttributes
- .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
- if (mapperScanAttrs != null) {
- registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,
- generateBaseBeanName(importingClassMetadata, 0));
- }
- }
-
- void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs,
- BeanDefinitionRegistry registry, String beanName) {
-
- BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
- builder.addPropertyValue("processPropertyPlaceHolders", true);
-
- Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
- if (!Annotation.class.equals(annotationClass)) {
- builder.addPropertyValue("annotationClass", annotationClass);
- }
-
- Class<?> markerInterface = annoAttrs.getClass("markerInterface");
- if (!Class.class.equals(markerInterface)) {
- builder.addPropertyValue("markerInterface", markerInterface);
- }
-
- Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
- if (!BeanNameGenerator.class.equals(generatorClass)) {
- builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));
- }
-
- Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
- if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
- builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
- }
-
- String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");
- if (StringUtils.hasText(sqlSessionTemplateRef)) {
- builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));
- }
-
- String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef");
- if (StringUtils.hasText(sqlSessionFactoryRef)) {
- builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef"));
- }
-
- List<String> basePackages = new ArrayList<>();
- basePackages.addAll(
- Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
-
- basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText)
- .collect(Collectors.toList()));
-
- basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName)
- .collect(Collectors.toList()));
-
- if (basePackages.isEmpty()) {
- basePackages.add(getDefaultBasePackage(annoMeta));
- }
-
- String lazyInitialization = annoAttrs.getString("lazyInitialization");
- if (StringUtils.hasText(lazyInitialization)) {
- builder.addPropertyValue("lazyInitialization", lazyInitialization);
- }
-
- String defaultScope = annoAttrs.getString("defaultScope");
- if (!AbstractBeanDefinition.SCOPE_DEFAULT.equals(defaultScope)) {
- builder.addPropertyValue("defaultScope", defaultScope);
- }
-
- builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));
-
- registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
-
- }
-
- private static String generateBaseBeanName(AnnotationMetadata importingClassMetadata, int index) {
- return importingClassMetadata.getClassName() + "#" + MapperScannerRegistrar.class.getSimpleName() + "#" + index;
- }
-
- private static String getDefaultBasePackage(AnnotationMetadata importingClassMetadata) {
- return ClassUtils.getPackageName(importingClassMetadata.getClassName());
- }
-
- static class RepeatingRegistrar extends MapperScannerRegistrar {
- @Override
- public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
- AnnotationAttributes mapperScansAttrs = AnnotationAttributes
- .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScans.class.getName()));
- if (mapperScansAttrs != null) {
- AnnotationAttributes[] annotations = mapperScansAttrs.getAnnotationArray("value");
- for (int i = 0; i < annotations.length; i++) {
- registerBeanDefinitions(importingClassMetadata, annotations[i], registry,
- generateBaseBeanName(importingClassMetadata, i));
- }
- }
- }
- }
-
- }
我们首先观察一下实现了一些什么接口才知道它想要执行的时机和操作的具体功能
1.InitializingBean.afterPropertiesSet():在属性赋值之后加了一个判断basePackage是否为空的操作
2.ApplicationContextAware只是拿到了ApplicationContext给当前对象里的属性赋值而已
3.重点是BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry:自定义了一个扫描器去扫描接口注册成BeanDefinition
留意一下(ClassPathMapperScanner)scanner.registerFilters();这里将
然后调用spring的扫描scanner.scan()
- public class MapperScannerConfigurer
- implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
-
- private String basePackage;
-
- private boolean addToConfig = true;
-
- private String lazyInitialization;
-
- private SqlSessionFactory sqlSessionFactory;
-
- private SqlSessionTemplate sqlSessionTemplate;
-
- private String sqlSessionFactoryBeanName;
-
- private String sqlSessionTemplateBeanName;
-
- private Class<? extends Annotation> annotationClass;
-
- private Class<?> markerInterface;
-
- private Class<? extends MapperFactoryBean> mapperFactoryBeanClass;
-
- private ApplicationContext applicationContext;
-
- private String beanName;
-
- private boolean processPropertyPlaceHolders;
-
- private BeanNameGenerator nameGenerator;
-
- private String defaultScope;
-
- @Override
- public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
- if (this.processPropertyPlaceHolders) {
- processPropertyPlaceHolders();
- }
-
- ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
- scanner.setAddToConfig(this.addToConfig);
- scanner.setAnnotationClass(this.annotationClass);
- scanner.setMarkerInterface(this.markerInterface);
- scanner.setSqlSessionFactory(this.sqlSessionFactory);
- scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
- scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
- scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
- scanner.setResourceLoader(this.applicationContext);
- scanner.setBeanNameGenerator(this.nameGenerator);
- scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
- if (StringUtils.hasText(lazyInitialization)) {
- scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
- }
- if (StringUtils.hasText(defaultScope)) {
- scanner.setDefaultScope(defaultScope);
- }
- scanner.registerFilters();
- scanner.scan(
- StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
- }
-
- @Override
- public void afterPropertiesSet() throws Exception {
- notNull(this.basePackage, "Property 'basePackage' is required");
- }
- }
1.继承了spring的ClassPathBeanDefinitionScanner扫描器
2.registerFilters()
这里将ClassPathMapperScanner作为TypeFilter添加进includeFilters里面了,目的让扫描出来的Mapper接口能通过ClassPathBeanDefinitionScanner.isCandidateComponent。
3.definition.setBeanClass(this.mapperFactoryBeanClass);
将MapperInterface BeanDefinition的beanClass设置成MapperFactoryBean.class
4.definition.setLazyInit(lazyInitialization);
将MapperInterface BeanDefinition设置为懒加载,调用的时候才将Bean对象实例化
- public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
-
- public void registerFilters() {
- boolean acceptAllInterfaces = true;
-
- // if specified, use the given annotation and / or marker interface
- if (this.annotationClass != null) {
- addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
- acceptAllInterfaces = false;
- }
-
- // override AssignableTypeFilter to ignore matches on the actual marker interface
- if (this.markerInterface != null) {
- addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {
- @Override
- protected boolean matchClassName(String className) {
- return false;
- }
- });
- acceptAllInterfaces = false;
- }
-
- if (acceptAllInterfaces) {
- // default include filter that accepts all classes
- addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
- }
-
- // exclude package-info.java
- addExcludeFilter((metadataReader, metadataReaderFactory) -> {
- String className = metadataReader.getClassMetadata().getClassName();
- return className.endsWith("package-info");
- });
- }
-
- private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
- AbstractBeanDefinition definition;
- BeanDefinitionRegistry registry = getRegistry();
- for (BeanDefinitionHolder holder : beanDefinitions) {
- definition = (AbstractBeanDefinition) holder.getBeanDefinition();
- boolean scopedProxy = false;
- if (ScopedProxyFactoryBean.class.getName().equals(definition.getBeanClassName())) {
- definition = (AbstractBeanDefinition) Optional
- .ofNullable(((RootBeanDefinition) definition).getDecoratedDefinition())
- .map(BeanDefinitionHolder::getBeanDefinition).orElseThrow(() -> new IllegalStateException(
- "The target bean definition of scoped proxy bean not found. Root bean definition[" + holder + "]"));
- scopedProxy = true;
- }
- 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
- definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
- definition.setBeanClass(this.mapperFactoryBeanClass);
-
- definition.getPropertyValues().add("addToConfig", this.addToConfig);
-
- // Attribute for MockitoPostProcessor
- // https://github.com/mybatis/spring-boot-starter/issues/475
- definition.setAttribute(FACTORY_BEAN_OBJECT_TYPE, beanClassName);
-
- boolean explicitFactoryUsed = false;
- if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
- definition.getPropertyValues().add("sqlSessionFactory",
- new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
- explicitFactoryUsed = true;
- } else if (this.sqlSessionFactory != null) {
- definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
- explicitFactoryUsed = true;
- }
-
- if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
- if (explicitFactoryUsed) {
- LOGGER.warn(
- () -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
- }
- definition.getPropertyValues().add("sqlSessionTemplate",
- new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
- explicitFactoryUsed = true;
- } else if (this.sqlSessionTemplate != null) {
- if (explicitFactoryUsed) {
- LOGGER.warn(
- () -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
- }
- definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
- explicitFactoryUsed = true;
- }
-
- if (!explicitFactoryUsed) {
- LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
- definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
- }
-
- definition.setLazyInit(lazyInitialization);
-
- if (scopedProxy) {
- continue;
- }
-
- if (ConfigurableBeanFactory.SCOPE_SINGLETON.equals(definition.getScope()) && defaultScope != null) {
- definition.setScope(defaultScope);
- }
-
- if (!definition.isSingleton()) {
- BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(holder, registry, true);
- if (registry.containsBeanDefinition(proxyHolder.getBeanName())) {
- registry.removeBeanDefinition(proxyHolder.getBeanName());
- }
- registry.registerBeanDefinition(proxyHolder.getBeanName(), proxyHolder.getBeanDefinition());
- }
-
- }
- }
- }
实现了FactoryBean接口,定义了一个专门处理MapperInterface Bean的工厂
2.当使用的时候(我这里用@Autowired注入作为使用例子)会调用MapperFactoryBean的getObject方法
@Autowired
private PeopleMapper peopleMapper;
- public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
- @Override
- public T getObject() throws Exception {
- return getSqlSession().getMapper(this.mapperInterface);
- }
- }
1.先走MybatisMapperRegistry.getMapper,
2.然后做一个强转MybatisMapperProxyFactory<T> mapperProxyFactory = (MybatisMapperProxyFactory<T>) knownMappers.get(type);
3.调用mapperProxyFactory.newInstance(sqlSession);
- public class MybatisMapperRegistry extends MapperRegistry {
- @Override
- public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
- // TODO 这里换成 MybatisMapperProxyFactory 而不是 MapperProxyFactory
- // fix https://github.com/baomidou/mybatis-plus/issues/4247
- MybatisMapperProxyFactory<T> mapperProxyFactory = (MybatisMapperProxyFactory<T>) knownMappers.get(type);
- if (mapperProxyFactory == null) {
- mapperProxyFactory = (MybatisMapperProxyFactory<T>) knownMappers.entrySet().stream()
- .filter(t -> t.getKey().getName().equals(type.getName())).findFirst()
- .orElseThrow(() -> new BindingException("Type " + type + " is not known to the MybatisPlusMapperRegistry."));
- }
- try {
- return mapperProxyFactory.newInstance(sqlSession);
- } catch (Exception e) {
- throw new BindingException("Error getting mapper instance. Cause: " + e, e);
- }
- }
- }
4.在newInstance()里面创建了一个MybatisMapperProxy对象然后调用proxy.newProxyInstance创建代理对象
- public class MybatisMapperProxyFactory<T> {
-
- @Getter
- private final Class<T> mapperInterface;
- @Getter
- private final Map<Method, MybatisMapperProxy.MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
-
- public MybatisMapperProxyFactory(Class<T> mapperInterface) {
- this.mapperInterface = mapperInterface;
- }
-
- @SuppressWarnings("unchecked")
- protected T newInstance(MybatisMapperProxy<T> mapperProxy) {
- return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);
- }
-
- public T newInstance(SqlSession sqlSession) {
- final MybatisMapperProxy<T> mapperProxy = new MybatisMapperProxy<>(sqlSession, mapperInterface, methodCache);
- return newInstance(mapperProxy);
- }
-
- }
Map<Method, MapperMethodInvoker> methodCache属性:用来存mapper的方法,第一次调用会put进去
SqlSession sqlSession:访问数据库
Class<T> mapperInterface:你的mapper接口类型
实现了InvocationHandler接口,职责是处理代理类的执行方法
当调用mapper的方法,invoke->if(你的所属类型是Object类就直接执行实现方法)else(是接口类型,走cachedInvoker)
cachedInvoker:会判断你是否是default方法,true:走DefaultMethodInvoker.invoke,直接传参执行方法,false:走PlainMethodInvoker.invoke,底层是走sqlSession访问数据库获取数据返回
- public class MybatisMapperProxy<T> implements InvocationHandler, Serializable {
-
- private static final long serialVersionUID = -5154982058833204559L;
- private static final int ALLOWED_MODES = MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
- | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC;
- private static final Constructor<MethodHandles.Lookup> lookupConstructor;
- private static final Method privateLookupInMethod;
- private final SqlSession sqlSession;
- private final Class<T> mapperInterface;
- private final Map<Method, MapperMethodInvoker> methodCache;
-
- public MybatisMapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethodInvoker> methodCache) {
- this.sqlSession = sqlSession;
- this.mapperInterface = mapperInterface;
- this.methodCache = methodCache;
- }
-
- static {
- Method privateLookupIn;
- try {
- privateLookupIn = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
- } catch (NoSuchMethodException e) {
- privateLookupIn = null;
- }
- privateLookupInMethod = privateLookupIn;
-
- Constructor<MethodHandles.Lookup> lookup = null;
- if (privateLookupInMethod == null) {
- // JDK 1.8
- try {
- lookup = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
- lookup.setAccessible(true);
- } catch (NoSuchMethodException e) {
- throw new IllegalStateException(
- "There is neither 'privateLookupIn(Class, Lookup)' nor 'Lookup(Class, int)' method in java.lang.invoke.MethodHandles.",
- e);
- } catch (Throwable t) {
- lookup = null;
- }
- }
- lookupConstructor = lookup;
- }
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- try {
- if (Object.class.equals(method.getDeclaringClass())) {
- return method.invoke(this, args);
- } else {
- return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
- }
- } catch (Throwable t) {
- throw ExceptionUtil.unwrapThrowable(t);
- }
- }
-
- private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
- try {
- return CollectionUtils.computeIfAbsent(methodCache, method, m -> {
- if (m.isDefault()) {
- try {
- if (privateLookupInMethod == null) {
- return new DefaultMethodInvoker(getMethodHandleJava8(method));
- } else {
- return new DefaultMethodInvoker(getMethodHandleJava9(method));
- }
- } catch (IllegalAccessException | InstantiationException | InvocationTargetException
- | NoSuchMethodException e) {
- throw new RuntimeException(e);
- }
- } else {
- return new PlainMethodInvoker(new MybatisMapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
- }
- });
- } catch (RuntimeException re) {
- Throwable cause = re.getCause();
- throw cause == null ? re : cause;
- }
- }
-
- private MethodHandle getMethodHandleJava9(Method method)
- throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
- final Class<?> declaringClass = method.getDeclaringClass();
- return ((MethodHandles.Lookup) privateLookupInMethod.invoke(null, declaringClass, MethodHandles.lookup())).findSpecial(
- declaringClass, method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()),
- declaringClass);
- }
-
- private MethodHandle getMethodHandleJava8(Method method)
- throws IllegalAccessException, InstantiationException, InvocationTargetException {
- final Class<?> declaringClass = method.getDeclaringClass();
- return lookupConstructor.newInstance(declaringClass, ALLOWED_MODES).unreflectSpecial(method, declaringClass);
- }
-
- interface MapperMethodInvoker {
- Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable;
- }
-
- private static class PlainMethodInvoker implements MapperMethodInvoker {
- private final MybatisMapperMethod mapperMethod;
-
- public PlainMethodInvoker(MybatisMapperMethod mapperMethod) {
- super();
- this.mapperMethod = mapperMethod;
- }
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
- return mapperMethod.execute(sqlSession, args);
- }
- }
-
- private static class DefaultMethodInvoker implements MapperMethodInvoker {
- private final MethodHandle methodHandle;
-
- public DefaultMethodInvoker(MethodHandle methodHandle) {
- super();
- this.methodHandle = methodHandle;
- }
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
- return methodHandle.bindTo(proxy).invokeWithArguments(args);
- }
- }
- }
通过自定义扫描器去扫描指定的backpage包下的mapperinterface
3. 4.通过自定义工厂类MapperFactoryBean实现了FactoryBean接口,在使用mapperinterface对象(调用getObject)的时候会自动创建代理类MybatisMapperProxy(由Bean容器管理)
5.通过实现InvocationHandler接口,自定义代理类执行对象方法
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。