Spring学习笔记 - 第二章 - 注解开发、配置管理第三方Bean、注解管理第三方Bean、Spring 整合 MyBatis 和 Junit 案例
Spring 学习笔记全系列传送门:
1、IoC/DI 配置管理第三方bean
本节内容的主要内容是:如果有需求让我们去管理第三方jar包中的类,该如何管理
1.1 案例:数据源对象管理
1.1.1 环境准备
pom.xml 中添加依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"> </beans>
运行类 App
package priv.dandelion; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
}
}
1.1.2 思路分析
注意:思路 中加粗部分,如何理解、如何做?
- 第三方类:DuridDataSource
- 如何注入:setter注入
- 需求:使用 Spring 的 IoC 容器管理 Druid 连接池对象
- 思路
- 使用第三方技术,需要在 pom.xml 中添加依赖
- 在配置文件中将第三方的类制作成一个Bean,让 IoC 容器进行管理
- 数据库连接需要基础的四要素
驱动
、连接
、用户名
和密码
,如何注入到对应的bean中 - 从IOC容器中获取对应的bean对象,将其打印到控制台查看结果
1.1.3 实现 Druid 管理
导入
druid
的依赖在 Spring 配置文件中配置第三方 bean
<!-- 管理 DuridDataSource 对象 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!-- 通过查询 DruidDataSource 具体实现发现需要使用 setter 注入 -->
<property name="driverClassName" value="com.mysql.jdbc.driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring_db"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
从 IOC 容器中获取对应的 bean 对象
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource) ctx.getBean("dataSource");
System.out.println(dataSource);
}
}
1.1.4 实现 C3P0 管理
注意:
- 数据连接池在配置属性的时候,除了可以注入数据库连接四要素外还可以配置很多其他的属性,具体都有哪些属性用到的时候再去查,一般配置基础的四个,其他都有自己的默认值
- Druid和C3P0在没有导入mysql驱动包的前提下,一个没报错一个报错,说明Druid在初始化的时候没有去加载驱动,而C3P0刚好相反
- Druid程序运行虽然没有报错,但是当调用DruidDataSource的getConnection()方法获取连接的时候,也会报找不到驱动类的错误
添加依赖
可从mvn的仓库
https://mvnrepository.com/
中进行搜索<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
配置第三方Bean
<bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_db"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
</bean>
到上面为止运行时会报错,因为必须依赖mysql驱动
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
1.2 加载 properties 文件
1.2.1 实现步骤
开启 context 命名空间
<?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 命名空间,加载指定的 properties 文件
- system-properties-mode="NEVER" 不加载系统环境变量,防止username冲突
- 多个配置文件的加载使用
,
隔开(非规范方式) - 多个配置文件的加载也可以使用
classpath:*.properties
(规范格式,但仅限于当前项目的 properties 文件) classpath*:*.properties
(规范格式,包含当前项目和所导入的 jar 包中的 properties 文件,推荐使用)
<!-- system-properties-mode="NEVER" 不加载系统环境变量,防止username冲突 -->
<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>
使用属性占位符
${}
读取加载的属性值<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>
1.2.2 完整代码
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
http://www.springframework.org/schema/context/spring-context.xsd"> <!--
管理 DuridDataSource 对象
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring_db"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
-->
<!-- system-properties-mode="NEVER" 不加载系统环境变量,防止username冲突 -->
<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>
<!-- 使用 properties 管理 DuridDataSource 对象 -->
<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> </beans>
Properties 文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=123456
2、核心容器
2.1 环境准备
依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
BookDao
仅
save()
方法,细节不表配置文件
<?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="priv.dandelion.dao.impl.BookDaoImpl"/>
</beans>
运行类
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
2.2 容器
2.2.1 容器的创建方式
加载类路径下的配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
从文件系统下加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext("绝对路径");
加载类路径下的多个配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("xml1.xml", "xml2.xml");
2.2.2 Bean 的三种获取方式
强转
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
将类型作为参数
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
按类型获取(类似依赖注入的按类型注入)
BookDao bookDao = ctx.getBean(BookDao.class);
2.2.3 BeanFactory 的使用与延迟加载
2.2.3.1 BeanFactory
使用 BeanFactory 来创建 IOC 容器的具体实现方式
public class AppForBeanFactory {
public static void main(String[] args) {
Resource resources = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resources);
BookDao bookDao = bf.getBean(BookDao.class);
bookDao.save();
}
}
2.2.3.2 延迟加载
可尝试手动实现 BookDao 的构造方法并输出内容,运行 ApplicationContext 和 BeanFactory 对比结果
BeanFactory 是延迟加载,只有在获取 bean 对象的时候才会去创建
ApplicationContext 是立即加载,容器加载的时候就会创建 bean 对象
ApplicationContext 要想成为延迟加载,只需要在配置文件中按照如下方式进行配置
<bean id="bookDao" class="priv.dandelion.dao.impl.BookDaoImpl" lazy-init="true"/>
2.2 核心容器总结
2.2.1 容器相关
2.2.2 Bean 相关
<bean/>
标签的常用属性及其作用属性 作用 id="BookDao" bean 的 id name= bean 的 别名 class="priv.dandelion.dao.impl.BookDaoImpl" bean 的类型,静态工厂类,FactoryBean 类 scope="singleton" 控制 bean 的实例数量 init-method="方法名" 生命周期初始化方法 destroy-method="方法名" 生命周期销毁方法 autowire="byType" 自动装配类型 factory-method="getInstance" bean 工厂方法,应用于静态工厂或实例工厂 factory-bean="priv.dandelion.factory.BookDaoFactory" 实例工厂 bean lazy-init="true" 控制 bean 延迟加载
2.2.3 依赖注入相关
<bean id="bookService" class="priv.dandelion.service.impl.BookServiceImpl">
<!--
构造器注入,一般用在第三方技术整合
-->
<!-- 构造器注入引用类型,注意此处的 ref 属性值为构造方法的形参名 -->
<constructor-arg name="userDao" ref="userDao"/>
<constructor-arg name="bookDao" ref="bookDao"/>
<!-- 构造器注入简单数据类型 -->
<constructor-arg name="databaseName" value="mysql"/>
<constructor-arg name="connectionNum" value="10"/>
<!-- 类型匹配与索引匹配,用于解耦 -->
<constructor-arg type="int" value="10"/>
<constructor-arg index="0" value="mysql"/>
<!--
setter注入,自己开发的内容多用该方式
-->
<!-- 注入引用数据类型 -->
<!--property标签:设置注入属性-->
<!--name属性:设置注入的属性名,实际是set方法对应的名称-->
<!--ref属性:设置注入引用类型bean的id或name-->
<property name="bookDao" ref="bookDao"/>
<property name="userDao" ref="userDao"/>
<!-- 注入简单数据类型 -->
<property name="connectionNum" value="100"/>
<property name="databaseName" value="mysql"/>
<!-- 注入集合类型 -->
<property name="list">
<list>
<!-- 集合注入简单数据类型 -->
<value>dandelion</value>
<!-- 集合注入引用数据类型 -->
<ref bean="bean的id"/>
</list>
</property>
</bean>
3、IoC/DI注解开发
3.1 环境准备
导入 Spring 依赖
BookDao 接口和实现类
BookService 接口和实现类
核心配置文件
<?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="priv.dandelion.dao.impl.BookDaoImpl"/> </beans>
运行类
public class App {
public static void main(String[] args) {
// 获取IOC容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取Bean
BookDao bookDao = (BookDao) context.getBean("bookDao");
bookDao.save();
}
}
3.2 注解开发定义 Bean
3.2.1 流程
删除原 XML 配置
<bean id="bookDao" class="priv.dandelion.dao.impl.BookDaoImpl"/>
添加组件注解
@Component
Spring将管理的bean视作自己的一个组件
@Component
的 value 属性(可不指定)值为 bean 的 id@Component("bookDao")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book priv.dandelion.dao save ...");
}
}
@Component
也可以不声明id,加载时需要使用按类型访问@Component
public class BookServiceImpl implements BookService {
// 删除业务层中使用new的方式创建的dao对象
private BookDao bookDao; public void save() {
System.out.println("book service save ...");
bookDao.save();
}
// 提供所要创建成员对象的对应的set方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
配置 Spring 的注解包扫描
- component:组件,Spring将管理的bean视作自己的一个组件
- scan:扫描
- base-package:指定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
http://www.springframework.org/schema/context/spring-context.xsd"> <!-- <bean id="bookDao" class="priv.dandelion.dao.impl.BookDaoImpl"/>--> <!-- 配置扫描组件 -->
<context:component-scan base-package="priv.dandelion"/> </beans>
运行类
BookServiceImpl类没有起名称,所以在App中是按照类型来获取bean对象
@Component注解如果不起名称,会有一个默认值就是
当前类名首字母小写
,所以也可以按照名称获取,如BookService bookService = (BookService)ctx.getBean("bookServiceImpl");
System.out.println(bookService);
public class App {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 注解中注明id,获取bean可按名称访问
BookDao bookDao = (BookDao) context.getBean("bookDao");
bookDao.save();
// 注解中没有注明id,获取bean需要按类型访问
BookService bookService = context.getBean(BookService.class);
System.out.println(bookService);
}
}
3.2.2 相关知识点
3.2.2.1 @Component
的衍生
对于@Component注解,还衍生出了其他三个注解
@Controller
、@Service
、@Repository
这三个注解和@Component注解的作用是一样的,仅用于方便我们后期在编写类的时候能很好的区分出这个类是属于
表现层
、业务层
还是数据层
的类。@Controller
:用于表现层 bean 定义@Service
:用于业务层 bean 定义@Repository
:用于数据层 bean 定义
3.2.2.2 @Component
相关内容归纳
名称 | @Component/@Controller/@Service/@Repository |
---|---|
类型 | 类注解 |
位置 | 类定义上方 |
作用 | 设置该类为spring管理的bean |
属性 | value(默认):定义bean的id |
3.3 纯注解开发模式
3.3.1 思路分析
编写配置类,弃用Spring配置文件
3.3.2 实现步骤
删除配置文件
编写配置类
// 声明这是一个配置类
@Configuration
// 配置包扫描,与原先的配置文件中一致
@ComponentScan("priv.dandelion")
// @ComponentScan({"priv.dandelion.dao","priv.dandelion.service"})
public class SpringConfig {
}
运行类
public class AppForAnnotation {
public static void main(String[] args) {
/*
原先使用配置文件时,需要使用ClassPathXmlApplicationContext()加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
*/ // 加载配置类
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); // 注解中注明id,获取bean可按名称访问
BookDao bookDao = (BookDao) context.getBean("bookDao");
bookDao.save();
// 注解中没有注明id,获取bean需要按类型访问
BookService bookService = context.getBean(BookService.class);
System.out.println(bookService);
}
}
3.3.3 相关知识点
3.3.3.1 @Configuration
@Configuration注解用于设定当前类为配置类
名称 @Configuration 类型 类注解 位置 类定义上方 作用 设置该类为spring配置类 属性 value(默认):定义bean的id
3.3.3.2 @ComponentScan
@ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式
名称 @ComponentScan 类型 类注解 位置 类定义上方 作用 设置spring配置类扫描路径,用于加载使用注解格式定义的bean 属性 value(默认):扫描路径,此路径可以逐层向下扫描
3.4 注解开发 Bean 作用范围和生命周期管理
3.4.1 Bean 的作用范围
在运行类中创建 BookDao 的两个 bean
运行结果:两个 bean 的地址一致
控制 Bean 的作用范围
@Repository("bookDao")
// 设置为非单例(默认为单例)
@Scope("prototype")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book priv.dandelion.dao save ...");
}
}
@Scope
名称 @Scope 类型 类注解 位置 类定义上方 作用 设置该类创建对象的作用范围
可用于设置创建出的bean是否为单例对象属性 value(默认):定义bean作用范围,
默认值singleton(单例),可选值prototype(非单例)
3.4.2 Bean的生命周期
生命周期方法注解
- 初始化方法:
@PostConstruct
(即构造后) - 销毁方法:
@PreDestroy
(即销毁前)
- 初始化方法:
示例
Dao
@Repository("bookDao")
@Scope("singleton")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book priv.dandelion.dao save ...");
} @PostConstruct
public void init() {
System.out.println("book priv.dandelion.dao init ...");
} @PreDestroy
public void destroy() {
System.out.println("book priv.dandelion.dao destroy ...");
}
}
Main
public class App {
public static void main(String[] args) { // 加载配置类
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); // 注解中注明id,获取bean可按名称访问
BookDao bookDao = (BookDao) context.getBean("bookDao");
bookDao.save();
// 手动关闭容器,以执行各项销毁
context.close();
/**
* book priv.dandelion.dao init ...
* book priv.dandelion.dao save ...
* book priv.dandelion.dao destroy ...
*
* Process finished with exit code 0
*/
}
}
知识点整理
@PostConstruct
名称 @PostConstruct 类型 方法注解 位置 方法上 作用 设置该方法为初始化方法 属性 无 @PreDestroy
名称 @PreDestroy 类型 方法注解 位置 方法上 作用 设置该方法为销毁方法 属性 无
3.5 注解开发依赖注入
3.5.1 环境准备
配置类
// 声明这是一个配置类
@Configuration
// 配置包扫描,与原先的配置文件中一致
@ComponentScan({"priv.dandelion.dao","priv.dandelion.service"})
public class SpringConfig {
}
Dao 实现类
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book priv.dandelion.dao save ...");
} @PostConstruct
public void init() {
System.out.println("book priv.dandelion.dao init ...");
} @PreDestroy
public void destroy() {
System.out.println("book priv.dandelion.dao destroy ...");
}
}
Service 实现类
@Service
public class BookServiceImpl implements BookService {
private BookDao bookDao; public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
3.5.2 注解实现按照类型注入
先说结论和注意事项:
实现方式:使用
@Autowired
注解注意事项
@Autowired
可以写在属性上,也可也写在setter方法上
@Autowired
修饰的成员属性对应的 setter 可以删除普通反射只能获取public修饰的内容,而自动装配基于反射设计创建对象并通过暴力反射为私有属性进行设值。暴力反射除了获取public修饰的内容还可以获取private修改的内容,所以此处无需提供 setter 方法
@Autowired
是按照类型注入,当存在多个相同类型的不同 bean 时,就自动按照名称注入,但一般最好指定名称,将在 3.5.3 详细说明
示例
Service 实现类
@Service
public class BookServiceImpl implements BookService { // 自动装配,按类型装配,采用暴力反射,不需要实现set方法
@Autowired
private BookDao bookDao; public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
运行类
public class App {
public static void main(String[] args) { // 加载配置类
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); // 注解中注明id,获取bean可按名称访问
BookDao bookDao = (BookDao) context.getBean("bookDao");
bookDao.save();
BookService bookService = context.getBean(BookService.class);
bookService.save();
// 手动关闭容器,以执行各项销毁
context.close();
/**
* book priv.dandelion.dao init ...
* book priv.dandelion.dao save ...
* book service save ...
* book priv.dandelion.dao save ...
* book priv.dandelion.dao destroy ...
*
* Process finished with exit code 0
*/
}
}
3.5.3 注解实现按照名称注入
先说结论和注意事项:
结论:使用
@Qualifier
注解注意事项
- 用于应对存在多个相同类型的 bean,首先需要为这些 bean 分别赋予名称,否则会报错
- 接 3.3.4,若存在多个相同类型的 bean,当使用
@Autowired
时,会按照名称进行注入,此时由于没有指定变量名,将默认采用该变量的变量名来进行匹配注入(如下面的代码块所示,此处为bookDao
)。但显而易见,这样会导致代码混乱且极易出错- 为避免出错,可以使用
@Qualifier
注解,在自动装配的情况下手动指定加载的 bean 的名称,该注解的 value 是 bean 的名称@Qualifier
注解必须搭配@Autowired
一起使用,不能单独使用3.3.4 中的 Service 代码展示
@Service
public class BookServiceImpl implements BookService { @Autowired
private BookDao bookDao; public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
为同类型的不同的 bean 命名
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ..." );
}
}
// =========================================================
@Repository("bookDao2")
public class BookDaoImpl2 implements BookDao {
public void save() {
System.out.println("book dao save ...2" );
}
}
在自动装配的情况下手动指定加载的 bean 的名称
@Service
public class BookServiceImpl implements BookService { // 自动装配,按类型装配,采用暴力反射,不需要实现set方法
@Autowired
// 自动装配的情况下指定加载bean的名称
@Qualifier("bookDao")
private BookDao bookDao; public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
3.5.4 简单数据类型注入
使用
@Value
注解实现,一般搭配外部配置文件使用,详见 3.5.5示例
@Repository("bookDao")
public class BookDaoImpl implements BookDao { @Value("dandelion")
private String name; public void save() {
System.out.println("book priv.dandelion.dao save1 ..." + name);
} @PostConstruct
public void init() {
System.out.println("book priv.dandelion.dao init ...");
} @PreDestroy
public void destroy() {
System.out.println("book priv.dandelion.dao destroy ...");
}
}
3.5.5 注解读取 properties 配置文件
添加配置文件
name=dandelion
password=123456
在配置类中添加属性源
@PropertySource
注解注意:
- 若有多个配置文件则写作数组
- 文件名不能使用通配符
*
// 声明这是一个配置类
@Configuration
// 配置包扫描,与原先的配置文件中一致
@ComponentScan({"priv.dandelion.dao","priv.dandelion.service"})
// 属性源
@PropertySource({"jdbc.properties","jdbc1.properties"})
public class SpringConfig {
}
读取配置文件中的内容
@Repository("bookDao")
public class BookDaoImpl implements BookDao { @Value("${name}")
private String name; @Value("${password}")
private String password; public void save() {
System.out.println("book priv.dandelion.dao save1 ..." + name + " " + password);
} @PostConstruct
public void init() {
System.out.println("book priv.dandelion.dao init ...");
} @PreDestroy
public void destroy() {
System.out.println("book priv.dandelion.dao destroy ...");
}
}
3.5.6 依赖注入相关知识点
3.5.6.1 @Autowired
名称 | @Autowired |
---|---|
类型 | 属性注解 或 方法注解(了解) 或 方法形参注解(了解) |
位置 | 属性定义上方 或 标准set方法上方 或 类set方法上方 或 方法形参前面 |
作用 | 为引用类型属性设置值 |
属性 | required:true/false,定义该属性是否允许为null |
3.5.6.2 @Qualifier
名称 | @Qualifier |
---|---|
类型 | 属性注解 或 方法注解(了解) |
位置 | 属性定义上方 或 标准set方法上方 或 类set方法上方 |
作用 | 为引用类型属性指定注入的beanId |
属性 | value(默认):设置注入的beanId |
3.5.6.3 @Value
名称 | @Value |
---|---|
类型 | 属性注解 或 方法注解(了解) |
位置 | 属性定义上方 或 标准set方法上方 或 类set方法上方 |
作用 | 为 基本数据类型 或 字符串类型 属性设置值 |
属性 | value(默认):要注入的属性值 |
3.5.6.4 @PropertySource
名称 | @PropertySource |
---|---|
类型 | 类注解 |
位置 | 类定义上方 |
作用 | 加载properties文件中的属性值 |
属性 | value(默认):设置加载的properties文件对应的文件名或文件名组成的数组 |
4、IoC/DI注解开发管理第三方bean
4.1 环境准备
Spring 依赖
配置类
@Configuration
public class SpringConfig {
}
Dao 实现类
@Repository
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ..." );
}
}
运行类
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
}
}
4.2 注解开发管理第三方 Bean
方式:使用自定义 Bean
- @Bean 注解的作用是将方法的返回值制作为 Spring 管理的一个 bean 对象(表示当前方法的返回值是一个 bean )
- @Bean 注解是有 Value 属性的,表示 bean 的名称,即 id
具体实现:
- 添加配置类
- 在配置类中添加方法,该方法返回所需的 bean 的类型,并为该方法添加
@Bean
注解- 在需要时,按类型获取 bean
导入第三方 jar 包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
在配置类中添加方法
引入外部配置文件的具体相关内容已经再上一小节详细说明
@Configuration
@PropertySource("jdbc.properties")
public class SpringConfig {
// 定义一个方法获得要管理的对象
public DataSource dataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName("${driverClassName}");
druidDataSource.setUrl("${url}");
druidDataSource.setUsername("${name}");
druidDataSource.setPassword("${password}");
return druidDataSource;
}
}
在方法伤添加
@Bean
注解@Bean注解的作用是将方法的返回值制作为 Spring 管理的一个 bean 对象(表示当前方法的返回值是一个 bean )
注意:
- 不能使用
DataSource ds = new DruidDataSource()
,因为 DataSource 接口中没有对应的 setter 方法来设置属性。
@Configuration
@PropertySource("jdbc.properties")
public class SpringConfig { // 定义一个方法获得要管理的对象
@Bean
public DataSource dataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName("${driverClassName}");
druidDataSource.setUrl("${url}");
druidDataSource.setUsername("${name}");
druidDataSource.setPassword("${password}");
return druidDataSource;
}
}
- 不能使用
从IoC容器中获取对象并打印
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
DataSource dataSource = ctx.getBean(DataSource.class);
System.out.println(dataSource);
}
}
4.3 引入外部配置类
在配置类中写过多的函数会导致混乱,故可以将配置拆出来单独写成类,后续会介绍如何引入外部配置类
4.3.1 使用包扫描引入
将函数拆解出来,单独作为一个类,并添加配置类注解
@Configuration
@PropertySource("jdbc.properties")
public class JDBCConfig {
// 定义一个方法获得要管理的对象
@Bean
public DataSource dataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName("${driverClassName}");
druidDataSource.setUrl("${url}");
druidDataSource.setUsername("${name}");
druidDataSource.setPassword("${password}");
return druidDataSource;
}
}
在配置类上使用注解,使用包扫描
@ComponentScan
引入外部配置类(不推荐,使用的是包名,引用内容不明了)@Configuration
@ComponentScan("priv.dandelion.config")
public class SpringConfig {
}
4.3.2 使用 @Import
引入
将函数拆解出来,单独作为一个类,不需要添加配置类注解
// @Configuration
@PropertySource("jdbc.properties")
public class JDBCConfig {
// 定义一个方法获得要管理的对象
@Bean
public DataSource dataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName("${driverClassName}");
druidDataSource.setUrl("${url}");
druidDataSource.setUsername("${name}");
druidDataSource.setPassword("${password}");
return druidDataSource;
}
}
在配置类上使用注解,使用
@Import
引入外部配置类如果需要引入多个外部配置类,可以使用数组的格式进行书写
@Configuration
@Import(JDBCConfig.class)
public class SpringConfig {
}
4.3.3 相关知识点
4.3.3.1@Bean
名称 | @Bean |
---|---|
类型 | 方法注解 |
位置 | 方法定义上方 |
作用 | 设置该方法的返回值作为spring管理的bean |
属性 | value(默认):定义bean的id |
4.3.3.2@Import
名称 | @Import |
---|---|
类型 | 类注解 |
位置 | 类定义上方 |
作用 | 导入配置类 |
属性 | value(默认):定义导入的配置类类名, 当配置类有多个时使用数组格式一次性导入多个配置类 |
4.4 注解开发实现为第三方 Bean 注入资源
4.4.1 简单数据类型
@PropertySource("jdbc.properties")
public class JDBCConfig {
// 对成员变量进行注入,降低耦合度
@Value("${driverClassName}")
private String driver;
@Value("${url}")
private String url;
@Value("${name}")
private String name;
@Value("${password}")
private String password;
// 定义一个方法获得要管理的对象
@Bean
public DataSource dataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(driver);
druidDataSource.setUrl(url);
druidDataSource.setUsername(name);
druidDataSource.setPassword(password);
return druidDataSource;
}
}
4.4.2 引用数据类型
4.4.2.1 需求分析
- 需求:假设需要在外部配置类中使用到BookDao
4.4.2.2 注入引用数据类型步骤
在 Spring 配置类中扫描
扫描的目的是让 Spring 能管理到 BookDao,也就是说要让 IOC 容器中有一个 bookDao类型的 Bean 对象,这一步骤的意义会在下面进行详细说明
@Configuration
@ComponentScan("priv.dandelion.dao")
@Import(JDBCConfig.class)
public class SpringConfig {
}
在外部配置类中加上参数并使用
引用类型注入只需要为 bean 定义方法设置形参即可,容器会根据类型自动装配对象。
此处如何理解:此处为自动装配,检测到该方法是在做第三方 Bean (要配置一个 Bean ),Spring 会认为这个形参要由 Spring 进行提供,此时会在 IoC 容器中寻找该类型的 Bean,而在上面主配置类中已经对 BookDao 类型的 Bean 进行了扫描。
// 定义一个方法获得要管理的对象
@Bean
public DataSource dataSource(BookDao bookDao) { System.out.println(bookDao); DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(driver);
druidDataSource.setUrl(url);
druidDataSource.setUsername(name);
druidDataSource.setPassword(password);
return druidDataSource;
}
5、注解开发总结
功能 | XML配置 | 注解 |
---|---|---|
定义bean | bean 标签 * id 属性 * class 属性 |
@Component,定义 bean,为简单明了,常使用以下三个注解 * @Controller 用于 Controller 的 bean* @Service 用于 Service 的 bean* @Repository 用于 Dao 的 bean@ComponentScan,设置 spring 配置类扫描路径,用于加载使用注解格式定义的 bean |
设置依赖注入 | setter 注入 构造器注入 自动装配 |
@Autowired,自动装配,默认按类型注入 * @Qualifier ,按照名称进行注入,搭配@Autowired 使用@Value,简单类型注入 |
配置第三方bean | bean 标签 静态工厂、实例工厂、FactoryBean |
@Bean 注解,用于配置类或外部配置类中的方法 * 方法的返回值为所需的 bean 的类型 |
作用范围 | scope 属性 | @Scope * 默认值singleton(单例),可选值prototype(非单例) |
生命周期 | 标准接口 * init-method * destroy-method |
@PostConstructor,用于表示一个方法是初始化方法 @PreDestory,用于表示一个方法是销毁方法 |
6、Spring整合
6.1 Spring 整合 MyBatis 思路分析
6.1.1 环境准备(MyBatis 的原始开发)
准备数据库
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
);
导入依赖 jar 包
<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>
根据表创建模型类
package priv.dandelion.entity; import java.io.Serializable; public class Account implements Serializable { private Integer id;
private String name;
private Double money;
//setter...getter...toString...方法略
}
创建Dao接口
使用自动代理,不需要再写映射文件,仅编写接口并使用注解编写 SQL 语句
package priv.dandelion.dao; import priv.dandelion.entity.Account;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update; import java.util.List; 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);
}
创建Service接口和实现类
接口
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);
}
实现类
@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);
}
}
添加数据库连接配置文件
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
# useSSL:关闭MySQL的SSL连接
jdbc.url=jdbc:mysql://localhost:3306/spring_db?useSSL=false
jdbc.username=root
jdbc.password=123456
添加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配置文件-->
<properties resource="jdbc.properties"></properties>
<!--别名扫描的包路径-->
<typeAliases>
<package name="priv.dandelion.entity"/>
</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="priv.dandelion.dao"></package>
</mappers>
</configuration>
编写应用程序
public class App {
public static void main(String[] args) throws IOException {
// 1.初始化 SqlSessionFactory
// 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 加载mybatis-config.xml配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
// 创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); // 2.获取连接,获取实现
// 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 执行SqlSession对象执行查询,获取结果User
AccountDao accountDao = sqlSession.getMapper(AccountDao.class); // 3.获取数据层接口
Account ac = accountDao.findById(2);
System.out.println(ac); // 4.关闭连接
// 释放资源
sqlSession.close();
}
}
6.1.2 整合思路分析
Mybatis的基础环境我们已经准备好了
- 思考:上述的内容中,哪些 Bean 可以交给Spring来管理?
Mybatis程序核心对象分析
由这部分内容可知:真正需要交给 Spring 管理的是第 1 部分初始化 SqlSessionFactory
public class App {
public static void main(String[] args) throws IOException {
// 1.初始化 SqlSessionFactory
// 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 加载mybatis-config.xml配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
// 创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); // 2.获取连接,获取实现
// 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 执行SqlSession对象执行查询,获取结果User
AccountDao accountDao = sqlSession.getMapper(AccountDao.class); // 3.获取数据层接口
Account ac = accountDao.findById(2);
System.out.println(ac); // 4.关闭连接
// 释放资源
sqlSession.close();
}
}
整合 Mybatis,就是将 Mybatis 用到的内容交给 Spring 管理,分析下配置文件
- 第一部分读取外部 properties 配置文件,Spring 有提供具体的解决方案
@PropertySource
,需要交给 Spring - 第二部分起别名包扫描,为 SqlSessionFactory 服务的,需要交给Spring
- 第三部分主要用于做连接池,Spring 之前我们已经整合了 Druid 连接池,这块也需要交给Spring
- 前面三部分一起都是为了创建 SqlSession 对象用的,那么用 Spring 管理 SqlSession 对象吗?回忆下 SqlSession 是由 SqlSessionFactory 创建出来的,所以只需要将 SqlSessionFactory 交给 Spring 管理即可。
- 第四部分是 Mapper 接口和映射文件
(如果使用注解就没有该映射文件)
,这个是在获取到 SqlSession 以后执行具体操作的时候用,所以它和 SqlSessionFactory 创建的时机都不在同一个时间,可能需要单独管理。
<?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>
<!-- 1.初始化属性数据,读取外部properties配置文件 -->
<properties resource="jdbc.properties"></properties> <!-- 2.初始化类型别名,别名扫描的包路径 -->
<typeAliases>
<package name="priv.dandelion.entity"/>
</typeAliases> <!-- 3.初始化dataSource,数据源 -->
<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> <!-- 4.初始化映射配置,映射文件扫描包路径 -->
<mappers>
<package name="priv.dandelion.dao"></package>
</mappers>
</configuration>
- 第一部分读取外部 properties 配置文件,Spring 有提供具体的解决方案
6.2 Spring 整合 MyBatis 步骤
上一部分已经分析了 Spring 与 Mybatis 的整合,大体需要做两件事:
- Spring 要管理 MyBatis 中的 SqlSessionFactory,使用到了 SqlSessionFactoryBean
- Spring 要管理 Mapper 接口的扫描,使用到了 MapperScannerConfigurer
在原先依赖的基础上,再添加两个依赖
<dependencies>
<!--
...
-->
<dependency>
<!--Spring操作数据库需要该jar包-->
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.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>
</dependencies>
创建 Spring 的主配置类
// 配置类注解
@Configuration
// 包扫描
@ComponentScan("priv.dandelion")
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 druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(driver);
druidDataSource.setUrl(url);
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
return druidDataSource;
}
}
主配置类中读 properties 并引入数据源配置类
@Configuration
@ComponentScan("priv.dandelion")
@PropertySource("classpath:jdbc.properties")
@Import(JDBCConfig.class)
public class SpringConfig {
}
创建 Mybatis 配置类并配置 SqlSessionFactory
说明:
- 使用 SqlSessionFactoryBean 封装 SqlSessionFactory 需要的环境信息
- SqlSessionFactoryBean 是 FactoryBean 的一个子类,在该类中将SqlSessionFactory 的创建进行了封装,简化对象的创建,使用时只需要将其需要的内容设置即可。
- 方法中有一个参数为 dataSource,当前 Spring 容器中已经创建了 Druid 数据源,类型刚好是 DataSource 类型,此时在初始化 SqlSessionFactoryBean 这个对象的时候,发现需要使用 DataSource 对象,而容器中刚好有这么一个对象,就自动加载了 DruidDataSource 对象。
- 使用 MapperScannerConfigurer 加载 Dao 接口,创建代理对象保存到 IOC 容器中
- MapperScannerConfigurer 对象也是 MyBatis 提供的专用于整合的 jar 包中的类,用来处理原始配置文件中的 mappers 相关配置,加载数据层的 Mapper 接口类
- MapperScannerConfigurer 有一个核心属性 basePackage,就是用来设置所扫描的包路径
public class MybatisConfig { /**
* 定义bean,SqlSessionFactoryBean,负责创建 SqlSessionFactory,即配置文件的二三部分
* @param dataSource
* @return SqlSessionFactoryBean
*/
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
ssfb.setTypeAliasesPackage("priv.dandelion.entity");
// JDBCConfig 中已经定义了这个 bean,故此处可采用引用类型注入,方法是直接为本方法增加需要注入类型的形参
ssfb.setDataSource(dataSource);
return ssfb;
} /**
* 定义bean,MapperScannerConfigurer,映射配置,配置包扫描,即配置文件的第四部分
* @return MapperScannerConfigurer
*/
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("priv.dandelion.dao");
return msc;
}
}
- 使用 SqlSessionFactoryBean 封装 SqlSessionFactory 需要的环境信息
主配置类中引入 Mybatis 配置类
@Configuration
@ComponentScan("priv.dandelion")
@PropertySource("classpath:jdbc.properties")
@Import({JDBCConfig.class, MybatisConfig.class})
public class SpringConfig {
}
编写运行类
public class App2 { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
AccountService accountService = ctx.getBean(AccountService.class); Account account = accountService.findById(1); System.out.println(account);
}
}
6.3 Spring 整合 Junit
6.3.1 环境准备
使用 Spring 整合 MyBatis 案例
6.3.2 整合 Junit 步骤
注意:
- 单元测试,如果测试的是注解配置类,则使用
@ContextConfiguration(classes = 配置类.class)
- 单元测试,如果测试的是配置文件,则使用
@ContextConfiguration(locations={配置文件名,...})
- Junit运行后是基于 Spring 环境运行的,所以 Spring 提供了一个专用的类运行器,这个务必要设置,这个类运行器就在 Spring 的测试专用包中提供的,导入的坐标就是这个东西
SpringJUnit4ClassRunner
- 上面两个配置都是固定格式,当需要测试哪个 bean 时,使用自动装配加载对应的对象,下面的工作就和以前做 Junit 单元测试完全一样了
引入依赖
<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>
编写测试类
// 设置类运行器
@RunWith(SpringJUnit4ClassRunner.class)
// 设置Spring环境对应的配置类,加载配置类,可以使用数组
@ContextConfiguration(classes = {SpringConfig.class})
// @ContextConfiguration 注解也可以用于加载配置文件(如果需要),可以使用数组
//@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());
}
}
6.4 相关知识点
6.4.1 @RunWith
名称 | @RunWith |
---|---|
类型 | 测试类注解 |
位置 | 测试类定义上方 |
作用 | 设置JUnit运行器 |
属性 | value(默认):运行所使用的运行期 |
6.4.2 @ContextConfiguration
名称 | @ContextConfiguration |
---|---|
类型 | 测试类注解 |
位置 | 测试类定义上方 |
作用 | 设置JUnit加载的Spring核心配置 |
属性 | classes:核心配置类,可以使用数组的格式设定加载多个配置类 locations: 配置文件,可以使用数组的格式设定加载多个配置文件名称 |
Spring学习笔记 - 第二章 - 注解开发、配置管理第三方Bean、注解管理第三方Bean、Spring 整合 MyBatis 和 Junit 案例的更多相关文章
- 《DOM Scripting》学习笔记-——第二章 js语法
<Dom Scripting>学习笔记 第二章 Javascript语法 本章内容: 1.语句. 2.变量和数组. 3.运算符. 4.条件语句和循环语句. 5.函数和对象. 语句(stat ...
- The Road to learn React书籍学习笔记(第二章)
The Road to learn React书籍学习笔记(第二章) 组件的内部状态 组件的内部状态也称为局部状态,允许保存.修改和删除在组件内部的属性,使用ES6类组件可以在构造函数中初始化组件的状 ...
- [HeadFrist-HTMLCSS学习笔记]第二章深入了解超文本:认识HTML中的“HT”
[HeadFrist-HTMLCSS学习笔记]第二章深入了解超文本:认识HTML中的"HT" 敲黑板!!! 创建HTML超链接 <a>链接文本(此处会有下划线,可以单击 ...
- Spring学习指南-第二章-Spring框架基础(完)
第二章 Spring框架基础 面向接口编程的设计方法 在上一章中,我们看到了一个依赖于其他类的POJO类包含了对其依赖项的具体类的引用.例如,FixedDepositController 类包含 ...
- [HeadFirst-JSPServlet学习笔记][第二章:高层概述]
第二章:高层体系结构 容器 1 什么是容器? servelet没有main()方法.它们受控于另一个Java应用,这个Java应用称为容器(Container) Tomcat就是这样一个容器.Web服 ...
- c#高级编程第七版 学习笔记 第二章 核心c#
第二章 核心C# 本章内容: 声明变量 变量的初始化和作用域 C#的预定义数据类型 在c#程序中使用条件语句.循环和跳转语句执行流 枚举 名称空间 Main()方法 基本的命令行c#编译器选项 使用S ...
- Java 学习笔记 ------第二章 从JDK到IDE
本章学习目标: 了解与设定PATH 了解与指定CLASSPATH 了解与指定SOURCEPATH 使用package与import管理类别 初步认识JDK与IDE的对应关系 一.第一个Java程序 工 ...
- 《Python基础教程(第二版)》学习笔记 -> 第二章 列表和元组
本章将引入一个新的概念:数据结构. 数据结构是通过某种方式阻止在一起的数据元素的集合,这些数据元素可以是数字或者字符,设置可以是其他数据结构. Python中,最基本的数据结构是序列(Sequence ...
- 交换机安全学习笔记 第二章 MAC地址泛洪攻击
本文为书中相关知识的摘要,由于书中以思科设备为配置依据,所以笔记中补充了华为.H3C设备的相关配置.华为设备配置参考华为S2352EI 产品版本:V100R005C01文档版本:02. H3C配置参 ...
- J2EE学习笔记-第二章(Web应用初步)
首先要理解一些概念的词语,到底这些是什么(当我读懂了后,会逐一填补完整,现在我真的有点混淆) web组件-相当于功能性的组件,就像是零件,汽车的轮胎,汽车的门,所有组件组合后,才能成为一辆车,有时候也 ...
随机推荐
- POJ1094 Sorting It All Out (floyd传递闭包)
关系具有传递性,可以用floyd解决. 将关系都看做i<j的形式,令d[i][j]=1,如果d[i][j]=d[j][i]=1,说明矛盾:d[i][j]=d[j][i]=0,说明i与j的关系无法 ...
- RAID5 IO处理之条带读代码详解
除了对齐读流程中读失败通过条带重试的场景会进入到条带读,当IO覆盖范围超过一个chunk时也会进入条带读(如向chunk为4K的RAID下发起始位置为1K大小为4K的IO),接下来我们就这部分逻辑进行 ...
- PHP cURL抓取网上图片
cURL的底层是由一个命令行工具实现的,用于获取远程文件或传输文件,更多的情况是用来模拟get/post表单提交.也可以用户文件上传,爬取文件,支持FTP/FTPS,HTTP/HTTPS等协议,通俗来 ...
- 怎样在GitHub上建立仓库、以及怎样实现分支代码的合并。保姆级别的教程
GitHub官网地址:https://github.com/ 注意:前提是已经注册了GitHub 文章目录 第一步:创建一个新的仓库 第二步.创建一个分支 第三步.编辑和发布更改的内容 第四步.拉取请 ...
- 3.pygame快速入门-游戏循环及动画实现
游戏循环的开始,意味着游戏的正式开始,游戏循环的作用如下 1.保证游戏不会直接退出 2.变化图像的位置--动画效果 3.检测用户交互--按键.鼠标等 游戏时钟 pyagame提供了一个pyga ...
- Java多线程(5):CAS
您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来- 在JDK1.5之前,Java的多线程都是靠synchronized来保证同步的,这会引起很多性能问题,例如死锁.但随着Java的不断完善,JNI ...
- 获取不同机型微信小程序状态栏+导航栏高度
获取不同机型微信小程序状态栏+导航栏高度 一. 前言 很多时候我们开发微信小程序,都需要先知道状态栏和导航栏的高度,才能去做其他功能 二. 获取微信小程序状态栏高度 用wx.getSystemInfo ...
- 二、Kubernetes 概念介绍
一.Master Master指的是集群控制节点,在每个Kubernetes集群里都需要有一个Master来负责整个集群的管理和控制,基本上Kubernetes的所有控制命令都发给它,它负责具体的 ...
- 长文梳理muduo网络库核心代码、剖析优秀编程细节
前言 muduo库是陈硕个人开发的tcp网络编程库,支持Reactor模型,推荐大家阅读陈硕写的<Linux多线程服务端编程:使用muduo C++网络库>.本人前段时间出于个人学习.找工 ...
- Transformer 结构分析
self-attetion 1. 输入 \[X = EmbeddingLookup(X) + PositionalEncoding \\ X.shape == (batch\_size, seq\_l ...