目录
1 注解开发
1.1 注解开发定义bean
- 使用@Component定义bean
- 核心配置文件通过组件扫描配置bean
- Spring提供@Component注解的三个衍生注解
- @Controller:用于表现层bean定义
- @Service:用于业务层bean定义
- @Repository:用于数据层bean定义
1.2 纯注解开发模式
- Spring3.0开启了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道
- @Configuration注解用于设定当前类为配置类
- @ComponScan注解用于设定扫描路径,此注解只能添加一次,多个用数组格式,如:
@ComponScan({"com.zs","com.zs.dao"})
- 读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器对象
//加载配置文件初始化容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//加载配置类初始化容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
【示例】:
//有了@ComponentScan,@Configuration就可以省略
@Configuration
@ComponentScan("com.itheima")
public class SpringConfig {
}
public class AppForAnnotation {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
System.out.println(bookDao);
BookService bookService = ctx.getBean(BookService.class);
System.out.println(bookService);
}
}
1.2 bean管理(作用范围和生命周期)
- 使用@Scope定义bean的作用范围
@Repository
//@Scope设置bean的作用范围
@Scope("prototype")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
- 使用@PostConstruct和@PreDestroy定义bean的生命周期
@Repository
@Scope("singleton")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
@PostConstruct //在构造方法之后执行,替换 init-method
public void init() {
System.out.println("init ...");
}
@PreDestroy //在销毁方法之前执行,替换 destroy-method
public void destroy() {
System.out.println("destroy ...");
}
}
1.4 注解开发依赖注入
- 使用@Autowired注解开启自动装配模式(按类型)
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
// setter方法可以删除
// public void setBookDao(BookDao bookDao) {
// this.bookDao = bookDao;
// }
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
注意:
- 自动装配基于反射设计创建对象并通过暴力反射为私有属性初始化数据(普通反射只能获取public修饰的内容 暴力反射除了获取public修饰的内容还可以获取private修改的内容),因此此处无需提供setter方法
- 自动装配建议使用午餐构造方法创建对象(默认),如果不提供对应构造方法,请提供唯一的构造方法
问题:BookDao接口如果有多个未注解id的实现类直接运行会报错,按照类型注入就无法区分到底注入哪个对象,
解决方案:按照名称注入
- 使用@Qualifier注解开启指定名称装配bean
@Service
public class BookServiceImpl implements BookService {
@Autowired
@Qualifier("bookDao1")
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
注意:@Qualifier注解无法单独使用,必须配合@Autowired注解使用
- 使用@Value实现简单类型注入
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
@Value("itheima")
private String name;
public void save() {
System.out.println("book dao save ..." + name);
}
}
思考:@Value跟直接赋值似乎是一个效果,还没有直接赋值简单,所以这个注解存在的意义是什么?
答:@Value一般用于读取properties配置文件,可以动态更改简单数据类型的值,而直接赋值是写死的。
- 使用@PorpertySource注解加载properties文件
配置类注解@PropertySource加载properties配置文件,使用@Value读取配置文件中的内容
【示例】:
resource下准备properties文件:jdbc.properties
name=itheima888
在配置类上添加@PropertySource注解:SpringConfig
@Configuration
@ComponentScan("com.itheima")
@PropertySource("jdbc.properties")
//@PropertySource("classpath:jdbc.properties")
public class SpringConfig {
}
使用@Value读取配置文件中的内容:
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
@Value("${name}")
private String name;
public void save() {
System.out.println("book dao save ..." + name);
}
}
注意:路径仅支持单一文件配置,多文件使用数组格式配置,不允许使用通配符*
1.5 第三方bean管理
- 使用@Bean配置第三方bean
在pom文件中导入druid的jar包,在配置类中添加一个方法,设置数据库属性(但是不建议将@Bean写到SpringConfig配置类中)
@Configuration
public class SpringConfig {
@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("root");
return ds;
}
}
注意:不能使用DataSource ds = new DruidDataSource(),因为DataSource接口中没有对应的setter方法来设置属性。不过能想到多态降低耦合是一个好习惯。
- 使用独立的配置类管理第三方bean
@Configuration
public class JdbcConfig {
@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("root");
return ds;
}
}
问题:这个配置类如何能被Spring配置类加载到,并创建DataSource对象在IOC容器中?
解决方案:使用包扫描引入(不推荐);使用@Import精准引入(推荐,直接能看出导入了哪些配置类)
方式一:导入式(推荐)
public class JdbcConfig {
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
//相关配置
return ds;
}
}
使用@Import注解手动加入配置类到核心配置,此注解只能添加一次,多个数据用数组形式
@Configuration
@Import({JdbcConfig.class})
public class SpringConfig {
}
方式二:扫描式(不推荐)
@Configuration //SpringConfig使用了@ComponentScan,这里必须加@Configuration注解
public class JdbcConfig {
@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("root");
return ds;
}
}
使用@ComponentScan注解扫描配置类所在的包,加载对应的配置类信息
@Configuration
@ComponentScan("com.itheima.config")
public class SpringConfig {
}
- 第三方bean注入资源
- 简单类型依赖注入
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("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;
}
}
引用类型依赖注入
需求:假设在构建DataSource对象的时候,需要用到BookDao对象,该如何把BookDao对象注入进方法内让其使用呢
方案:
在SpringConfig中扫描BookDao
@Configuration
@ComponentScan("com.itheima.dao")
@Import({JdbcConfig.class})
public class SpringConfig {
}
在JdbcConfig类的方法上添加参数
//@Configuration
public class JdbcConfig {
@Bean
public DataSource dataSource(BookDao bookDao){ //假如要用到bookDao,这样直接以形参的格式就可以自动注入
System.out.println(bookDao);
DruidDataSource ds = new DruidDataSource();
//属性设置
return ds;
}
}
引用类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装配对象
1.6 注解开发总结
XML配置与注解配置比较
2 Spring整合MyBatis
2.1 思路分析
- MyBatis程序核心对象分析
问题:哪些对象可以交给Spring来管理
答:SqlSessionFactory - 分析MyBatis配置文件
2.2 具体实现
- 导入整合需要的spring-jdbc、mybatis-spring依赖
<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>
- 创建Spring的主配置类
//配置类注解
@Configuration
//包扫描,根据定义的扫描路径,把符合扫描规则的类作为Bean装配到IOC容器中
@ComponentScan("com.itheima")
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;
}
}
- 主配置类中读properties并引入数据源配置类
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import(JdbcConfig.class)
public class SpringConfig {
}
- 创建Mybatis配置类并配置SqlSessionFactory
public class MybatisConfig {
//定义bean,SqlSessionFactoryBean,用于快速创建SqlSessionFactory对象
@Bean
//SqlSessionFactoryBean内部实现FactoryBean接口的getObject方法返回SqlSessionFactory,所以这里返回SqlSessionFactoryBean即可
//为外部配置类注入引用数据类型DataSource,IOC里是有DataSource对象的,有扫描第三方配置类JdbcConfg
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
//SqlSessionFactoryBean是FactoryBean的子类,用于封装sqlSessionFactory的环境信息,Mybatis核心配置中的typeAliases,environments
//FactoryBean是一种创建bean的方法
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
//设置模型类的别名扫描
ssfb.setTypeAliasesPackage("com.itheima.domain");
//设置数据源,这里数据源对象是bean
ssfb.setDataSource(dataSource);
//应该还有一步设置事务处理,暂且不设置,前面导入的spring-jdbc包是可以事务处理的
return ssfb;
}
//定义bean,返回映射扫描配置器对象MapperScannerConfigurer,设置映射在哪个包下。
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.itheima.dao");
return msc;
}
}
- 主配置类中引入Mybatis配置类
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
public class SpringConfig {
}
- 配置MybatisConfig后service就可以直接调用dao的方法
因为SqlSessionFactory和MapperScannerConfigurer已经在bean里了
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
public void save(Account account) {
accountDao.save(account);
}
public void update(Account account){
accountDao.update(account);
}
public void delete(Integer id) {
accountDao.delete(id);
}
public Account findById(Integer id) {
return accountDao.findById(id);
}
public List<Account> findAll() {
return accountDao.findAll();
}
}
- 运行类
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(2);
System.out.println(ac);
}
}
运行结果:
3 Spring整合Junit
整合Junit与整合Druid和MyBatis差异比较大,为什么呢?Junit是一个搞单元测试用的工具,它不是我们程序的主体,也不会参加最终程序的运行,从作用上来说就和之前的东西不一样,它不是做功能的,看做是一个辅助工具就可以了
- 导入Junit和spring-test依赖
<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,使用Spring整合Junit专用的类加载器
//设置类运行器
@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());
}
}