第五章: Spring的纯注解配置:
分析第四章案例的存在的问题:
问题1:测试类中重复代码的问题(这个问题在后面讲spring整合Junit的时候来解决)
问题2:不管是xml文件配置还是注解进行配置,都离不开配置文件(两个约束不同的配置文件)
spring中的新注解
(1)@Configuration注解
@Configuration
作用:指定当前类是一个配置类,它的作用和bean.xml是一样的
位置:类上
细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。
(2)@ComponentScan 和 @ComponentScans
@ComponentScan
作用:用于通过注解指定spring在创建容器时要扫描的包
位置: 类上
属性:
basePackages属性:指定创建容器时要扫描的包
value属性:它和basePackages属性的作用是一样的,都是用于指定创建容器时要扫描的包。
注意:
@ComponentScan(value="com.zy")我们使用此注解就等同于在xml中配置了:
<context:component-scan base-package="com.zy"></context:component-scan>
@ComponentScans
作用:用于通过注解指定spring在创建容器时要扫描的多个包
(就是 @ComponentScan的一个集合)
(3) @Bean
@Bean
作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中,带有该注解的方法会自动在容器中找对象进行传入
位置: 方法上面
属性:
name属性:用于指定bean的id。当不写时,默认值是当前方法的名称
细节:
当我们使用@Bean注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象。
查找的方式和@Autowired注解的作用是一样的(按照类型自动注入)(先根据形参类型选着,再根据形参名选着)
(4) @Scope
@Scope
作用:说明作用范围
位置:
在配置类中可以和@Bean放到创建Bean对象的方法上
属性:
singleton(单例) prototype(多例)
(5) 通过上面几个注解,来使用纯注解的方式改造上面案例的bean.xml文件
//声明该类是配置类
@Configuration
//扫描 com.itheima 这个包
@ComponentScan("com.itheima")
public class SpringConfiguration {
//创建QueryRunner的Bean对象,该方法会传入一个DataSource对象,该对象会在容器中寻找
@Bean(name="runner")
//声明作用范围
@Scope("prototype")
public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
//创建一个DataSource对象,放到容器中
@Bean(name="dataSource")
public DataSource createQueryDateSource() {
ComboPooledDataSource ds = new ComboPooledDataSource();
try {
ds.setDriverClass("com.mysql.cj.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/mybatis_damo1?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false");
ds.setUser("root");
ds.setPassword("015718");
} catch (PropertyVetoException e) {
e.printStackTrace();
}
return ds;
}
}
----------------------------------------------------------------------------------------------------------------------------------------
测试方法怎么写??
不在使用bean.xml文件,使用配置类的方式,怎么进行加载配置类??
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
(6)@Import
@Import
作用:用于导入其他的配置类
位置:类上
属性:
value:用于指定其他配置类的字节码。
当我们使用Import的注解之后,有Import注解的类就父配置类,而导入的都是子配置类
(7) @PropertySource
@PropertySource
作用:用于指定properties文件的位置
属性:
value:指定文件的名称和路径。
关键字:classpath,表示类路径下
(8)把上面配置类进行改造
在(5)里面数据库已经写死,进行改造
//声明为配置类
@Configuration
//声明要扫描的包
@ComponentScan("com.itheima")
//要导入的其他的配置类
@Import(JdbcConfig.class)
//要加载的配置文件(classpath:代表为使用类路径)
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration {
}
-----------------------------------------------------------------------------------------------------------------------------------------
public class JdbcConfig {
//使用@Value标签来给属性赋值,使用#{}来引用配置文件中的值
@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(name="runner")
@Scope("prototype")
public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
@Bean(name="dataSource")
public DataSource createQueryDateSource() {
ComboPooledDataSource ds = new ComboPooledDataSource();
try {
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
return ds;
}
}
(9) @Qualifier注解的另一种用法
- 用法一:
- 上面讲过
@Resource注解可以和@Autowired注解一起使用,指定使用容器中的哪一个对象给属性赋值
- 上面讲过
- 用法二:
- 在配置类中在方法上使用@Bean标签创建Bean对象的时候,当方法需要一个形参的时候,会自动在容器中找符合要求的Bean对象
- 当容器中有多个符合要求的Bean对象的时候,可以使用@Resource注解指定使用哪一个对象
@Qualifier另一种用法
作用:
指定要配置文件中创建Bean对象的方法,传入哪一个容器中的Bean对象
位置:
在创建对象的形参上面
属性:
name属性: 指定要使用那个Bean对象的id
@Bean(name="runner")
@Scope("prototype")
public QueryRunner createQueryRunner(@Qualifier("ds1") DataSource dataSource){
return new QueryRunner(dataSource);
}
@Bean(name="ds1")
public DataSource createQueryDateSource1() {
ComboPooledDataSource ds = new ComboPooledDataSource();
try {
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
return ds;
}
@Bean(name="ds2")
public DataSource createQueryDateSource2() {
ComboPooledDataSource ds = new ComboPooledDataSource();
try {
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
return ds;
}
第六章 Spring整合Junit
在第五章的时候,解决了案例中还有使用Bean配置文件问题,使用了纯注解
还有一个问题就是:测试类中重复代码的问题
在Junit中以前学过两个注解:
@Before 每个测试方法运行之前都会运行一次。
@After是每个测试方法执行以后都会被执行一次。
步骤:
(1) 导入spring整合的Junit的jar包(坐标)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
(2) 使用Junit提供的一个注解把原来的maini方法替换掉了,替换成spring提供的注解
@Runwith(SpringJUnit4ClassRunner.class) (main方法的运行器)
位置: 类上
(3) 告诉spring的运行器,spring的创建是基于xml文件的还是基于注解的
@ContextConfiguration
属性:
locations:指定xml文件的位置,加上classpath关键字,表示在类路径下
classes:指定注解类所在地位置
位置:
类上
在Junit的测试类中就可以使用容器中的Bean对象,在Junit的测试类中的属性上添加上@Autowired可以实现属性的自动注入
(4) 注意事项:
当我们使用spring 5.x版本的时候,要求junit的jar必须是4.12及以上
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AccountServiceTest {
//测试类中的属性,在容器中自动的注入Bean对象
@Autowired
private IAccountService as = null;
@Test
public void testFindAll() {
//3.执行方法
List<Account> accounts = as.findAllAccount();
for(Account account : accounts){
System.out.println(account);
}
}
@Test
public void testFindOne() {
//3.执行方法
Account account = as.findAccountById(1);
System.out.println(account);
}
@Test
public void testSave() {
Account account = new Account();
account.setName("test anno");
account.setMoney(12345f);
//3.执行方法
as.saveAccount(account);
}
@Test
public void testUpdate() {
//3.执行方法
Account account = as.findAccountById(4);
account.setMoney(23456f);
as.updateAccount(account);
}
@Test
public void testDelete() {
//3.执行方法
as.deleteAccount(4);
}
}