Spring-day02
01_开启Spring注解
目标
- 能够设置Spring的注解扫描
路径
- 注解开发的意义
- 在配置文件中开启Spring注解扫描
注解开发的意义
在Spring中除了可以使用xml配置IoC外,还可以使用注解配置IoC
- 注解配置相对xml方式会比较简洁,但是阅读性也会差一些
Spring启动时使用注解的形式替代xml配置,将繁杂的spring配置文件从工程中彻底消除掉,简化书写
注解配置的弊端:
- 注解的配置需要基于源代码
- 为了达成注解驱动的目的,可能会将原先很简单的书写,变的更加复杂
在配置文件中开启Spring注解扫描
在Spring中要使用注解配置,要启动注解扫描:
- 根据指定的包名,加载类中配置的注解项
<context:component-scan base-package="packageName"/>
说明:
-
在进行包扫描时,会对配置的包及其子包中所有文件进行扫描
-
扫描过程是以文件夹递归迭代的形式进行的
-
扫描过程仅读取合法的java文件
-
扫描时仅读取spring可识别的注解
-
扫描结束后会将可识别的有效注解转化为spring对应的资源加入IoC容器
注意:
-
无论是注解格式还是XML配置格式,最终都是将资源加载到IoC容器中,差别仅仅是数据读取方式不同
- 从加载效率上来说注解优于XML配置文件
02_IoC的注解配置-装配bean
目标
- 能够使用@Component注解装配bean
路径
- @Component注解介绍
- 使用@Component注解装配bean
@Component注解介绍
在Spring中使用@Component注解,设置类为spring管理的bean
@Component //相当于在xml中配置:<bean id="" class="">
public class ClassName{
}
@Component注解中的属性:
- value : 指定bean的id。如果不指定value属性,默认bean的id是当前类的类名(首字母小写)。
@Component("service") //相当于在xml中配置:<bean id="service" class="包.UserServiceImpl">
public class UserServiceImpl implements UserService{
}
使用@Component注解装配bean
在Spring中使用注解的步骤:
- 开启spring注解扫描
- 在类上添加@Component注解
代码示例:
- 配置文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启spring注解扫描
spring扫描指定包下的类,加载配置了注解的类
-->
<context:component-scan base-package="com.itheima"/>
</beans>
- 业务层
//接口
public interface IUserService {
public void saveUser(User user);
}
//实现类
@Component("userService")
public class UserServiceImpl implements IUserService {
@Override
public void saveUser(User user) {
System.out.println("UserSerive => saveUser方法");
}
}
- 测试类
public class UserServiceTest {
private IUserService userService;//业务对象
@Before
public void initUserService() {
//加载配置文件初始化容器
ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
//从容器中获取对象
userService = (IUserService) cxt.getBean("userService");
}
@Test
public void testSaveUser() {
//创建User对象
User user = new User("黑马","123123");
userService.saveUser(user);
}
}
03_IoC的注解配置-衍生注解
目标
- 能够使用衍生注解装配bean
路径
- 衍生注解介绍
- 使用衍生注解装配bean
衍生注解介绍
在@Component注解下,衍生了@Controller、@Service 、@Repository三个注解。功能同等于@Component
- 衍生注解提供了更加明确的语义
- @Controller:一般用于表现层的注解
- @Service:一般用于业务层的注解
- @Repository:一般用于持久层的注解
使用衍生注解装配bean
使用衍生注解完成bean的装配:
1、 使用@Service注解装配service的实现类
2、 使用@Respository注解装配dao的实现类
代码示例:
- 配置文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启spring注解扫描
spring扫描指定包下的类,加载配置了注解的类
-->
<context:component-scan base-package="com.itheima"/>
</beans>
- Dao层(持久层)
//接口
public interface IUserDao {
public void addUser(User user);
}
//实现类
@Repository("userDao")
public class UserDaoImpl implements IUserDao{
/**
* 添加用户
* @param user
*/
@Override
public void addUser(User user) {
System.out.println("UserDao => addUser方法");
}
}
- 业务层
//接口
public interface IUserService {
public void saveUser(User user);
}
//实现类
@Service("userService")
public class UserServiceImpl implements IUserService {
@Override
public void saveUser(User user) {
System.out.println("UserSerive => saveUser方法");
}
}
- 测试类
//测试dao层
public class UserDaoTest {
private IUserDao userDao;
@Before
public void initUserService() {
//加载配置文件初始化容器
ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
//从容器中获取对象
userDao = (IUserDao) cxt.getBean("userDao");
}
@Test
public void testAddUser() {
//创建User对象
User user = new User("黑马", "123123");
userDao.addUser(user);
}
}
//测试业务层
public class UserServiceTest {
private IUserService userService;
@Before
public void initUserService() {
//加载配置文件初始化容器
ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
//从容器中获取对象
userService = (IUserService) cxt.getBean("userService");
}
@Test
public void testSaveUser() {
//创建User对象
User user = new User("黑马","123123");
userService.saveUser(user);
}
}
虽然从spring容器中单独获取service的实现类和dao的实现类都没有问题。
但是当在service实现类中加入dao对象后时,发现会报空指针异常
原因是service的实现类中调用了dao的实现类,但是dao的实现类对象并没有被注入到service的实现类中,因此造成了空指针异常。
原因分析:我们仅仅使用注解装配了bean,但是并没有将dao注入到service中。
解决方案:使用注解注入
04_IoC的注解配置-属性注入1
目标
- 能够使用@Autowired或@Qualifier实现引用类型属性注入
路径
- @Autowired注解介绍
- 使用@Autowired向业务类中注入dao对象
- @Qualifier注解介绍
@Autowired注解介绍
@Autowired注解:
public class ClassName{
@Autowired
private 引用类型 对象名;
}
- 作用:按照类型注入引用类型对象
- 当容器中只有一个类型匹配的对象时直接注入
- 当有多个类型匹配的对象时,使用要注入的对象的变量名称作为bean的id,在spring容器查找,找到了也可以注入成功,找不到就报错。
- 细节:当使用注解注入属性时,可以省略setter方法
使用@Autowired向业务类中注入dao对象
代码示例:
- 业务层
@Service("userService")
public class UserServiceImpl implements IUserService {
@Autowired //自动按照类型注入
private IUserDao userDao;//dao层对象
@Override
public void saveUser(User user) {
System.out.println("UserSerive => saveUser方法");
userDao.addUser(user);
}
}
- 测试类
public class UserServiceTest {
private IUserService userService;
@Before
public void initUserService() {
//加载配置文件初始化容器
ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
//从容器中获取对象
userService = (IUserService) cxt.getBean("userService");
}
@Test
public void testSaveUser() {
//创建User对象
User user = new User("黑马","123123");
userService.saveUser(user);
}
}
//输出结果:
UserSerive => saveUser方法
UserDao => addUser方法
@Autowired注解的属性:
required (通常不用书写)[了解即可]
取值:
true: 此对象必须注入成功,若不成功则报错 (默认值)
false: 可以注入不成功,此对象为null
@Qualifier注解介绍
@Qualifier注解:
public class ClassName{
@Autowired
@Qualifier("beanId")
private 引用类型 对象名;
}
-
作用:在自动按照类型注入(@Autowired)的基础之上,再按照bean的id注入
-
应用场景:
在使用@Autowired注入,当有多个类型匹配的对象时: 按照@Qualifier("beanId")注解指定beanId进行注入
-
属性: value , 指定bean的id
-
注意事项:@Qualifier注解不能独立使用,必须和@Autowired一起使用
代码示例:
- Dao层 (有多个类型相同的Dao对象)
//第1个:IUserDao
@Repository("userDao")
public class UserDaoImpl implements IUserDao {
@Override
public void addUser(User user) {
System.out.println("UserDao => addUser方法");
}
}
//第2个:IUserDao
@Repository("userDao2")
public class UserDaoImpl2 implements IUserDao {
@Override
public void addUser(User user) {
System.out.println("UserDao2 => addUser方法");
}
}
- 业务层
@Service("userService")
public class UserServiceImpl implements IUserService {
@Autowired
@Qualifier("userDao2") //从容器中获取名为"userDao2"的对象注入
private IUserDao userDao;
@Override
public void saveUser(User user) {
System.out.println("UserSerive => saveUser方法");
userDao.addUser(user);
}
}
05_IoC的注解配置-属性注入2
目标
- 能够使用@Value实现非引用类型属性注入
路径
- @Value注解介绍
- 使用@Value向基本类型或String类型属性注入数据
@Value注解介绍
@Value注解:
public class ClassName{
@Value("100")
private int num;
@Value("黑马")
private String name;
}
-
说明:
-
value值仅支持基本数据、String类型、包装类类型
-
value值支持读取properties文件中的属性值
-
value值支持SpringEL表达式
-
@value注解如果添加在属性上方,可以省略setter方法
-
-
相关属性
- value(默认):定义对应的属性值
使用@Value向基本类型或String类型属性注入数据
代码示例:
- 业务层
@Service("userService2")
public class UserServiceImpl2 implements IUserService {
@Value("1000")
private int num; //基本类型
@Value("黑马")
private String name; //String类型
@Value("20")
private Integer age; //Integer类型(包装类)
@Autowired
private IUserDao userDao;
@Override
public void saveUser(User user) {
System.out.println("UserSerive2 => saveUser方法");
System.out.println("int类型:"+num);
System.out.println("String类型:"+name);
System.out.println("包装类类型:"+age);
userDao.addUser(user);
}
}
- 测试类
public class UserServiceTest {
private IUserService userService;
@Before
public void initUserService() {
//加载配置文件初始化容器
ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
//从容器中获取对象
userService = (IUserService) cxt.getBean("userService2");
}
@Test
public void testSaveUser() {
//创建User对象
User user = new User("黑马","123123");
userService.saveUser(user);
}
}
//输出结果:
UserSerive2 => saveUser方法
int类型:1000
String类型:黑马
包装类类型:20
UserDao => addUser方法
06_IoC的注解配置-加载properties文件
目标
- 能够使用@PropertySource加载properties文件
路径
- @PropertySource注解介绍
- 使用@PropertySource加载properties文件
@PropertySource注解介绍
@PropertySource注解:
@PropertySource(value = "文件名.properties")
public class ClassName {
@Value("${properties文件中的属性名}")
private String attributeName;
}
- 作用:加载外部properties配置文件
- 属性:value , 设置加载的properties文件名
使用@PropertySource加载properties文件
代码示例:
- properties文件
name=heima
num=10
- 业务层
@Service("userService2")
@PropertySource(value = "data.properties") //引入外部properties配置文件
public class UserServiceImpl2 implements IUserService {
@Value("${num}") //获取配置文件中的数据
private int num;
@Value("${name}")
private String name;
@Value("${age}")
private Integer age;
@Autowired
private IUserDao userDao;
@Override
public void saveUser(User user) {
System.out.println("UserSerive2 => saveUser方法");
System.out.println("int类型:"+num);
System.out.println("String类型:"+name);
System.out.println("包装类类型:"+age);
userDao.addUser(user);
}
}
- 测试类
public class UserServiceTest {
private IUserService userService;
@Before
public void initUserService() {
//加载配置文件初始化容器
ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
//从容器中获取对象
userService = (IUserService) cxt.getBean("userService2");
}
@Test
public void testSaveUser() {
//创建User对象
User user = new User("黑马","123123");
userService.saveUser(user);
}
}
//输出结果:
UserSerive2 => saveUser方法
int类型:10
String类型:heima
包装类类型:20
UserDao => addUser方法
小结
从外部资源文件中获取数据:
- 使用:@PropertySource注解,加载外部配置文件
- 使用:@Value注解+SpringEL表达式,获取配置文件中的数据
07_IoC的注解配置-纯注解开发
目标
- 能够使用Spring纯注解方式编写程序
路径
- @Configuration注解介绍
- @ComponentScan注解介绍
- 使用纯注解形式开发
取消spring的xml配置文件,使用纯注解开发模式:
- 指定配置类,代替xml配置文件
- 在配置类中指定要扫描的包
- 使用AnnotationConfigApplicationContext类代替ClassPathXmlApplicationContext类
@Configuration注解介绍
@Configuration注解
@Configuration
public class SpringConfig{
}
作用:指定当前类是一个spring配置类,当创建容器时会从该类上加载注解
- 简单来讲:就是替换掉spring的xml配置文件(不在使用applicationContext.xml配置文件了)
面临的问题:使用配置类代替了XML配置文件了,但是如何配置创建容器时要扫描的包呢?
- 使用:@ComponentScan注解
@ComponentScan注解介绍
@ComponentScan注解:
@Configuration
@ComponentScan("包名路径")
public class SpringConfig{
}
-
作用:用于指定spring在初始化容器时要扫描的包
-
和xml配置文件中的功能一样
<context:component-scan base-package="包名路径"/>
-
-
属性: value , 用于指定要扫描的包。和标签中的base-Package属性作用一样。
使用纯注解形式开发
纯注解方式开发:使用AnnotationConfigApplicationContext类加载注解配置
获取容器时要使用:AnnotationApplicationContext(有@Configuration注解的类.class)
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
代码示例:
- 配置类
@Configuration //当前类是Spring配置类
@ComponentScan("com.itheima")//指定扫描的包
@PropertySource(value = "data.properties")//加载外部资源文件
public class SpringConfig {
}
- 业务类
@Service("userService2")
//@PropertySource(value = "data.properties") //可以删除(配置类中已加载了外部配置文件)
public class UserServiceImpl2 implements IUserService {
@Value("${num}")
private int num; //基本类型
@Value("${name}")
private String name; //String类型
@Value("${age}")
private Integer age; //Integer类型(包装类)
@Autowired
private IUserDao userDao;
@Override
public void saveUser(User user) {
System.out.println("UserSerive2 => saveUser方法");
System.out.println("int类型:"+num);
System.out.println("String类型:"+name);
System.out.println("包装类类型:"+age);
userDao.addUser(user);
}
}
- 测试类
public class UserServiceTest2 {
private IUserService userService;
@Before
public void initUserService() {
//加载配置类初始化容器 (不使用XML配置文件了)
ApplicationContext cxt = new AnnotationConfigApplicationContext(SpringConfig.class);
//从容器中获取对象
userService = (IUserService) cxt.getBean("userService2");
}
@Test
public void testSaveUser() {
//创建User对象
User user = new User("黑马","123123");
userService.saveUser(user);
}
}
小结
使用纯注解形式开发Spring的步骤:
- 创建Spring配置类(代替xml配置文件)
- 使用:@Configurable注解表示当前类为配置类
- 在Spring配置类上,指定要扫描的包路径
- 使用:@ComponentScan注解指定扫描的包
- 使用AnnotationConfigApplicationContext创建Spring容器
08_IoC的注解配置-加载第三方资源
目标
- 能够使用@Bean注解装配bean
路径
- @Bean注解介绍
- 使用@Bean加载第三方资源
- 第三方bean配置与管理
在XML配置文件中,可以把第三方框架(例:Druid)中的类,配置到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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置Druid中的类,作为Spring容器中的一个资源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/db1"></property>
<property name="username" value="root"></property>
<property name="password" value="itheima"></property>
</bean>
</beans>
- 通过bean标签的id值,就可以获取到第三方框架中类的对象
问题:当使用纯注解开发模式后,就取消了XML配置文件,如果要从spring容器中获取第三框架中的类,怎么办?
答案:第三方框架的bean是无法在其源码上进行修改,可以使用@Bean实现第三方bean的引入
@Bean注解介绍
@Bean注解:
@Component
public class ClassName{
@Bean("名字")
public 返回值类型 方法名(){
return 返回值;
}
}
- 作用:设置方法的返回值作为spring管理的bean(将方法的返回值作为一个bean,并且放入spring容器)
- 属性:value , 定义bean的访问id
说明:
- @Bean注解用于替代XML配置中的静态工厂与实例工厂创建bean(不区分方法是否为静态或非静态)
- @Bean所在的类必须被spring扫描加载,否则该注解无法生效
使用@Bean加载第三方资源
代码示例:
- 第三方资源
@Component //@Bean所在的类必须被spring扫描加载,否则该注解无法生效
public class MyDataSource {
@Bean("druidDataSource") //bean的id名(spring容器中资源的名字)
public DataSource createDruidDataSource(){
//创建第三方资源对象
DruidDataSource druidDataSource = new DruidDataSource();
//设置参数
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/db1");
druidDataSource.setUsername("root");
druidDataSource.setPassword("itheima");
//返回对象
return druidDataSource;
}
}
- Dao层
@Repository("userDao")
public class UserDaoImpl implements IUserDao {
@Autowired
@Qualifier("druidDataSource") //指定bean的名字
private DataSource dataSource;
/**
* 添加用户
* @param user
*/
@Override
public void addUser(User user) {
System.out.println("UserDao => addUser方法");
try {
System.out.println("数据库连接状态:"+dataSource.getConnection().isClosed());
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
- 测试类
public class UserDaoTest2 {
private IUserDao userDao;
@Before
public void initUserService() {
//加载配置类初始化容器
ApplicationContext cxt = new AnnotationConfigApplicationContext(SpringConfig.class);
//从容器中获取对象
userDao = (IUserDao) cxt.getBean("userDao");
}
@Test
public void testAddUser() {
//创建User对象
User user = new User("黑马", "123123");
userDao.addUser(user);
}
}
//输出结果:
UserDao => addUser方法
数据库连接是否关闭:false
第三方bean配置与管理
以上程序代码中,使用@Component注解,保证第三方框架中的类可以被spring扫描加载
除了这种方式外,还可以使用@Import注解,导入第三方bean作为spring控制的资源
@Import注解:
@Import(MyDataSource.class)
public class ClassName {
}
说明:
-
@Import注解在同一个类上,仅允许添加一次,如果需要导入多个,使用数组的形式进行设定
@Import(value = {MyDataSource.class, MyDS.class , .... })//按照顺序加载 //@Import(...)//同一个类上,不允许出现2次Import public class ClassName { }
-
在被导入的类中可以继续使用@Import导入其他资源(了解)
-
@Bean所在的类可以使用导入的形式进入spring容器,无需声明为bean
代码示例:
- 配置类
@Configurable //当前类是Spring配置类
@ComponentScan("com.itheima")//指定扫描的包
@PropertySource(value = "data.properties")//加载外部资源文件
@Import(MyDataSource.class) //导入MyDataSource类
public class SpringConfig {
}
- 第三方资源Bean
//@Component //可以删除 (在配置类中导入了MyDataSource类)
public class MyDataSource {
@Bean("druidDataSource") //bean的id名(spring容器中资源的名字)
public DataSource createDruidDataSource(){
//创建第三方资源对象
DruidDataSource druidDataSource = new DruidDataSource();
//设置参数
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/db1");
druidDataSource.setUsername("root");
druidDataSource.setPassword("itheima");
//返回对象
return druidDataSource;
}
}
另一种方式:直接在SpringConfig配置类中添加第三方Bean资源
@Configurable //当前类是Spring配置类
@ComponentScan("com.itheima")//指定扫描的包
@PropertySource(value = "data.properties")//加载外部资源文件
public class SpringConfig {
@Bean("druidDataSource") //bean的id名(spring容器中资源的名字)
public DataSource createDruidDataSource(){
//创建第三方资源对象
DruidDataSource druidDataSource = new DruidDataSource();
//设置参数
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/db1");
druidDataSource.setUsername("root");
druidDataSource.setPassword("itheima");
//返回对象
return druidDataSource;
}
}
09_IoC的注解配置-bean作用域
目标
- 了解@Scope设置bean作用域的方式
路径
- @Scope注解介绍
- 使用@Scope设置Bean作用域
@Scope注解介绍
@Scope注解:
@Component
@Scope
public class ClassName{
}
- 作用:设置该类作为bean对应的scope属性
- 属性:value ,定义bean的作用域。(默认为singleton)
使用@Scope设置Bean作用域
代码示例:
- Dao层
@Repository("userDao2")
@Scope("singleton") //单例
//@Scope("prototype") //非单例
public class UserDaoImpl2 implements IUserDao {
public UserDaoImpl2(){
System.out.println("UserDaoImpl2构造方法...");
}
/**
* 添加用户
* @param user
*/
@Override
public void addUser(User user) {
System.out.println("UserDao2 => addUser方法");
}
}
- 测试类
public class UserDaoTest3 {
@Test
public void testBeanScope(){
//加载配置类初始化容器
ApplicationContext cxt = new AnnotationConfigApplicationContext(SpringConfig.class);
//从容器中获取对象
IUserDao userDao1 = (IUserDao) cxt.getBean("userDao2");
IUserDao userDao2 = (IUserDao) cxt.getBean("userDao2");
System.out.println(userDao1);
System.out.println(userDao2);
}
}
10_IoC的注解配置-bean生命周期
目标
- 能够使用@PostConstruct、@PreDestroy设置初始化、销毁方法
路径
- 使用@PostConstruct、@PreDestroy设置初始化、销毁方法
@PostConstruct、@PreDestroy注解介绍
@PostConstruct注解:
@Component
public class ClassName{
@PostConstruct
public void init() {
//初始化方法
}
}
@PreDestroy注解:
@Component
public class ClassName{
@PreDestroy
public void destory() {
//销毁方法
}
}
代码示例:
@Repository("userDao2")
@Scope("singleton")
//@Scope("prototype")
public class UserDaoImpl2 implements IUserDao {
public UserDaoImpl2(){
System.out.println("UserDaoImpl2构造方法...");
}
@PostConstruct
public void init(){
System.out.println("UserDaoImpl2 => 初始化方法");
}
@PreDestroy
public void destroy(){
System.out.println("UserDaoImpl2 => 销毁方法");
}
/**
* 添加用户
* @param user
*/
@Override
public void addUser(User user) {
System.out.println("UserDao2 => addUser方法");
}
}
public class UserDaoTest3 {
@Test
public void testBeanScope(){
//加载配置类初始化容器
ApplicationContext cxt = new AnnotationConfigApplicationContext(SpringConfig.class);
//从容器中获取对象
IUserDao userDao1 = (IUserDao) cxt.getBean("userDao2");
IUserDao userDao2 = (IUserDao) cxt.getBean("userDao2");
System.out.println(userDao1);
System.out.println(userDao2);
}
}
11_Spring整合Mybatis
目标
- 能够使用Spring整合Mybatis
路径
- 准备工作
- 使用Spring整合Mybatis
- 优化Spring和Mybatis的整合
我们之前介绍过,spring可以整合其他框架融合自己的体系, 下面我们一起来学习下使用spring整合mybatis
Spring整合Mybatis步骤:
- 创建基于mybatis的项目
- 使用spring的IoC改造mybatis
准备工作
前期准备工作:
- 数据库
- 构造maven项目
- 导入坐标 [Mybatis、Mysql、Druid、Spring]
- Pojo类
- Dao层
- Service层
- 配置文件
- 工具类:SqlSessionUtil
- 数据库:
create database spring_db;
use spring_db;
## 表
create table account(
id int primary key auto_increment,
name varchar(20),
money double
);
## 测试数据
insert into account values(null,'jack',1000),(null,'rose',1000);
- 构造maven项目:
- 导入坐标
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>spring_demo2-mybatis</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- spring依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!--
junit测试框架
-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--
mysql驱动
-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
<!--
Druid
-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.1</version>
</dependency>
<!--
mybatis
-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
</dependencies>
</project>
- Pojo类
public class Account {
private Integer id;
private String name;
private Float money;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Float getMoney() {
return money;
}
public void setMoney(Float money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
- Dao层
public interface AccountDao {
@Insert("insert into account(name,money)values(#{name},#{money})")
void saveAccount(Account account);
@Delete("delete from account where id = #{id} ")
void deleteAccountById(Integer id);
@Update("update account set name = #{name} , money = #{money} where id = #{id} ")
void updateAccount(Account account);
@Select("select id,name,money from account")
List<Account> findAll();
@Select("select id,name,money from account where id = #{id} ")
Account findById(Integer id);
}
- Service层
//接口
public interface IAccountService {
/**
* 添加用户
* @param account
*/
public void saveAccount(Account account);
/**
* 修改用户
* @param account
*/
public void updateAccount(Account account);
/**
* 删除用户
* @param id
*/
public void deleteAccount(Integer id);
/**
* 根据id查询用户
* @param id
* @return
*/
public Account findById(Integer id);
/**
* 查询所有用户
* @return
*/
public List<Account> findAll();
}
//实现类
public class AccountServiceImpl implements IAccountService {
@Override
public void saveAccount(Account account) {
SqlSession session = SqlSessionUtil.getSession();
AccountDao accountDao = session.getMapper(AccountDao.class);
accountDao.saveAccount(account);
session.close();
}
@Override
public void updateAccount(Account account) {
SqlSession session = SqlSessionUtil.getSession();
AccountDao accountDao = session.getMapper(AccountDao.class);
accountDao.updateAccount(account);
session.close();
}
@Override
public void deleteAccount(Integer id) {
SqlSession session = SqlSessionUtil.getSession();
AccountDao accountDao = session.getMapper(AccountDao.class);
accountDao.deleteAccountById(id);
session.close();
}
@Override
public Account findById(Integer id) {
SqlSession session = SqlSessionUtil.getSession();
AccountDao accountDao = session.getMapper(AccountDao.class);
Account account = accountDao.findById(id);
session.close();
return account;
}
@Override
public List<Account> findAll() {
SqlSession session = SqlSessionUtil.getSession();
AccountDao accountDao = session.getMapper(AccountDao.class);
List<Account> list = accountDao.findAll();
session.close();
return list;
}
}
-
配置文件
- 数据库配置
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db jdbc.username=root jdbc.password=itheima
- mybatis配置文件
<?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> <!-- 引入外部资源文件 --> <properties resource="db.properties"/> <typeAliases> <package name="com.itheima.pojo"/> </typeAliases> <environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED"> <property name="driver" 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> </dataSource> </environment> </environments> <mappers> <!-- 指定扫描的包 --> <package name="com.itheima.dao"></package> </mappers> </configuration>
-
工具类
public class SqlSessionUtil {
private static SqlSessionFactory factory;
static {
//实例化工厂建造类
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//读取核心配置文件
try (InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml")) {
//创建工厂对象
factory = builder.build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取会话对象
* @return 会话对象 : 自动提交事务
*/
public static SqlSession getSession() {
return factory.openSession(true);
}
/**
* 获取会话对象
* @param isAutoCommit 是否自动提交事务
*/
public static SqlSession getSession(boolean isAutoCommit) {
return factory.openSession(isAutoCommit);
}
/**
* 提交事务并关闭session
* @param session
*/
public static void commitAndClose(SqlSession session) {
if (session != null) {
session.commit();
session.close();
}
}
/**
* 回滚事务并关闭session
* @param session
*/
public static void rollbackAndClose(SqlSession session) {
if (session != null) {
session.rollback();
session.close();
}
}
}
使用Spring整合Mybatis
spring改造mybatis的步骤:
- 新增mybatis配置类:MybatisConfig
- 新增spring配置类:SpringConfig
- 修改AccountServiceImpl类
- 新增mybatis配置类
//Mybatis配置类
public class MybatisConfig {
//SqlSessionFactoryBuilder -> SqlSessionFactory -> SqlSession -> AccountDao
//将SqlSessionFactory放入到ioc容器
@Bean("factory")
public SqlSessionFactory getFactory() throws IOException {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = builder.build(inputStream);
return factory;
}
//将SqlSession放到ioc容器中
@Bean //在方法上使用@Bean注解时:方法参数列表中声明的对象会自动从ioc容器中获取
public SqlSession getSqlSession(SqlSessionFactory factory){
SqlSession sqlSession = factory.openSession(true);
return sqlSession;
}
//将accountDao放到ioc容器中
@Bean("accountDao") //自动从ioc容器中获取SqlSession类型的bean对象
public AccountDao getDao(SqlSession sqlSession){
AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
return accountDao;
}
}
- 新增spring配置类
@Configuration
@ComponentScan("com.itheima")
@Import(MybatisConfig.class)
public class SpringConfig {
}
- 修改AccountServiceImpl类
@Service("accountService")
public class AccountServiceImpl implements IAccountService {
@Autowired //自动注入
private AccountDao accountDao;
@Override
public void saveAccount(Account account) {
accountDao.saveAccount(account);
}
@Override
public void updateAccount(Account account) {
accountDao.updateAccount(account);
}
@Override
public void deleteAccount(Integer id) {
accountDao.deleteAccountById(id);
}
@Override
public Account findById(Integer id) {
Account account = accountDao.findById(id);
return account;
}
@Override
public List<Account> findAll() {
List<Account> list = accountDao.findAll();
return list;
}
}
测试类:
public class AccountServiceTest {
IAccountService accountService;
@Before
public void init(){
//加载配置类初始化容器
ApplicationContext cxt = new AnnotationConfigApplicationContext(SpringConfig.class);
//从容器中获取对象
accountService = (IAccountService) cxt.getBean("accountService");
}
@Test
public void testFindAccountById(){
Account account = accountService.findById(1);
System.out.println(account);
}
}
优化Spring和Mybatis的整合
优化spring和mybatis整合的步骤:
- 导入坐标
- 修改MybatisConfig类
- 修改SpringConfig类
- 导入坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
- 修改MybatisConfig类
//Mybatis配置类
public class MybatisConfig {
/*
SqlSessionFactoryBean (mybatis的spring整合包提供的类)
1. 底层会提供 SqlSessionFactory
2. 当开发者需要注入dao层bean的,此SqlSessionFactory会自动提供
还可以设置dao层的扫描
*/
@Bean
public SqlSessionFactoryBean getSqlSessionFactoryBean(DataSource ds){
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
//设置pojo的包扫描
//factoryBean.setTypeAliasesPackage("com.itheima.pojo");
//设置连接池
factoryBean.setDataSource(ds);
return factoryBean;
}
//定义bean,返回MapperScannerConfigurer对象(mybatis的spring整合包提供的类)
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
//设置dao层的接口扫描
msc.setBasePackage("com.itheima.dao");
return msc;
}
}
- 修改SpringConfig类
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:db.properties")
@Import(MybatisConfig.class)
public class SpringConfig {
@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
public DataSource getDataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
}
注意:连接池配置不能放在MybatisConfig类中(只有先创建好连接池对象,MybatisConfig类中才能使用)
- 可以放在SpringConfig类中,或者另写一个配置类,但是要保证此配置类先于MybatisConfig加载
12_Spring整合Junit
目标
- 能够使用Spring整合Junit
路径
- 测试类中存在的问题
- 解决问题的思路
- 涉及的知识点介绍
- 使用spring整合junit
测试类中存在的问题
在之前书写的测试类中,每个测试方法都有以下两行代码:
//加载配置初始化容器
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
或
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
//从容器中获取对象
IUserService userService = (IUserService)ac.getBean("userService");
- 这两行代码如果不写的话:直接会提示空指针异常。(所以又不能轻易删掉)
解决问题的思路
解决思路:
- 我们需要程序能自动帮我们创建容器。一旦程序能自动创建spring容器,我们就无须手动创建了,问题也就解决了。
我们都使用过junit,但是junit都无法知晓我们是否使用了spring框架,更不用说帮我们创建spring容器了。不过好在,junit给我们暴露了一个注解,可以让我们替换掉它的运行器。
在spring框架中提供了一个运行器,可以读取配置文件或注解配置类来创建容器。只需要告诉它配置类或配置文件在哪就行了。
涉及的知识点介绍
替换掉Junit的运行器:@RunWith
@RunWith(SpringJUnit4ClassRunner.class)//替换掉junit的运行器,换成可以初始化spring容器的运行器
public class 测试类{
}
加载SpringIoC容器:@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfig.class})//加载配置类
public class 测试类{
}
-
属性:
-
class[] :用来指定配置类
-
value[] :用来指定xml配置文件的路径
@ContextConfiguration(value = {"classpath:bean.xml"})
-
使用spring整合junit
使用spring整合junit的步骤:
- 导入坐标
- 在测试类上添加:@RunWith、@ContextConfiguration
<!-- 引入单元测试的jar包(需要在4.12及以上) -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- 导入Spring整合junit的jar包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.10.RELEASE</version>
<!-- 注意:要保证Spring体系下的jar包的版本号相同 -->
</dependency>
测试类:
@RunWith(SpringJUnit4ClassRunner.class) //SpringJUnit4ClassRunner替代junit原生执行器
@ContextConfiguration(classes= SpringConfig.class) //加载注解配置类
//@ContextConfiguration(value="classpath:applicationContext.xml") //加载xml配置文件
public class AccountTest {
@Autowired //自动装配依赖
IAccountService accountService;
@Test
public void testFindAccountById(){
Account ac = accountService.findById(1);
System.out.println(ac);
}
}
标签:spring,Spring,void,public,user,day02,注解,class
From: https://www.cnblogs.com/-turing/p/17206355.html