目录
一:概述
二:代码演示
二:Spring整合MyBatis的原理剖析
三:案例演示
一:概述
xml整合第三方框架有两种整合方案:
-
不需要自定义名空间,不需要使用Spring的配置文件配置第三方框架本身内容,例如:MyBatis;
-
需要引入第三方框架命名空间,需要使用Spring的配置文件配置第三方框架本身内容,例如:Dubbo。
Spring整合MyBatis,之前已经在Spring中简单的配置了SqlSessionFactory, 但是这不是正规的整合方式,MyBatis提供了mybatis-spring.jar专门用于两大框架的整合。 Spring整合MyBatis的步骤如下:
-
导入MyBatis整合Spring的相关坐标;(请见资料中的pom.xml)
-
编写Mapper和Mapperxml;
-
配置SqlSessionFactoryBean和MapperScannerConfigurer;
-
编写测试代码
二:代码演示
①:原始方式使用Mybatis
1.创建BookMapper类和BookMapper.xml文件
package com.tangyuan.mapper;
import com.tangyuan.pojo.Book;
import java.util.List;
/**
* @author 唐渊
* @create 2022-11-30 14:27
*/
public interface BookMapper {
List<Book> findAll();
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.tangyuan.mapper.BookMapper" >
<select id="findAll" resultType="com.tangyuan.pojo.Book">
select
*
from t_book
</select>
</mapper>
2.在mybatis-config.xml中引用文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/bookshop?useSSL=false"></property>
<property name="username" value="root"></property>
<property name="password" value="1234"></property>
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.tangyuan.mapper"/>
</mappers>
</configuration>
3.编写原始测试代码
package com.tangyuan.test;
import com.tangyuan.mapper.BookMapper;
import com.tangyuan.pojo.Book;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @author 唐渊
* @create 2022-11-30 14:35
*/
public class MyBatisTest {
public static void main(String[] args) throws Exception {
//读取配置文件
//静态工厂方法方式
InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
//设置构造器
//无参构造实例化
SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
//构建工厂
//实例工厂方法
SqlSessionFactory build = builder.build(resource);
SqlSession sqlSession = build.openSession();
BookMapper mapper = sqlSession.getMapper(BookMapper.class);
List<Book> all = mapper.findAll();
for (Book a:all){
System.out.println(a);
}
}
}
----------------------------------------------------整合代码操作-----------------------------------------------------------
1.在pom文件引入依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.20</version>
</dependency>
2.在主xml文件中进行文件的配置
<!--1.配置SqlSessionFactoryBean,作用将SqlSessionFactory存储到Spring容器-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置数据源信息-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/bookshop"></property>
<property name="username" value="root"></property>
<property name="password" value="1234"></property>
</bean>
<!--2.扫描指定的包,产生Mapper对象存储到Spring容器-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.tangyuan.mapper"></property>
</bean>
3.在需要方法的类上调用方法
//需要Mapper,直接注入Mapper和提供set方法
private BookMapper bookMapper;
public void setBookMapper(BookMapper bookMapper) {
this.bookMapper = bookMapper;
}
//输出集合
@Override
public void show(){
List<Book> all = bookMapper.findAll();
all.forEach(System.out::println);
}
4.在xml文件上进行bean的配置
<bean id="userService" class="com.tangyuan.service.impl.UserServiceImpl">
<property name="bookMapper" ref="bookMapper"></property>
</bean>
5.测试
//创建ApplicationContext,加载配置文件,实例化容器
ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
IUserService userService = (IUserService) applicationContext.getBean("userService");
userService.show();
二:Spring整合MyBatis的原理剖析
整合包里提供了一个SqlSessionFactoryBean和一个扫描Mapper的配置对象,SqlSessionFactoryBean一旦被实例化, 就开始扫描Mapper并通过动态代理产生Mapper的实现类存储到Spring容器中。相关的有如下四个类:
-
SqlSessionFactoryBean:需要进行配置, 用于提供SqlSessionFactory;
-
MapperScannerConfigurer:需要进行配置,用于扫描指定mapper注册BeanDefinition;
-
MapperFactoryBean:Mapper的FactoryBean, 获得指定Mapper时调用getObject方法;
-
ClassPathMapperScanner:definition.setAutowireMode(2) 修改了自动注入状态,所以 MapperFactoryBean中的setSqlSessionFactory会自动注入进去。
Spring整合其他组件时就不像MyBatis这么简单了, 例如Dubbo框架在于Spring进行整合时, 要使用Dubbo提供的命名空间的扩展方式, 自定义了一些Dubbo的标签
<?xml version="1.0"encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!--配置应用名称-->
<dubbo:applicationname="dubbo1-consumer"/>
<!--配置注册中心地址-->
<dubbo:registryaddress="zookeeper://localhost:2181"/>
<!--扫描dubbo的注解-->
<dubbo:annotationpackage="com.itheima.controller"/>
<!--消费者配置>
<dubbo:consumercheck="false"timeout="1000"retries="o"/>
</beans>
为了降低我们此处的学习成本, 不在引入Dubbo第三方框架了, 以Spring的context命名空间去进行讲解, 该方式也是命名空间扩展方式。 需求:加载外部properties文件, 将键值对存储在Spring容器中
jdbc.url=jdbc:mysql://localhost:3306/db_shopping
jdbc.username=root
jdbc.password=1234
1.创建外部properties文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/bookshop
jdbc.username=root
jdbc.password=1234
2.通过命名空间引用外部文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd
">
<!--加载properties文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
3.配置属性
<!--配置数据源信息-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
外部命名空间标签的执行流程,如下:
-
将自定义标签的约束与物理约束文件与网络约束名称的约束以键值对形式存储到一个spring.schemas文件里 , 该文件存储在类加载路径的META-INF里, Spring会自动加载到;
-
将自定义命名空间的名称与自定义命名空间的处理器映射关系以键值对形式存在到一个叫spring.handlers文 件里, 该文件存储在类加载路径的META-INF里, Spring会自动加载到;
-
准备好NamespaceHandler, 如果命名空间只有一个标签, 那么直接在parse方法中进行解析即可, 一般解析结 果就是注册该标签对应的BeanDefinition。如果命名空间里有多个标签, 那么可以在init方法中为每个标签都注 册一个BeanDefinitionParser, 在执行NamespaceHandler的parse方法时在分流给不同的 BeanDefinitionParser进行解析(重写doParse方法即可) 。
三:案例演示
设想自己是一名架构师, 进行某一个框架与Spring的集成开发, 效果是通过一个指示标签, 向Spring容器中自动注入一个BeanPostProcessor
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/xmlSchema-instance"
xmlns:haohao="http://www.tangyuan.com/haohao"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.tangyuan.com/haohao
http://www.tangyuan.com/haohao/haohao-annotation.xsd">
<haohao:annotation-driven/>
</beans>
步骤分析:
1.确定命名空间名称、schema虚拟路径、标签名称;
2.编写schema约束文件haohao-annotation.xsd
3.在类加载路径下创建META-INF目录, 编写约束映射文件spring.schemas和处理器映射文件spring.handlers
4.编写命名空间处理器HaohaoNamespaceHandler, 在init方法中注册HaohaoBeanDefinitionParser
5.编写标签的解析器HaohaoBeanDefinitionParser, 在parse方法中注册HaohaoBeanPostProcessor
6.编写HaohaoBeanPostProcessor
========以上五步是框架开发者写的,以下是框架使用者写的
1.在applicationContext.xml配置文件中引入命名空间
2.在applicationContext.xml配置文件中使用自定义的标签
代码演示:
1.确定命名空间名称、schema虚拟路径、标签名称;
2.编写schema约束文件haohao-annotation.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.tangyuan.com/haohao"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.tangyuan.com/haohao">
<xsd:element name="annotation-driven"></xsd:element>
</xsd:schema>
3.在类加载路径下创建META-INF目录, 编写约束映射文件spring.schemas和处理器映射文件spring.handlers
http\://www.tangyuan.com/haohao/haohao-annotation.xsd=com/tangyuan/haohao/config/haohao-annotation.xsd
http\://www.tangyuan.com/haohao=com.tangyuan.handlers.HaohaoNamespaceHandler
4.编写命名空间处理器HaohaoNamespaceHandler, 在init方法中注册HaohaoBeanDefinitionParser
package com.tangyuan.handlers;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
public class HaohaoNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
//初始化,一般情况下,一个名空间下有多个标签,会在init方法中为每一个标签注册一个标签解析器
this.registerBeanDefinitionParser("annotation-driven",new HaohaoBeanDefinitionParser());
}
}
5.编写标签的解析器HaohaoBeanDefinitionParser, 在parse方法中注册HaohaoBeanPostProcessor
package com.tangyuan.handlers;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
public class HaohaoBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
//注入一个BeanPostProcessor
BeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClassName("com.tangyuan.processor.HaohaoBeanPostProcessor");
parserContext.getRegistry().registerBeanDefinition("haohaoBeanPostProessor",beanDefinition);
return beanDefinition;
}
}
6.编写HaohaoBeanPostProcessor
package com.tangyuan.processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class HaohaoBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("HaohaoBeanPostProcessor执行....");
return bean;
}
}
7.在主xml文件引用
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:haohao="http://www.tangyuan.com/haohao"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd
http://www.tangyuan.com/haohao
http://www.tangyuan.com/haohao/haohao-annotation.xsd
">
<!--使用自定义的命名空间标签-->
<haohao:annotation-driven></haohao:annotation-driven>