typora-root-url: img
一、使用xml文件整合MyBatis框架
这是MyBatis的核心配置文件,我们就对比着核心配置文件,将MyBatis整合进Spring中
首先我们需要先导入对应着的坐标
<dependency> <!--实体类映射文件依然存在,所以需要-->
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<dependency> <!--访问数据库-->
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency> <!--spring框架的中的context坐标,用于读取配置文件-->
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency> <!--spring框架的中的jbdc坐标,用于处理数据库连接操作-->
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency> <!--连接池-->
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency> <!--MyBatis整合进Spring的实现坐标-->
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
起初我理解是,已经将MyBatis整合进Spring了,为什么还需要MyBatis的jar包?直接使用整合jar包不就好了吗?
因为我在这个测试中使用的配置文件的方式来映射Dao接口的(我将sql语句写在xml文件中,没有用注解)。所以任然需要MyBatis的jar包。
为什么将MyBatis整合进Spring需要MyBatis提供jar包?
因为Spring牛逼,市场占有份额高,所以由MyBatis提供,而且市面上这么多插件和框架,Spring的人得天天关注谁出新框架了之类得。
Spring的配置文件
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--读取properties配置文件-->
<context:property-placeholder location="classpath:*.properties"/>
<!--集成durid连接池 值是从配置文件中读取出来的-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置核心配置文件-->
<!--配置service作为spring的bean,注入dao 后面spring会自动帮我们注入-->
<bean id="accountService" class="com.MyDemo.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<!--spring整合mybatis后控制的创建连接用的对象-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--包扫描别名-->
<property name="typeAliasesPackage" value="com.xiao.domain"/>
</bean>
<!--加载mybatis映射配置的扫描,将其作为spring的bean进行管理-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xiao.dao"/>
</bean>
</beans>
分块解释:
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
因为读取配置文件,是归属另一块命名空间管理,所以需要引入新的约束
<context:property-placeholder location="classpath:*.properties"/>
读取配置文件,classpath:*.properties 读取resources目录下所有properties文件,*是通配符
<!--集成durid连接池 值是从配置文件中读取出来的-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
在原有的Mybatis中,提供有连接池,但是现在整合进Spring,连接池没了,所以需要我们自己配置。
将连接池这个类告诉Spring,它就会帮我们自动创建这个对象。
<!--spring整合mybatis后控制的创建连接用的对象-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--包扫描别名-->
<property name="typeAliasesPackage" value="com.xiao.domain"/>
</bean>
我们在使用MyBatis框架的时的操作步骤:
工厂构造类 —> 工厂类 —> sql会话对象 —> 根据接口和配置文件生成sql语句执行对象
最终我们要得到就是sql语句的执行对象。
//1.读取mybatis主配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建构建者对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//3.使用构建者创建SqlSessionFactory工厂
SqlSessionFactory factory = builder.build(in);
//4.获得sql会话对象
SqlSession sqlSession = factory.openSession(true);
//5.获得执行对象
UserDao userDao = sqlSession.getMapper(UserDao.class);
MyBatis提供将其整合进Spring的jar包
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
由这个jar包的结构目录我们知道,我们现在可以直接获取SqlSession对象。通过这个类直接创建即可。
对比之前MyBatis使用配置文件方式创建SqlSession对象,配置文件中我们需要加载配置文件,定义数据库连接池,定义包的别名,定义实体类映射的配置文件。
通过查看这个类的方法结构我们知道,现在我们将这些原本使用配置文件设置的方式改为了set方法,那么我们就可以在spring中使用set注入,为SqlSession对象赋值。
那么我们还需要的实体类映射配置文件呢?
原本我们也可以使用set方法进行设置,但是MyBatis给了我们更优化的方法
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xiao.dao"/>
</bean>
将加载实体类定义为了一个类,那么我们只需要通过bean标签配置之后,spring会帮助我们自动生成对象。
spring在看见MyBatis的整合之后
<!--spring整合mybatis后控制的创建连接用的对象-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--包扫描别名-->
<property name="typeAliasesPackage" value="com.xiao.domain"/>
</bean>
<!--加载mybatis映射配置的扫描,将其作为spring的bean进行管理-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xiao.dao"/>
</bean>
会先创建出一个SqlSession对象,和实体类映射配置对象,SqlSession对实体类映射配置对象进行加工,产生了sql语句执行对象,然后进行分发,一看,咦,
<!--配置service作为spring的bean,注入dao 后面spring会自动帮我们注入-->
<bean id="accountService" class="com.xiao.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean
你需要使用,那么我spring就将对应的sql语句执行对象注入进去。欧克,完美结束。
二、Spring注解开发
使用注解的形式替代xml配置,将繁杂的spring配置文件从工程中彻底消除掉,简化书写
对比注解和配置文件的方式:
1、使用配置的方式多一个配置文件,需要在java代码和配置文件之间相互切换
2、但是注解需要在源代码上进行修饰,如果我们使用第三方资源时,无法修改源代码,所以会增加一定工作量,但是这是注解的便利更多,所以是可以接受的。
调用注解管理的对象:
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
AccountService accountServiceImpl2 = (AccountService) ctx.getBean("AccountServiceImpl_2");
accountServiceImpl2.save(new Account(3,"shaoting",2000));
我们new对象的方式和配置文件不一样了,但是调用都是一样的,都是使用getBean方法。
1、常用注解
<context:component-scan base-package="packageName"/>
在使用注解之前,我们需要先在配置文件声明。这样spring才会到指定目录下去扫描注解。
至于为什么使用了注解还需要配置文件,先慢慢来,后面会将配置文件全部移除掉。替换是有一个过程的。
说明:
◆ 在进行包所扫描时,会对配置的包及其子包中所有文件进行扫描
◆ 扫描过程是以文件夹递归迭代的形式进行的
◆ 扫描过程仅读取合法的java文件
◆ 扫描时仅读取spring可识别的注解
◆ 扫描结束后会将可识别的有效注解转化为spring对应的资源加入IoC容器
注意:
◆ 无论是注解格式还是XML配置格式,最终都是将资源加载到IoC容器中,差别仅仅是数据读取方式不同
◆ 从加载效率上来说注解优于XML配置文件(因为看见了注解就直接加载到容器中,使用配置,得先根据class属性找到对应的类,在将其加载到容器中)
1.1 bean的定义
替换bean标签的注解:@Component @Controller @Service @Repository
类型:类注解
位置:类定义上方
作用:设置该类为spring管理的bean
说明:
◆ @Controller、@Service 、@Repository是@Component的衍生注解,功能同@Component
@Controller、@Service 、@Repository是spring的一个规范,分别对应web控制层、业务层、数据层
实际上与@Component相同,四个都可以混着用,但是建议按照规范书写,不然容易引发同事矛盾。
@Service("AccountServiceImpl")
public class AccountServiceImpl implements AccountService {
}
名称:@Scope
类型:类注解
位置:类定义上方
作用:设置该类作为bean对应的scope属性
@Scope("prototype")
public class ClassName{}
相关属性
◆ value(默认):定义bean的作用域,默认为singleton
名称:@PostConstruct、@PreDestroy
类型:方法注解
位置:方法定义上方
作用:设置该类作为bean对应的生命周期方法
参考上面的那一张图吧。
2、注解加载第三方资源
我们的注解是加载类上面的,第三方资源的代码我们没有修改的权限,那么怎么通过注解的方式让spring帮我们管理对象呢?
使用工厂对象创建的方法。在配置文件中
<!--静态工厂创建bean-->
<bean id="userService4" class="com.xiao.service.UserServiceFactory" factory-method="getService"/>
这句代码执行流程是:spring要给这个类创建对象,一看,有一个factory-method="getService"属性,spring就明白了,你原来是让我执行这个类的方法,不是创建这个类的对象,那么spring就去执行这个方法,结果得到另一个对象。那么spring就管理这个返回的对象
那么注解,我们也有对应的注解。所以我们通过工厂模式来加载第三方的资源
话不多说上代码:
首先必须给类加上注解,保证这个类被spring扫描到,spring进入这个类,看见@Bean注解,就会调用这个方法,将得到的对象与对应的id(bena注解括号里的值)管理起来,所以我们直接getBean对应id即可获取这个第三方的资源对象。
你说为什么不使用静态方法,让spring管理这个类就行了。后面要使用第三方资源直接通过类点调用就好了。
因为,首先多一层,控制肯定不方便,而且在属性注入的时候,我们直接使用对应id进行注入,难不成你要我还要再被注入的类中,再去点调用一次方法得到第三方资源对象,这肯定不合理。
3、属性注入
对比配置文件
<bean id="accountService" class="com.xiao.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
再bean标签中使用property标签,而且对应的类必须要有set方法!
使用注解注入。
3.1 基本属性类型
直接在对应的属性上面写值,这只是一种格式,@Value中可以使用变量,通常和读取配置文件结合使用(后面讲)
那么set方法我也可以省略。
3.2 引用数据类型
名称:@Autowired、@Qualifier
类型:属性注解、方法注解
位置:属性定义上方,方法定义上方
作用:设置对应属性的对象或对方法进行引用类型传参
◆ @Autowired默认按类型装配,指定@Qualifier后可以指定自动装配的bean的id
@Autowired
private UserDao userDao;
名称:@Primary
类型:类注解
位置:类定义上方
作用:设置类对应的bean按类型装配时优先装配
@Autowired 自动属性注入,spring会自动识别。刚好你这里有一个类型是UserDao,如果没有id,但是只有一个UserDao的实现类,那么spring也会讲这个唯一的UserDao给你注入到对应的属性值中。
如果你有两个UserDao的实现类,但是其中一个id和你变量名匹配,那么spring会将id与变量匹配的UserDao注入对应的属性值中。
如果两个UserDao实现类,但是两个的id都不和变量匹配,那么会报错
如果两个UserDao实现类,但是两个的id都不和变量匹配,那么我们可以使用@Qualifier(“id值”),可以指定注入哪一个UserDao的实现类。
如果两个Use人Dao都没有指定id,使用@Autowired自动装配会报错,那么我们可以使用@Primary在两个UserDao的实现类中,谁有就先注入谁的,但是两者不同同时存在!
如果在系统更迭时,出现了三个UserDao的实现类,那么只能通过@Qualifier指定具体的id
3.3 加载properties配置文件的注解
名称:@PropertySource
类型:类注解
位置:类定义上方
作用:加载properties文件中的属性值
范例:
@PropertySource(value = "classpath:filename.properties")
public class ClassName {
@Value("${propertiesAttributeName}")
private String attributeName;
}
说明:
◆ 不支持*通配格式,一旦加载,所有spring控制的bean中均可使用对应属性值
◆ value(默认):设置加载的properties文件名
◆ ignoreResourceNotFound:如果资源未找到,是否忽略,默认为false
当你的配置文件都有,你可以在()里只写配置问价名,但是注意要是数组格式{1,2,3}
但是当你配置文件不存在会报错,如果想让有就加载没有就忽略的功能,那么加上 ignoreResourceNotFound=true,那么前面的数组必须对应value属性。
@PropertySource(value = {"classpath:filename.properties","abc.properties"},ignoreResourceNotFound=true)
结合之前基本类型的属性注入。就可以使用文件中的值,${} ,对应文件中的键
三、Spring纯注解开发
纯注解格式:
-
名称:@Configuration、@ComponentScan
-
类型:类注解
-
位置:类定义上方
-
作用:设置当前类为spring核心配置加载类
-
范例:
@Configuration @ComponentScan("scanPackageName") public class SpringConfigClassName{ }
@Configuration 声明这是一个配置类,就不用去加载spring的配置文件了,
@ComponentScan(“scanPackageName”),作用是打开包扫描,去指定目录下扫描哪些类使用了spring注解。效果等于配置文件中的 <context:component-scan base-package=“packageName”/>
说明:
◆ 核心配合类用于替换spring核心配置文件,此类可以设置空的,不设置变量与属性
◆ bean扫描工作使用注解@ComponentScan替代
AnnotationConfigApplicationContext
加载纯注解格式上下文对象,需要使用AnnotationConfigApplicationContext
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
第三方bean配置与管理
名称:@Import
类型:类注解
位置:类定义上方
作用:导入第三方bean作为spring控制的资源
范例:
@Configuration
@Import(OtherClassName.class)
public class ClassName {
}
说明:
◆ @Import注解在同一个类上,仅允许添加一次,如果需要导入多个,使用数组的形式进行设定
◆ 在被导入的类中可以继续使用@Import导入其他资源(了解)
◆ @Bean所在的类可以使用导入的形式进入spring容器,无需声明为bean
之前我们的配置文件也是根据不同的模块对配置文件进行拆分,这个@Import就是带体配置文件的import标签的
四、使用纯注解整合MyBatis
我们只需要将对应部分换成注解就行了,其他的思想和思路和配置文件时一样的,只要你会配置文件整合,那么注解你就只需要多记忆几个注解。
首先我们制作一个主配置类,所以需要@Configuration申明这时一个著配置类,然后我们需要包扫描,所以需要@ConponentScan(“包路径”)
在实际开发中,一个外部资源,一个模块一个配置类,所以我们需要将其他配置类导入进来,@Import
@Configuration
@ConponentScan("com.test")
@Import({"JDBCConfig.class","MyBatisConfig.class"})
@PropertySource("classPath:jdbc.properties")
public class SpringConfig(){
}
JDBCConfig配置类
需要读取properties配置文件,所以需要@PropertySource,那么和xml配置文件一样,同意在主类上加
我们需要从配置文件中读取数据@Value
我们需要类似工厂模式的方法加载第三方资源,所以需要@Bean,因为Import导入了,所以类上面不需要@Component
public class JDBCConfig(){
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String userName;
@Value("${jdbc.password}")
private String password;
@Bean("dataSource")
public DataSource getDataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
MyBatisConfig配置类
我们需要Sqlsession对象,所以使用工厂方法@Bean。反正第三方的资源,需要我们创建都对象才能使用的都使用@Bean注解工厂模式进行创建,因为源码我们无法进行修改。
public class MyBatisConfig(){
@Bean
public SqlSessionFactoryBean getSqlSessionFactoryBean(@Autowired DataSource dataSource){
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
ssfb.setTypeAliasesPackage("com.xiao.domain");
ssfb.setDataSource(dataSource);
return ssfb;
}
//通过包扫描读取配置文件
@Bean
public MapperScannerConfigurer getMapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.xiao.dao");
return msc;
}
}
将SqlSession对象交有spring进行管理,显示MyBatis使用纯注解的方式就整合完毕了。
为什么MyBaits的Bean不用加id值,因为这是交给spring使用的,spring会根据类型自动识别,为什么上面JDBCConfig的Bean需要加id,因为这个类创建之后要给SqlSession对象使用,使用传参的方式,@Autowired自动注入到参数中。
使用
@Service("AccountServiceImpl_2")
public class AccountServiceImpl_2 implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public void save(Account account) {
accountDao.save(account);
}
@Override
public List<Account> findAll() {
return accountDao.findAll();
}
}
Sqlsession对象,根据实体类映射生成sql语句执行对象,生成之后交由spring管理,根据 @Autowired注解,自动将对应类型的sql语句对象注入到业务层中。
现在想一想框架。我们多了三个配置类。但是MyBatis的核心配置文件,实体类映射文件得了,但是数据层的接口得需要使用注解,这是一个非常要注意的地方。
五、Spring整合Junit
Spring接管Junit的运行权,使用Spring专用的Junit类加载器
因为我要使用自动注入,所以需要加载Spring配置类