解决的问题1:自己的框架如何与springboot进行整合?
- 自研一个框架如何与springboot进行整合?
首先我们了解了像mybatis,springmvc,jedis等框架是与springboot已经整合好的
但是像dubbo等还有很多的框架 没有整合好 我们自己研发的框架要怎样与springboot进行整合.
读springboot整合mybatis过程
读配置模块 首先我们找到 AutoConfigurationimportSelector自动加载配置类,
可以看到在117行添加断点,看执行的调用过程
进入断点,我们发现springboot加载了很多的类,其中每个类都加载了AutoConfiguration这个类
那我们查看Autoconfiguration,是否我们想要被springboot整合也需要写这样的类?
答案很明显,在AutoConfiguration中既有SQLSessionFactory创建sqlSessionFactory,又有MybatisProperties读取yml文件 所以我们要想写一个类似的mybatis的而且要被springboot加载也需要写这三个类!
找到sqlSessionFactory方法(返回值是一个sqlSessionFactory并放到容器中) 加断点 发现已经进入断点
通过mybatisproperties 读取yml文件
那么springboot是如何发现并整合mybatis的呢?
我们在maven依赖中找到 springboot-actuator-autoconfigure这个jar包
找到META-INF/spring.factories中得到答案:存储形式是key:value形式
Key是springboot固定的形式而value正是MybatisAutoConfiguration也就是说Springboot自己去找META-INF/spring.factories找到需要整合的框架的配置文件进行配置
我们自己来实现一个框架,与springboot进行整合
首先我们需要创建SqlSessionFactory 类,模拟mybatis产生sqlSession访问数据库
/**
* @author renjiaxing
*我们创建一个SqlSessionFactory 模拟返回一个sqlSession
*/
public class SqlSessionFactory {
public String getSqlSession() {
return "sqlSession";
}
}
接着我们需要一个MybatisProperties 这个类进行加载yml文件
/**
* @author renjiaxing
*读取application.yml中的属性
*/
@ConfigurationProperties(prefix ="com.cy.mybatis" )
public class MybatisProperties {
private String ip="localhost";
private String username="root";
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
最后我们将这两个类融合到MybatisAutoConfiguration配置类中
//代替sping中的<bean class=SqlSessionFactory>
@Configuration
@EnableConfigurationProperties(MybatisProperties.class)
public class MybatisAutoConfiguration {
static {
System.out.println("加载MybatisAutoConfiguration");
}
//读取配置属性
@Resource
MybatisProperties mybatisProperties;
//创建核心类,放在容器中
@Bean
public SqlSessionFactory sqlSessionFactory() {
System.out.println("ip="+mybatisProperties.getIp());
System.out.println("username="+mybatisProperties.getUsername());
SqlSessionFactory factory=new SqlSessionFactory();
return factory;
}
}
最后我们要想被springboot整合还需要做最重要的一步
在resources目录下创建META-INF/spring.factories文件
最后我们将写好的程序打包,如下图打包成功
接下来我们来测试自己写的框架是否能被springboot整合.
我们创建一个测试项目 将我们刚刚打包好依赖添加进去
写一个测试的controller调用我们之前写好的框架,调用getSqlSession
/**
* @author renjiaxing
*尝试使用springboot整合我们所写的框架,并且获取yml文件中的信息
*/
@RestController
public class TestController {
//从容器中取sqlSessionFactory对象
@Autowired
SqlSessionFactory sqlSessionFactory;
@RequestMapping("/test")
public String test() {
return sqlSessionFactory.getSqlSession();
}
}
在yml文件中写入配置信息
com:
cy:
mybatis:
ip: 200.2.2.2
username: abc
启动项目,访问
拿到我们sqlsessionfactory方法中的sqlsession并且控制台也拿到了配置信息
我们完成了自己写的框架与springboot进行整合
解决的问题2:如何让我们的框架更有容错性
- 我们自己写一个类似mybatis简单的框架,要明白框架的组成,或者是说程序以及软件是由什么组成的?
[当然在大学中,可能有老师会教软件是由数据结构+算法构成的,但是随着时代的推移,
我认为软件是由很多的框架单一职责组成的,虽然我没上过!!(spring,springboot将这些框架整合到一起),
而框架是由很多个模块组成的(模块是由spi标准整合到一起)
模块又是通过设计模式,数据结构,算法来实现]
两种提供服务的方法:
Spi的介绍:(service provide interface)以接口的形式对外提供服务(优势就是模块可以被替换掉)
Tomcat:以网络的形式对外提供服务
写过一个跟数据库框架,有配置模块,SQL运行模块…很多模块
用spi标准来加载每一个模块,为每个模块提供接口,实现类放在META-INF/Services目录下
在框架中用serviceLoader加载模块
我们通过代码类实现
/**
* @author renjiaxing
*定义模块要实现的功能
*/
public interface config {
//加载配置信息
public void loadConfig();
}
创建一个接口项目,添加一个加载配置信息的方法.
接着我们写一个默认实现类
/**
* @author renjiaxing
*定义接口的默认实现
*/
public class DefaultConfigImpl implements config {
@Override
public void loadConfig() {
System.out.println("框架的默认实现");
}
}
我们写好实现类,当别人使用我们所写的框架时,就会有默认服务,但是如果别人发现我们写的代码有bug需要进行修改,我们如何写我们的代码,才能实现别人只需要写一个新的实现类,我们的框架,自己刷新并且继续使用
[Jar包含了什么?
Class文件+META-INF文件夹 spring.factories告诉Spring boot框架自动配置类在哪
Services/接口 放的是类名
]
我们需要添加一个META-INF/services 写一个文件 文件名写的是我们接口的名字
文件中的内容写的是实现类的名字
写好后我们将程序打包,写一个测试类进行测试.
将写好的实现类假如依赖
/**
* @author renjiaxing
*测试我们通过spi写的框架在遇到bug时,只需要重新写实现类,框架继续执行
*/
public class App
{
public static void main( String[] args )
{
System.out.println( "框架启动了, 加载每个模块" );
ServiceLoader<config> serviceLoader =ServiceLoader.load(config.class);
Iterator<config> iterator = serviceLoader.iterator();
while (iterator.hasNext()) {
config config = iterator.next();
config.loadConfig();
}
}
}
执行代码
可以看到此时执行的默认的实现
- 那么当我们的程序出现了bug需要修改时,我们是否能只是重写一个实现类就可以执行呢?
我们重写一个新的实现类
/**
* @author renjiaxing
*使用框架的程序员发现框架的默认的实现由bug 写一个新的实现
*做框架使用了spi标准,要求实现类必须放在一个文件中文件名必须是接口名 文件内容是实现类名
* /META-INF/services文件夹中,框架才能使用serviceload才能加载到实现类
*/
public class NewConfigImpl implements config {
@Override
public void loadConfig() {
System.out.println("新的实现");
}
}
同样的添加一个META-INF/services 写一个文件 文件名写的是我们接口的名字
文件中的内容写的是新的实现类的名字
同样的打一个包,在spi-mybatis项目中添加新的依赖
执行代码
新的代码已经执行
根据断点看源码我们能够了解sql的执行过程是
简单的流程就是
DefaultSqlSession–>executor–>statementHandler–>jdbc
加上缓存后的流程就是
Spring框架中bean class=SqlSessionFactoryBean 创建了几个对象?
两个:如果是SqlSessionFactory创建一个
SqlSessionfactoryBean返回一个SqlSessionfactoryBean,
它又实现了FactoryBean,有一个getObject方法返回一个SqlSessionFactory
所以是两个对象