Spring篇--xml方式整合第三方框架

打印 上一主题 下一主题

主题 804|帖子 804|积分 2412

Spring xml方式整合第三方框架

xml整合第三方框架有两种整合方案:

​ · 不必要自界说名空间,不必要利用Spring的配置文件配置第三方框架本身内容,例如:MyBatis;
​ · 必要引入第三方框架定名空间,必要利用Spring的配置文件配置第三方框架本身内容,例如:Dubbo。
Spring整合MyBatis,之前已经在Spring中简朴的配置了SqlSessionFactory,但是这不是正规的整合方式,
MyBatis提供了mybatis-spring.jar专门用于两大框架的整合。
Spring整合MyBatis的步骤如下:

​ · 导入MyBatis整合Spring的相关坐标;(请见资料中的pom.xml)
​ · 编写Mapper和Mapper.xml;
​ · 配置SqlSessionFactoryBean和MapperScannerConfigurer;
​ · 编写测试代码
配置SqlSessionFactoryBean和MapperScannerConfigurer:
  1. <!--配置数据源-->
  2. <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
  3.     <property name="url" value="jdbc:mysql://localhost:3306/mybatis"></property>
  4.     <property name="username" value="root"></property>
  5.     <property name="password" value="root"></property>
  6. </bean>
  7. <!--配置SqlSessionFactoryBean-->
  8. <bean class="org.mybatis.spring.SqlSessionFactoryBean">
  9.     <property name="dataSource" ref="dataSource"></property>
  10. </bean>
  11. <!--配置Mapper包扫描-->
  12. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  13.     <property name="basePackage" value="com.zjy.dao"></property>
  14. </bean>
复制代码
编写Mapper和Mapper.xml
  1. public interface UserMapper {
  2.     List<User> findAll();
  3. }
复制代码
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.zjy.dao.UserMapper">
  6.     <select id="findAll" resultType="com.zjy.pojo.User">
  7.         select * from tb_user
  8.     </select>
  9. </mapper>
复制代码
编写测试代码
  1. ClassPathxmlApplicationContext applicationContext =
  2.     new ClassPathxmlApplicationContext("applicationContext.xml");
  3. UserMapper userMapper = applicationContext.getBean(UserMapper.class);
  4. List<User> all = userMapper.findAll();
  5. System.out.println(all);
复制代码
Spring整合MyBatis的原理剖析

整合包里提供了一个SqlSessionFactoryBean和一个扫描Mapper的配置对象,SqlSessionFactoryBean一旦被实例化,就开始扫描Mapper并通过动态代理产生Mapper的实现类存储到Spring容器中。相关的有如下四个类:
​ · SqlSessionFactoryBean:必要举行配置,用于提供SqlSessionFactory;
​ · MapperScannerConfigurer:必要举行配置,用于扫描指定mapper注册BeanDefinition;
​ · MapperFactoryBean:Mapper的FactoryBean,获得指定Mapper时调用getObject方法;
​ · ClassPathMapperScanner:definition.setAutowireMode(2) 修改了自动注入状态,所以MapperFactoryBean中的setSqlSessionFactory会自动注入进去。
配置SqlSessionFactoryBean作用是向容器中提供SqlSessionFactory,SqlSessionFactoryBean实现了FactoryBean和InitializingBean两个接口,所以会自动执行getObject() 和afterPropertiesSet()方法
  1. SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean{
  2.     public void afterPropertiesSet() throws Exception {
  3.         //创建SqlSessionFactory对象
  4.         this.sqlSessionFactory = this.buildSqlSessionFactory();
  5.     }
  6.     public SqlSessionFactory getObject() throws Exception {
  7.         return this.sqlSessionFactory;
  8.     }
  9. }
复制代码
配置MapperScannerConfigurer作用是扫描Mapper,向容器中注册Mapper对应的MapperFactoryBean,MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor和InitializingBean两个接口,会在postProcessBeanDefinitionRegistry方法中向容器中注册MapperFactoryBean
  1. class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean{
  2.     public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
  3.         ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
  4.         scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
  5.     }
  6. }
复制代码
  1. class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
  2.     public Set<BeanDefinitionHolder> doScan(String... basePackages) {
  3.         Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
  4.         if (beanDefinitions.isEmpty()) {
  5.         } else {
  6.             this.processBeanDefinitions(beanDefinitions);
  7.         }
  8.     }
  9.     private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
  10.         //设置Mapper的beanClass是org.mybatis.spring.mapper.MapperFactoryBean
  11.         definition.setBeanClass(this.mapperFactoryBeanClass);
  12.         definition.setAutowireMode(2); //设置MapperBeanFactory 进行自动注入
  13.     }
  14. }
复制代码
autowireMode取值:1是根据名称自动装配,2是根据类型自动装配
  1. class ClassPathBeanDefinitionScanner{
  2.     public int scan(String... basePackages) {
  3.         this.doScan(basePackages);
  4.     }
  5.     protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
  6.         //将扫描到的类注册到beanDefinitionMap中,此时beanClass是当前类全限定名
  7.         this.registerBeanDefinition(definitionHolder, this.registry);
  8.         return beanDefinitions;
  9.     }
  10. }
复制代码
  1. UserMapper userMapper = applicationContext.getBean(UserMapper.class);
复制代码
  1. public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
  2.     public MapperFactoryBean(Class<T> mapperInterface) {
  3.         this.mapperInterface = mapperInterface;
  4.     }
  5.     public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
  6.         this.sqlSessionTemplate = this.createSqlSessionTemplate(sqlSessionFactory);
  7.     }
  8.     public T getObject() throws Exception {
  9.         return this.getSqlSession().getMapper(this.mapperInterface);
  10.     }
  11. }
复制代码
Spring 整合其他组件

Spring 整合其他组件时就不像MyBatis这么简朴了,例如Dubbo框架在于Spring举行整合时,要利用Dubbo提供的定名空间的扩展方式,自界说了一些Dubbo的标签
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.        xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
  6.                            http://www.springframework.org/schema/beans/spring-beans.xsd
  7.                            http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
  8.     <!--配置应用名称-->
  9.     <dubbo:application name="dubbo1-consumer"/>
  10.     <!--配置注册中心地址-->
  11.     <dubbo:registry address="zookeeper://localhost:2181"/>
  12.     <!--扫描dubbo的注解-->
  13.     <dubbo:annotation package="com.itheima.controller"/>
  14.     <!--消费者配置-->
  15.     <dubbo:consumer check="false" timeout="1000" retries="0"/>
  16. </beans>
复制代码
引入context定名空间,在利用context定名空间的标签
  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2.        xmlns:context="http://www.springframework.org/schema/context"
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.        xsi:schemaLocation="http://www.springframework.org/schema/beans
  5.                            http://www.springframework.org/schema/beans/spring-beans.xsd
  6.                            http://www.springframework.org/schema/context
  7.                            http://www.springframework.org/schema/context/spring-context.xsd">
  8.     <context:property-placeholder location="classpath:jdbc.properties" />
  9.    
  10. <beans>
复制代码
原理剖析剖析过程,只能从源头ClassPathXmlApplicationContext入手,经历复杂的源码追踪,找到如下两个点:
1)在创建DefaultNamespaceHandlerResolver时,为处理器映射地点handlerMappingsLocation属性赋值,并加载定名空间处理器到Map<String, Object> handlerMappings 中去
  1. this.handlerMappingsLocation = "META-INF/spring.handlers";
复制代码

第一点完成后,Map集合handlerMappings就被填充了许多XxxNamespaceHandler,继续往下追代码
2)在DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法中,发现如下逻辑:
  1. //如果是默认命名空间
  2. if (delegate.isDefaultNamespace(ele)) {
  3.     this.parseDefaultElement(ele, delegate);
  4.     //否则是自定义命名空间
  5. } else {
  6.     delegate.parseCustomElement(ele);
  7. }
复制代码
如果是默认定名空间,则执行parseDefaultElement方法
  1. private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
  2.     if (delegate.nodeNameEquals(ele, "import")) {
  3.         this.importBeanDefinitionResource(ele);
  4.     } else if (delegate.nodeNameEquals(ele, "alias")) {
  5.         this.processAliasRegistration(ele);
  6.     } else if (delegate.nodeNameEquals(ele, "bean")) {
  7.         this.processBeanDefinition(ele, delegate);
  8.     } else if (delegate.nodeNameEquals(ele, "beans")) {
  9.         this.doRegisterBeanDefinitions(ele);
  10.     }
  11. }
复制代码
如果是自界说定名空间,则执行parseCustomElement方法
  1. public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
  2.     //解析命名空间
  3.     String namespaceUri = this.getNamespaceURI(ele);
  4.     //获得命名空间解析器
  5.     NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
  6.     //解析执行的标签
  7.     return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
  8. }
复制代码
在执行resovle方法时,就是从Map<String, Object> handlerMappings中根据定名空间名称获得对应的处理器对象,此处是ContextNamespaceHandler,终极执行NamespaceHandler的parse方法
ContextNamespaceHandler源码如下,间接实现了NamespaceHandler接口,初始化方法init会被自动调用。由于context定名空间下有多个标签,所以每个标签又单独注册了对应的剖析器,注册到了其父类NamespaceHandlerSupport的Map<String, BeanDefinitionParser> parsers中去了
  1. public class ContextNamespaceHandler extends NamespaceHandlerSupport {
  2.     public ContextNamespaceHandler() {
  3.     }
  4.     public void init() {
  5.         this.registerBeanDefinitionParser("property-placeholder", new
  6.                                           PropertyPlaceholderBeanDefinitionParser());
  7.         this.registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
  8.         this.registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
  9.         this.registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
  10.         this.registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
  11.         this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
  12.         this.registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
  13.         this.registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
  14.     }
  15. }
复制代码
流程总结
将自界说标签的约束 与 物理约束文件与网络约束名称的约束 以键值对情势存储到一个spring.schemas文件里,该文件存储在类加载路径的 META-INF里,Spring会自动加载到;
将自界说定名空间的名称与自界说定名空间的处理器映射关系 以键值对情势存在到一个叫spring.handlers文件里,该文件存储在类加载路径的 META-INF里,Spring会自动加载到;
准备好NamespaceHandler,如果定名空间只有一个标签,那么直接在parse方法中举行剖析即可,一般剖析结果就是注册该标签对应的BeanDefinition。如果定名空间里有多个标签,那么可以在init方法中为每个标签都注册一个BeanDefinitionParser,在执行NamespaceHandler的parse方法时在分流给不同的BeanDefinitionParser举行剖析(重写doParse方法即可)。
举行某一个框架与Spring的集成开发

设想自己是一名架构师,举行某一个框架与Spring的集成开发,结果是通过一个指示标签,向Spring容器中自动注入一个BeanPostProcessor
  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2.        xmlns:xsi="http://www.w3.org/2001/xmlSchema-instance"
  3.        xmlns:xiaozhang="http://www.zjy.com/xiaozhang"
  4.        xsi:schemaLocation="http://www.springframework.org/schema/beans
  5.                            http://www.springframework.org/schema/beans/spring-beans.xsd
  6.                            http://www.zjy.com/xiaozhang
  7.                            http://www.itheima.com/haohao/haohao-annotation.xsd">
  8.     <xiaozhang:annotation-driven/>
  9. </beans>
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

天津储鑫盛钢材现货供应商

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表