(2)pom.xml中添加依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
(3)resources下添加spring的配置文件applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
(4)编写一个运行类App
public class App{
public static void main( String[] args ) {
ApplicationContext ctz = new ClassPathXmlApplicationContext("applicationContext.xml");
}
}
需求:使用Spring的IOC容器来管理Druid连接池对象
1.使用第三方的技术,需要在pom.xml添加依赖
2.在配置文件中将【第三方的类】制作成一个bean,让IOC容器进行管理
3.数据库连接需要基础的四要素驱动
、连接
、用户名
和密码
,【如何注入】到对应的bean中
4.从IOC容器中获取对应的bean对象,将其打印到控制台查看结果
druid
的依赖坐标pom.xml中添加druid
依赖
<--druid数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
在applicationContext.xml配置文件中添加DruidDataSource
的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--管理DruidDataSource对象-->
<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/spring_db"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
</beans>
说明:
public class App{
public static void main( String[] args ) {
ApplicationContext ctz = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource=(DataSource) ctz.getBean("dataSource");
System.out.println(dataSource);
}
}
打印如下结果: 说明第三方bean对象已经被spring的IOC容器进行管理
第三方的类指的是什么?
DruidDataSource
如何注入数据库连接四要素?
setter注入
C3P0
的依赖坐标pom.xml中添加依赖
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
mvn的仓库链接
: https://mvnrepository.com/
在applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--管理DruidDataSource对象-->
<bean class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/spring_db"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_db"></property>
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
</bean>
</beans>
注意:
程序报错
报的错为ClassNotFoundException,翻译出来是类没有发现的异常
,具体的类为com.mysql.jdbc.Driver
。错误的原因是缺少mysql的驱动包。
分析出错误的原因,具体的解决方案就比较简单,只需要在pom.xml把驱动包引入即可。
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db
jdbc.username=root
jdbc.password=123456
<?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
http://www.springframework.org/schema/context/spring-context.xsd"
><!--开辟了一个新的命名空间叫context-->
</beans>
context
命名空间下的标签来加载properties配置文件 <!--2.使用context空间,加载指定的properties文件-->
<context:property-placeholder location="jdbc.properties"></context:property-placeholder>
4.使用属性占位符${}读取properties文件中的属性值
使用${key}
来读取properties配置文件中的内容并完成属性注入
<property name="name" value="${jdbc.driver}"></property>
<?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
http://www.springframework.org/schema/context/spring-context.xsd"
><!--开辟了一个新的命名空间叫context-->
<!--1.开启context命名空间-->
<!--2.使用context空间,加载指定的properties文件-->
<context:property-placeholder location="jdbc.properties"></context:property-placeholder>
<!--3.使用属性占位符${}读取properties文件中的属性-->
<bean 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>
<bean id="bookDao" class="com.itcast.dao.impl.BookDaoImpl">
<property name="name" value="${jdbc.driver}"></property>
</bean>
</beans>
需求:从properties配置文件中读取key为name的值,并将其注入到BookDao中并在save方法中进行打印。
1.在项目中添加BookDao和BookDaoImpl类
2.为BookDaoImpl添加一个name属性并提供setter方法
3.在jdbc.properties中添加数据注入到bookDao中打印方便查询结果
4.在applicationContext.xml添加配置完成配置文件加载、属性注入(${key})
BookDao和BookDaoImpl类,并在BookDaoImpl类中添加name
属性与setter方法
public class BookDaoImpl implements BookDao {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public void save() {
System.out.println("book dao save ..." + name);
}
}
在applicationContext.xml添加配置,bean的配置管理
、读取外部properties
、依赖注入
:
<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
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="jdbc.properties"/>
<bean id="bookDao" class="com.itcast.dao.impl.BookDaoImpl">
<property name="name" value="${jdbc.driver}"/>
bean>
beans>
在App类中,从IOC容器中获取bookDao对象,调用方法,查看值是否已经被获取到并打印控制台
public class App {
public static void main(String[] args) throws Exception{
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
至此,读取properties配置文件中的内容就已经完成,但是在使用的时候,有些注意事项:
问题一:键值对的key为username
引发的问题
1.在properties中配置键值对的时候,如果key设置为username
username=root666
2.在applicationContext.xml注入该属性
<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
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="jdbc.properties"/>
<bean id="bookDao" class="com.itcast.dao.impl.BookDaoImpl">
<property name="name" value="${username}"/>
bean>
beans>
3.运行后,在控制台打印的却不是root666
,而是自己电脑的用户名
4.出现问题的原因是
标签会加载系统的环境变量,而且环境变量的值会被优先加载,如何查看系统的环境变量?
public static void main(String[] args) throws Exception{
Map<String, String> env = System.getenv();
System.out.println(env);
}
5.解决方案
<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
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
beans>
system-properties-mode:设置为NEVER,表示不加载系统属性,解决上述问题。
当然还有一个解决方案就是避免使用username
作为属性的key
。
问题二:当有多个properties配置文件需要被加载,该如何配置?
1.调整下配置文件的内容,在resources下添加jdbc.properties
,jdbc2.properties
,内容如下:
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=123456
jdbc2.properties
username=root666
2.修改applicationContext.xml
<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
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="jdbc.properties,jdbc2.properties" system-properties-mode="NEVER"/>
<context:property-placeholder location="*.properties" system-properties-mode="NEVER"/>
<context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"/>
<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>
beans>
说明:
*.properties
代表所有以properties结尾的文件都会被加载,可以解决方式一的问题,但是不标准classpath:
代表的是从根路径下开始查找,但是只能查询当前项目的根路径如何加载properties配置文件
<context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER">context:property-placeholder>
如何在applicationContext.xml引入properties配置文件中的值
${key}
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="bookDao" class="com.itcast.dao.impl.BookDaoImpl"></bean>
</beans>
public interface BookDao {
public void say();
}
public class BookDaoImpl implements BookDao {
@Override
public void say() {
System.out.println("book dao say ...");
}
}
public class App {
public static void main( String[] args ) {
ApplicationContext ctz = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctz.getBean("bookDao");
bookDao.say();
}
}
案例中创建ApplicationContext
的方式为:
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
这种方式翻译为:类路径下的XML配置文件
除了上面这种方式,Spring还提供了另外一种创建方式为:
ApplicationContext ctx = new FileSystemXmlApplicationContext("applicationContext.xml");
这种方式翻译为:文件系统下的XML配置文件
运行报错:
从错误信息中能发现,这种方式是从项目路径下开始查找applicationContext.xml
配置文件的,所以需要将其修改为:
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\code\springmvc_ssm_study01\spring_10_container\src\main\resources\applicationContext.xml");
说明:使用绝对路径
。这种方式虽能实现,但是当项目的位置发生变化后,代码也需要跟着改,耦合度较高
,不推荐使用。
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
这种方式存在的问题是每次获取的时候都需要进行类型转换
;
方式二:
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
这种方式可以解决类型强转问题,但是参数又多加了一个,相对来说没有简化多少。
方式三:
BookDao bookDao = ctx.getBean(BookDao.class);
这种方式就类似我们之前所学习依赖注入中的按类型注入。必须要确保IOC容器中该类型对应的bean对象只能有一个。
(1)在IDEA中双击shift
,输入BeanFactory
(2)点击进入BeanFactory类,ctrl+h,就能查看到如下结构的层次关系
容器类从无到有根据需要一层层叠加上来的,重点理解设计思想。
使用BeanFactory来创建IOC容器的具体实现方式:
public class AppForBeanFactory {
public static void main(String[] args) {
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resource);
BookDao bookDao = bf.getBean(BookDao.class);
bookDao.say();
}
}
为了更好的看出BeanFactory
和ApplicationContext
之间的区别,在BookDaoImpl添加如下构造函数:
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("constructor ....");
}
@Override
public void say() {
System.out.println("book dao say ...");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="bookDao" class="com.itcast.dao.impl.BookDaoImpl" lazy-init="true"></bean>
</beans>
容器创建的两种方式
获取Bean的三种方式
容器类层次结构
BeanFactory
BeanFactory
是IoC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载
ApplicationContext
接口是Spring容器的核心接口,初始化时bean立即加载
bean操作相关方法
,通过其他接口扩展其功能 <dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao" class="com.itcast.dao.impl.BookDaoImpl"></bean>
</beans>
public interface BookDao {
public void say();
}
public class BookDaoImpl implements BookDao {
@Override
public void say() {
System.out.println("book dao say ...");
}
}
public interface BookService {
public void say();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
@Override
public void say() {
System.out.println("book service say ...");
}
}
public class App {
public static void main( String[] args ) {
ApplicationContext ctz = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = ctz.getBean("bookDao",BookDao.class);
bookDao.say();
}
}
将配置文件中的
标签删除掉
<bean id="bookDao" class="com.itcast.dao.impl.BookDaoImpl"></bean>
在BookDaoImpl类上添加@Component
注解
@Component("bookDao")
public class BookDaoImpl implements BookDao {
@Override
public void say() {
System.out.println("book dao say ...");
}
}
注意:@Component注解不可以添加在接口上,因为接口是无法创建对象的。
为了让Spring框架能够扫描到写在类上的注解,需要在配置文件上进行包扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<!--开启Spring的注解包扫描-->
<context:component-scan base-package="com.itcast"></context:component-scan>
</beans>
说明:
component-scan
base-package指定Spring框架扫描的包路径,它会扫描指定包及其子包中的所有类上的注解。
在BookServiceImpl类上也添加@Component
交给Spring框架管理
@Component
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
@Override
public void say() {
System.out.println("book service say ...");
}
}
public class App {
public static void main( String[] args ) {
ApplicationContext ctz = new ClassPathXmlApplicationContext("applicationContext.xml");
//按名称获取bean对象
BookDao bookDao = (BookDao) ctz.getBean("bookDao");
System.out.println(bookDao);
//按类型获取bean对象
BookService bookService = ctz.getBean(BookService.class);
System.out.println(bookService);
}
}
BookServiceImpl类没有起名称,所以在App中是按照类型来获取bean对象
@Component注解如果不起名称,会有一个默认值就是当前类名首字母小写
,所以也可以按照名称获取,如
BookService bookService = (BookService)ctx.getBean("bookServiceImpl");
System.out.println(bookService);
对于@Component注解,还衍生出了其他三个注解@Controller
、@Service
、@Repository
通过查看源码会发现:
这三个注解和@Component注解的作用是一样的,为什么要衍生出这三个呢?
方便我们后期在编写类的时候能很好的区分出这个类是属于表现层
、业务层
还是数据层
的类。
名称 | @Component/@Controller/@Service/@Repository |
---|---|
类型 | 类注解 |
位置 | 类定义上方 |
作用 | 设置该类为spring管理的bean |
属性 | value(默认):定义bean的id |
Spring3.0
开启了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道
SpringConfig
public class SpringConfig {
}
在配置类上添加@Configuration
注解,将其标识为一个配置类,替换applicationContext.xml
@Configuration
public class SpringConfig {
}
在配置类上添加包扫描注解@ComponentScan
替换
//配置类
@Configuration
@ComponentScan("com.itcast")
public class SpringConfig {
}
AppForAnnotation
并运行public class AppForAnnotation {
public static void main( String[] args ) {
//注解开发,注解配置,加载配置类
ApplicationContext ctz = new AnnotationConfigApplicationContext(SpringConfig.class);
//按名称获取bean对象
BookDao bookDao = (BookDao) ctz.getBean("bookDao");
System.out.println(bookDao);
//按类型获取bean对象
BookService bookService = ctz.getBean(BookService.class);
System.out.println(bookService);
}
}
运行AppForAnnotation,可以看到两个对象依然被获取成功
@ComponentScan({com.itheima.service","com.itheima.dao"})
//加载配置文件初始化容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//加载配置类初始化容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
名称 | @Configuration |
---|---|
类型 | 类注解 |
位置 | 类定义上方 |
作用 | 设置该类为spring配置类 |
属性 | value(默认):定义bean的id |
名称 | @ComponentScan |
---|---|
类型 | 类注解 |
位置 | 类定义上方 |
作用 | 设置spring配置类扫描路径,用于加载使用注解格式定义的bean |
属性 | value(默认):扫描路径,此路径可以逐层向下扫描 |
小结:
使用注解完成Spring的bean管理
的作用是指定扫描包路径,注解为@ComponentScan创建一个Maven项目
pom.xml添加Spring的依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
SpringConfig
@Configuration
@ComponentScan({"com.itcast"})
public class SpringConfig {
}
public interface BookDao {
public void say();
}
@Repository
public class BookDaoImpl implements BookDao {
@Override
public void say() {
System.out.println("book dao say ...");
}
}
public class App {
public static void main( String[] args ) {
ApplicationContext ctz = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao1 = ctz.getBean(BookDao.class);
BookDao bookDao2 = ctz.getBean(BookDao.class);
System.out.println(bookDao1);
System.out.println(bookDao2);
}
}
(1)先运行App类,在控制台打印两个一摸一样的地址,说明默认情况下bean是单例
(2)要想将BookDaoImpl变成非单例,只需要在其类上添加@scope
注解
@Repository
//@Scope设置bean的作用范围
//@Scope("singleton")//单例
@Scope("prototype")//非单例
public class BookDaoImpl implements BookDao {
@Override
public void say() {
System.out.println("book dao say ...");
}
}
再次执行App类,打印结果:
名称 | @Scope |
---|---|
类型 | 类注解 |
位置 | 类定义上方 |
作用 | 设置该类创建对象的作用范围 可用于设置创建出的bean是否为单例对象 |
属性 | value(默认):定义bean作用范围, 默认值singleton(单例),可选值prototype(非单例) |
(1)在BookDaoImpl中添加两个方法,init
和destroy
@Repository
//@Scope设置bean的作用范围
@Scope("singleton")//单例
//@Scope("prototype")//非单例
public class BookDaoImpl implements BookDao {
@Override
public void say() {
System.out.println("book dao say ...");
}
public void init() {
System.out.println("init ... 构造方法后");
}
public void destroy() {
System.out.println("destroy ... 销毁前");
}
}
(2)如何标识,哪个是初始化方法,哪个是销毁方法?
需要在对应的方法上添加@PostConstruct
和@PreDestroy
注解。
@Repository
//@Scope设置bean的作用范围
@Scope("singleton")//单例
//@Scope("prototype")//非单例
public class BookDaoImpl implements BookDao {
@Override
public void say() {
System.out.println("book dao say ...");
}
@PostConstruct //在构造方法之后执行,替换 init-method
public void init() {
System.out.println("init ... 构造方法后");
}
@PreDestroy //在销毁方法之前执行,替换 destroy-method
public void destroy() {
System.out.println("destroy ... 销毁前");
}
}
(3)要想看到两个方法执行,需要注意的是destroy
只有在容器关闭的时候,才会执行,所以需要修改App的类
public class App {
public static void main( String[] args ) {
AnnotationConfigApplicationContext ctz = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao1 = ctz.getBean(BookDao.class);
BookDao bookDao2 = ctz.getBean(BookDao.class);
System.out.println(bookDao1);
System.out.println(bookDao2);
ctz.close(); //关闭容器
}
}
(4)运行App,类查看打印结果,证明init和destroy方法都被执行了。
注意:@PostConstruct和@PreDestroy注解如果找不到,需要导入下面的jar包
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
找不到的原因是,从JDK9以后jdk中的javax.annotation包被移除了,这两个注解刚好就在这个包中。
名称 | @PostConstruct |
---|---|
类型 | 方法注解 |
位置 | 方法上 |
作用 | 设置该方法为初始化方法 |
属性 | 无 |
名称 | @PreDestroy |
---|---|
类型 | 方法注解 |
位置 | 方法上 |
作用 | 设置该方法为销毁方法 |
属性 | 无 |
Spring为了使用注解简化开发,并没有提供构造函数注入
、setter注入
对应的注解,只提供了自动装配的注解实现。
创建一个Maven项目
pom.xml添加Spring的依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
SpringConfig
@Configuration
@ComponentScan({"com.itcast"})
public class SpringConfig {
}
public interface BookDao {
public void say();
}
@Repository
public class BookDaoImpl implements BookDao {
@Override
public void say() {
System.out.println("book dao say ...");
}
}
public interface BookService {
public void say();
}
@Service
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
@Override
public void say() {
System.out.println("book service say ...");
bookDao.say();
}
}
public class App {
public static void main( String[] args ) {
AnnotationConfigApplicationContext ctz = new AnnotationConfigApplicationContext(SpringConfig.class);
BookService bookService = ctz.getBean(BookService.class);
bookService.say();
}
}
最终创建好的项目结构如下:
出现问题的原因是,在BookServiceImpl类中添加了BookDao的属性,并提供了setter方法,但是目前是没有提供配置注入BookDao的,所以bookDao对象为Null,调用其save方法就会报控指针异常
。
@Autowired
对于这个问题使用注解该如何解决?
(1) 在BookServiceImpl类的bookDao属性上添加@Autowired
注解
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
// public void setBookDao(BookDao bookDao) {
// this.bookDao = bookDao;
// }
public void say() {
System.out.println("book service say ...");
bookDao.say();
}
}
注意:
写在属性上并将setter方法删除掉
(2) @Autowired是按照类型注入,那么对应BookDao接口如果有多个实现类,比如添加BookDaoImpl2
@Repository
public class BookDaoImpl2 implements BookDao {
@Override
public void say() {
System.out.println("book dao say ...");
}
}
这个时候再次运行App,就会报错
此时,按照类型注入就无法区分到底注入哪个对象,解决方案:按照名称注入
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
@Override
public void say() {
System.out.println("book dao say ... bookDao");
}
}
@Repository("bookDao2")
public class BookDaoImpl2 implements BookDao {
@Override
public void say() {
System.out.println("book dao say ... bookDao2");
}
}
此时就可以注入成功,但是得思考个问题:
@Autowired是按照类型注入的,给BookDao的两个实现起了名称,它还是有两个bean对象,为什么不报错?
@Autowired默认按照类型自动装配,如果IOC容器中同类的Bean找到多个,就按照变量名和Bean的名称匹配。因为变量名叫bookDao
而容器中也有一个booDao
,所以可以成功注入。
分析下面这种情况是否能完成注入呢?
bookDao
名称去找,因为IOC容器只有名称叫bookDao1
和bookDao2
,所以找不到,会报NoUniqueBeanDefinitionException
@Qualifier
当根据类型在容器中找到多个bean,注入参数的属性名又和容器中bean的名称不一致,这个时候该如何解决,就需要使用到@Qualifier
来指定注入哪个名称的bean对象。
@Service
public class BookServiceImpl implements BookService {
@Autowired
@Qualifier("bookDao2")
private BookDao bookDao;
@Override
public void say() {
System.out.println("book service say ... bookDao");
bookDao.say();
}
}
@Qualifier注解后的值就是需要注入的bean的名称。
注意:@Qualifier不能独立使用,必须和@Autowired一起使用
@Value
引用类型看完,简单类型注入就比较容易懂了。简单类型注入的是基本数据类型或者字符串类型,下面在BookDaoImpl
类中添加一个name
属性,用其进行简单类型注入
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
private String name;
private int age;
@Override
public void say() {
System.out.println("book dao say ... : \n" + name + "今年" + age + "岁");
}
}
数据类型换了,对应的注解也要跟着换,这次使用@Value
注解,将值写入注解的参数中就行了
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
@Value("刘亦菲")
private String name;
@Value("18")
private int age;
@Override
public void say() {
System.out.println("book dao say ... : \n" + name + "今年" + age + "岁");
}
}
注意数据格式要匹配
@PropertySource
—@Value("${name}")
@Value
一般会被用在从properties配置文件中读取内容进行使用,具体如何实现?
jdbc.properties
name=root
在配置类上添加@PropertySource
注解
@Configuration
@ComponentScan({"com.itcast"})
//@PropertySource("jdbc.properties")//属性源
@PropertySource({"jdbc.properties"})//属性源
public class SpringConfig {
}
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
@Value("${name}")
private String name;
@Value("18")
private int age;
@Override
public void say() {
System.out.println("book dao say ... : \n" + name + "今年" + age + "岁");
}
}
步骤4:运行程序
运行App类,查看运行结果,说明配置文件中的内容已经被加载到
注意:
如果读取的properties配置文件有多个,可以使用@PropertySource
的属性来指定多个
@PropertySource({"jdbc.properties","xxx.properties"})
@PropertySource
注解属性中不支持使用通配符*
,运行会报错
@PropertySource({"*.properties"})
@PropertySource
注解属性中可以把classpath:
加上,代表从当前项目的根路径找文件
@PropertySource({"classpath:jdbc.properties"})
名称 | @Autowired |
---|---|
类型 | 属性注解 或 方法注解(了解) 或 方法形参注解(了解) |
位置 | 属性定义上方 或 标准set方法上方 或 类set方法上方 或 方法形参前面 |
作用 | 为引用类型属性设置值 |
属性 | required:true/false,定义该属性是否允许为null |
名称 | @Qualifier |
---|---|
类型 | 属性注解 或 方法注解(了解) |
位置 | 属性定义上方 或 标准set方法上方 或 类set方法上方 |
作用 | 为引用类型属性指定注入的beanId |
属性 | value(默认):设置注入的beanId |
名称 | @Value |
---|---|
类型 | 属性注解 或 方法注解(了解) |
位置 | 属性定义上方 或 标准set方法上方 或 类set方法上方 |
作用 | 为 基本数据类型 或 字符串类型 属性设置值 |
属性 | value(默认):要注入的属性值 |
名称 | @PropertySource |
---|---|
类型 | 类注解 |
位置 | 类定义上方 |
作用 | 加载properties文件中的属性值 |
属性 | value(默认):设置加载的properties文件对应的文件名或文件名组成的数组 |
创建一个Maven项目
pom.xml添加Spring的依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
SpringConfig
@Configuration
public class SpringConfig {
}
public interface BookDao {
public void say();
}
@Repository
public class BookDaoImpl implements BookDao {
@Override
public void say() {
System.out.println("book dao say ...");
}
}
public class App {
public static void main( String[] args ) {
AnnotationConfigApplicationContext ctz = new AnnotationConfigApplicationContext(SpringConfig.class);
}
}
在上述环境中完成对Druid
数据源的管理,具体的实现步骤为:
<!--导入druid数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
注意该方法的返回值就是要创建的Bean对象
类型
@Configuration
public class SpringConfig {
//1.定义一个方法获得要管理的对象
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("123456");
return ds;
}
}
@Bean
注解@Bean注解的作用是将方法的返回值制作为Spring管理的一个bean对象
@Configuration
public class SpringConfig {
//1.定义一个方法获得要管理的对象
//2.添加@Bean,表示当前方法的返回值是一个bean
//@Bean("dataSource")
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("123456");
return ds;
}
}
注意:不能使用DataSource ds = new DruidDataSource()
因为DataSource接口中没有对应的setter方法来设置属性。
public class App {
public static void main( String[] args ) {
AnnotationConfigApplicationContext ctz = new AnnotationConfigApplicationContext(SpringConfig.class);
DataSource dataSource = ctz.getBean(DataSource.class);
System.out.println("dataSource = " + dataSource);
}
}
至此使用@Bean来管理第三方bean的案例就已经完成。
如果有多个bean要被Spring管理,直接在配置类中多些几个方法,方法上添加@Bean注解即可。
如果把所有的第三方bean都配置到Spring的配置类SpringConfig
中,虽然可以,但是不利于代码阅读和分类管理,所有我们就想能不能按照类别将这些bean配置到不同的配置类中?
对于数据源的bean,我们新建一个JdbcConfig
配置类,并把数据源配置到该类下。
@Configuration
public class JdbcConfig {
//1.定义一个方法获得要管理的对象
//2.添加@Bean,表示当前方法的返回值是一个bean
//@Bean("dataSource")
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("123456");
return ds;
}
}
现在的问题是,这个配置类如何能被Spring配置类加载到,并创建DataSource对象在IOC容器中?
针对这个问题,有两个解决方案:
@Configuration
@ComponentScan("com.itcast.config")
public class SpringConfig {
}
JdbcConfig类要放入到com.itcast.config
包下,需要被Spring的配置类扫描到即可
@Configuration
public class JdbcConfig {
//1.定义一个方法获得要管理的对象
//2.添加@Bean,表示当前方法的返回值是一个bean
//@Bean("dataSource")
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("123456");
return ds;
}
}
依然能获取到bean对象并打印控制台。
这种方式虽然能够扫描到,但是不能很快的知晓都引入了哪些配置类,所有这种方式不推荐使用
。
@Import
引入这种方案可以不用加@Configuration
注解,但是必须在Spring配置类上使用@Import
注解手动引入需要加载的配置类
//@Configuration
public class JdbcConfig {
//1.定义一个方法获得要管理的对象
//2.添加@Bean,表示当前方法的返回值是一个bean
//@Bean("dataSource")
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("123456");
return ds;
}
}
@Configuration
//@ComponentScan("com.itcast.config")
//@Import({JdbcConfig.class})
@Import(JdbcConfig.class)
public class SpringConfig {
}
注意:
扫描注解可以移除
@Import参数需要的是一个数组,可以引入多个配置类。
@Import注解在配置类中只能写一次,下面的方式是不允许的
@Configuration
//@ComponentScan("com.itcast.config")
@Import(JdbcConfig.class)
@Import(Xxx.class)
public class SpringConfig {
}
依然能获取到bean对象并打印控制台
名称 | @Bean |
---|---|
类型 | 方法注解 |
位置 | 方法定义上方 |
作用 | 设置该方法的返回值作为spring管理的bean |
属性 | value(默认):定义bean的id |
名称 | @Import |
---|---|
类型 | 类注解 |
位置 | 类定义上方 |
作用 | 导入配置类 |
属性 | value(默认):定义导入的配置类类名, 当配置类有多个时使用数组格式一次性导入多个配置类 |
对于下面代码关于数据库的四要素不应该写死在代码中,应该是从properties配置文件中读取。如何来优化下面的代码?
//@Configuration
public class JdbcConfig {
//1.定义一个方法获得要管理的对象
//2.添加@Bean,表示当前方法的返回值是一个bean
//@Bean("dataSource")
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("123456");
return ds;
}
}
public class JdbcConfig {
private String driver;
private String url;
private String userName;
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("123456");
return ds;
}
}
@Value
注解引入值//@Configuration
public class JdbcConfig {
@Value("com.mysql.jdbc.Driver")
private String driver;
@Value("jdbc:mysql://localhost:3306/spring_db")
private String url;
@Value("root")
private String userName;
@Value("123456")
private String passWord;
//1.定义一个方法获得要管理的对象
//2.添加@Bean,表示当前方法的返回值是一个bean
//@Bean("dataSource")
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(passWord);
return ds;
}
}
现在的数据库连接四要素还是写在代码中,需要做的是将这些内容提
取到jdbc.properties配置文件,大家思考下该如何实现?
1.resources目录下添加jdbc.properties
2.配置文件中提供四个键值对分别是数据库的四要素
3.使用@PropertySource加载jdbc.properties配置文件
4.修改@Value注解属性的值,将其修改为
${key}
,key就是键值对中的键的值
假设在构建DataSource对象的时候,需要用到BookDao对象,该如何把BookDao对象注入进方法内让其使用呢?
//@Configuration
public class JdbcConfig {
@Value("com.mysql.jdbc.Driver")
private String driver;
@Value("jdbc:mysql://localhost:3306/spring_db")
private String url;
@Value("root")
private String userName;
@Value("123456")
private String passWord;
//1.定义一个方法获得要管理的对象
//2.添加@Bean,表示当前方法的返回值是一个bean
//@Bean("dataSource")
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(passWord);
return ds;
}
}
扫描的目的是让Spring能管理到BookDao,也就是说要让IOC容器中有一个bookDao对象
@Configuration
@ComponentScan("com.itcast")
//@Import({JdbcConfig.class})
@Import(JdbcConfig.class)
public class SpringConfig {
}
//@Configuration
public class JdbcConfig {
@Value("com.mysql.jdbc.Driver")
private String driver;
@Value("jdbc:mysql://localhost:3306/spring_db")
private String url;
@Value("root")
private String userName;
@Value("123456")
private String passWord;
//1.定义一个方法获得要管理的对象
//2.添加@Bean,表示当前方法的返回值是一个bean
//@Bean("dataSource")
@Bean
public DataSource dataSource(BookDao bookDao) {
System.out.println(bookDao);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(passWord);
return ds;
}
}
引用类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装配对象。
create database spring_db character set utf8;
use spring_db;
create table tbl_account(
id int primary key auto_increment,
name varchar(35),
money double
);
insert into tbl_account(name, money) VALUES
('Tom',1000),('Jerry',500);
项目的pom.xml添加相关依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
public class Account implements Serializable {
private Integer id;
private String name;
private Double money;
//setter...getter...toString...方法略
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 Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "AccountDao{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
public interface AccountDao{
@Insert("insert into tbl_account(name,money)values(#{name},#{money})")
void save(Account account);
@Delete("delete from tbl_account where id = #{id}")
void delete(Integer id);
@Update("update tbl_account set name = #{name},money = #{money} where id = #{id}")
void update(Account account);
@Select("select * from tbl_account")
List<Account> findAll();
@Select("select * from tbl_account where id = #{id}")
Account findById(Integer id);
}
public interface AccountService {
void save(Account account);
void delete(Integer id);
void update(Account account);
List<Account> findAll();
Account findById(Integer id);
}
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public void save(Account account) {
accountDao.save(account);
}
@Override
public void delete(Integer id) {
accountDao.delete(id);
}
@Override
public void update(Account account) {
accountDao.update(account);
}
@Override
public List<Account> findAll() {
return accountDao.findAll();
}
@Override
public Account findById(Integer id) {
return accountDao.findById(id);
}
}
resources目录下添加,用于配置数据库连接四要素
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db?useSSL=false
jdbc.username=root
jdbc.password=123456
useSSL:关闭MySQL的SSL连接
<?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配置文件-->
<properties resource="jdbc.properties"></properties>
<!--别名扫描的包路径-->
<typeAliases>
<package name="com.itcast.domain"/>
</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.itcast.dao"></package>
</mappers>
</configuration>
public class App {
public static void main( String[] args ) throws IOException {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2. 加载SqlMapConfig.xml配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
// 4. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 执行SqlSession对象执行查询,获取结果User
AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
Account ac = accountDao.findById(1);
System.out.println(ac);
// 6. 释放资源
sqlSession.close();
}
}
Mybatis的基础环境我们已经准备好了,接下来就得分析下在上述的内容中,哪些对象可以交给Spring来管理?
说明 :
读取
外部properties配置文件
,Spring有提供具体的解决方案@PropertySource
,需要交给Spring起别名
包扫描,为SqlSessionFactory服务的,需要交给Spring连接池
,Spring之前我们已经整合了Druid连接池
,这块也需要交给Spring[如果使用注解就没有该映射文件]
,这个是在获取到SqlSession以后执行具体操作的时候用,所以它和SqlSessionFactory创建的时机都不在同一个时间,可能需要单独管理。前面我们已经分析了Spring与Mybatis的整合,大体需要做两件事,
第一件事是:Spring要管理MyBatis中的SqlSessionFactory
第二件事是:Spring要管理Mapper接口的扫描
具体该如何实现,具体的步骤为:
<dependency>
<!--Spring操作数据库需要该jar包-->
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<dependency>
<!--
Spring与Mybatis整合的jar包
这个jar包mybatis在前面,是Mybatis提供的
-->
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
//配置类注解
@Configuration
//包扫描,主要扫描的是项目中的AccountServiceImpl类
@ComponentScan("com.itcast")
public class SpringConfig {
}
在配置类中完成数据源的创建
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
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
}
//配置类注解
@Configuration
//包扫描,主要扫描的是项目中的AccountServiceImpl类
@ComponentScan("com.itcast")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class})
public class SpringConfig {
}
public class MybatisConfig {
//定义bean,SqlSessionFactoryBean,用于产生SqlSessionFactory对象
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
//设置模型类的别名扫描
ssfb.setTypeAliasesPackage("com.itcast.domain");
//设置数据源
ssfb.setDataSource(dataSource);
return ssfb;
}
//定义bean,返回MapperScannerConfigurer对象
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.itcast.dao");
return msc;
}
说明:
SqlSessionFactoryBean是前面我们讲解FactoryBean的一个子类,在该类中将SqlSessionFactory的创建进行了封装,简化对象的创建,我们只需要将其需要的内容设置即可。
方法中有一个参数为dataSource,当前Spring容器中已经创建了Druid数据源,类型刚好是DataSource类型,此时在初始化SqlSessionFactoryBean这个对象的时候,发现需要使用DataSource对象,而容器中刚好有这么一个对象,就自动加载了DruidDataSource对象。
使用MapperScannerConfigurer加载Dao接口,创建代理对象保存到IOC容器中
//配置类注解
@Configuration
//包扫描,主要扫描的是项目中的AccountServiceImpl类
@ComponentScan("com.itcast")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
public class SpringConfig {
}
在运行类中,从IOC容器中获取Service对象,调用方法获取结果
//SqlMapConfig.xml文件删除,新建一个运行类
public class App2 {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
AccountService accountService = ctx.getBean(AccountService.class);
Account ac = accountService.findById(1);
System.out.println(ac);
}
}
支持Spring与Mybatis的整合就已经完成了,其中主要用到的两个类分别是:
pom.xml
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
在test\java下创建一个AccountServiceTest,这个名字任意
//设置类运行器
@RunWith(SpringJUnit4ClassRunner.class)
//设置Spring环境对应的配置类
@ContextConfiguration(classes = {SpringConfig.class}) //加载配置类
//@ContextConfiguration(locations={"classpath:applicationContext.xml"})//加载配置文件
public class AccountServiceTest {
//支持自动装配注入bean
@Autowired
private AccountService accountService;
@Test
public void testFindById(){
System.out.println(accountService.findById(1));
}
@Test
public void testFindAll(){
System.out.println(accountService.findAll());
}
}
注意:
@ContextConfiguration(classes = 配置类.class)
@ContextConfiguration(locations={配置文件名,...})
SpringJUnit4ClassRunner
名称 | @RunWith |
---|---|
类型 | 测试类注解 |
位置 | 测试类定义上方 |
作用 | 设置JUnit运行器 |
属性 | value(默认):运行所使用的运行期 |
名称 | @ContextConfiguration |
---|---|
类型 | 测试类注解 |
位置 | 测试类定义上方 |
作用 | 设置JUnit加载的Spring核心配置 |
属性 | classes:核心配置类,可以使用数组的格式设定加载多个配置类 locations:配置文件,可以使用数组的格式设定加载多个配置文件名称 |