spring第二天ioc和注解
一、学习目标
- 掌握外部属性文件注入
- 掌握半xml半注解方式开发模式(必须掌握)
- 掌握全注解方式开发模式
- 掌握spring跟junit测试适配
二.外部属性文件注入
在实际开发中我们通常会有数据库连接账号密码 redis连接池账号密码 秘钥之类的属性需要配置
例如我们的数据库连接池配置
<!-- 导入mysql驱动包的依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!-- 导入druid连接池的依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<!-- 导入hikari的依赖 -->
<dependency>
<groupId>hikari-cp</groupId>
<artifactId>hikari-cp</artifactId>
<version>1.7.6</version>
</dependency>
2.1最原始的配置
<!--
配置druid的数据库连接池
功能最全的 性能也牛逼的
-->
<bean id="dataSource0" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/heima29"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!--hikari数据连接池 据说性能之王-->
<bean id="dataSource1" class="com.zaxxer.hikari.HikariDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/heima29"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
上述配置自然是没有问题 但是有个缺点就是 讲属性配置到了spring的核心配置文件中 不容易查找和维护
2.2使用外部属性注入的方式
2.2.1 先创建一个外部属性文件 放在resources目录下
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/heima29
jdbc.username=root
jdbc.password=123456
2.2.2 在spring的配置文件修改外部属性注入
<!--
配置外部properties属性位置信息
classpath: 类路径的意思
-->
<context:property-placeholder location="classpath:db.properties"/>
<!--
下方使用属性的方式 可以使用${属性名的方式}
-->
<bean id="dataSource0" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"></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="dataSource1" class="com.zaxxer.hikari.HikariDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
可以看出这种方式 维护更加自由 需要修改数据库配置的 不用打开xml配置文件 直接找到db.properties就行了
三、掌握半xml半注解方式开发模式(学习springboot之前都是这么玩的)
通过上述的学习过程中,我们可以在spring的配置文件中 配置我们业务需要的对象
<!--
配置外部properties属性位置信息
classpath: 类路径的意思
-->
<context:property-placeholder location="classpath:db.properties"/>
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource0"></property>
</bean>
<bean id="dataSource0" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--
随着业务的开发 我们会在spring配置文件
配置越来越多的bean标签
-->
<bean id="xx" class="a.b.c.x">
<bean id="yy" class="a.b.c.y">
<bean id="zz" class="a.b.c.z">
.......
这种方式最终会导致spring配置文件的膨胀 查找和维护工作十分费力
❤️接下来我们学习半xml半注解的方式 来做ioc配置 简化开发❤️
3.1 首先修改配置配置文件
<!--
通过包扫描的方式 告诉spring框架 我的东西都在哪个包下放着呢
多个包 以,分割开来
所谓包扫描 原理就是找到那个文件遍历文件夹 查找这个文件夹的所有的文件名
-->
<context:component-scan base-package="com.itheima.service,com.itheima.dao"/>
<!--
注意事项:
先保留下来 一些不是我们写的类 比如连接池对象之类 因为那些类不是我们写的
-->
3.2 修改代码 添加注解
service代码
package com.itheima.service.impl;
import com.itheima.dao.AccountDao;
import com.itheima.pojo.Account;
import com.itheima.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
*
* 这里我们可以采用@Component注解或者@Service 注解
* 建议使用@Service 注解 更加见名知意
* 而且可以起名字 默认不写就是类名
*/
//@Component
@Service("AccountServiceImpl")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public void save(Account account) {
accountDao.save(account);
}
@Override
public Account findById(int id) {
return accountDao.findById(id);
}
@Override
public void update(Account account) {
accountDao.update(account);
}
@Override
public void del(int id) {
accountDao.del(id);
}
}
dao代码
package com.itheima.dao.impl;
import com.itheima.dao.AccountDao;
import com.itheima.pojo.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
*
* 这里我们可以采用@Component注解或者@Repository 注解
* 建议使用@Repository注解 更加见名知意
* 而且可以起名字
*/
//@Component
@Repository("AccountDaoImpl")
public class AccountDaoImpl implements AccountDao {
/*@Autowired
@Qualifier("dataSource1")*/
@Resource(name="dataSource1")
private DataSource dataSource;
@Override
public void save(Account account) {
System.out.println("保存账户信息");
}
@Override
public Account findById(int id) {
System.out.println("正在根据id查询账户信息");
try {
Connection connection = dataSource.getConnection();
System.out.println(connection);
} catch (SQLException e) {
e.printStackTrace();
}
return new Account();
}
@Override
public void update(Account account) {
System.out.println("正在更新账户信息");
}
@Override
public void del(int id) {
System.out.println("正在根据id删除账户信息");
}
}
测试代码
@Test
public void test01() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
AccountService accountService = context.getBean(AccountService.class);
accountService.findById(1);
}
3.3常用的注解
3.3.1@Component(value="")注解
-
标记在类上,也可以放在接口上
-
注解作用:把AccountDao实现类对象交由Spring IOC容器管理
-
相当于XML配置文件中的Bean标签
<bean id="accountDao" class="com.itheima.dao.AccountDao"/>
-
-
注解Value属性:相当于bean标签id,对象在IOC容器中的唯一标识,可以不写,默认值是当前类首字母缩写的类名。
-
三个衍射注解分别是:@Controller,@Service,@Repository。
- 作用与@Component注解一样
- 设计初衷增加代码的可读性,体现三层架构
- @Controller一般标注在表现层
- @Service一般标注在业务层
- @Repository一般 标注在持久层
-
❤️注意事项:
组件可以起名 但是建议不要起名 它的默认名字就是类名 首字母小写
3.3.2@Autowired注解
-
标记在成员变量或set方法上
-
注解作用:自动将ioc容器中的对象注入到当前的成员变量中。
-
默认按照变量数据类型注入,如果数据类型是接口,注入接口实现类。
-
相当于XML配置文件中的property标签
<property name="accountDao" ref="accountDao"/>
-
-
按照变量的数据类型注入
-
注意事项:
- 它只能注入其他的bean类型
- 成员变量的接口数据类型,有多个实现类的时候,要使用bean的id注入,否则会报错。
- Spring框架提供的注解
-
指定Bean的id,使用@Qualifier的注解配合,@Qualifier注解的value属性指定bean的id
3.3.3@Resource(name="")注解
-
标记在成员变量或set方法上
-
注解作用:相当于@Autowired的注解与@Qualifier的注解合并了。直接按照bean的id注入。
-
相当于XML配置文件中的property标签
<property name="accountDao" ref="accountDao"/>
-
-
name属性:指定bean的id
-
如果不写name属性则按照变量数据类型注入,数据类型是接口的时候注入其实现类。如果定义name属性,则按照bean的id注入。
-
Java的JDK提供本注解
四、掌握全注解方式开发模式
4.1 复制上面的半xml半注解的代码 将配置文件删除
4.2 编写注解配置类
package com.itheima.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.itheima.pojo.User;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import javax.sql.DataSource;
/**
* @Configuration 这个注解意思 表示 该类就替代了beans.xml
* @ComponentScan 作用等同于<context:component-scan base-package= "com.itheima.service,com.itheima.dao"></context:component-scan>
* @PropertySource 作用等同于 <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
*
* @Import 导入其他的配置类 分模块配置 便于维护
*
*/
@Configuration
@ComponentScan({"com.itheima.service","com.itheima.dao"})
@Import({DataSourceConfig.class})
public class SpringConfig {
/*我想放一个user对象进去行不行?*/
/* @Bean
public User xxx(){
return new User();
}*/
}
package com.itheima.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
@PropertySource("classpath:db.properties")
public class DataSourceConfig {
@Value("${jdbc.driverClassName}")
private String className;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/**
* @Bean
* 表示就该方法的返回值 放入到容器里 名字自己起名
* 万一你忘记起名字 或者你对名字不敏感 它有默认名字 默认名字就是方法名字
* @return
*/
@Bean("dataSource0")
public DataSource createDruidDatasource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(className);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
@Bean("dataSource1")
public DataSource createHikariDatasource(){
HikariDataSource hikariDataSource = new HikariDataSource();
hikariDataSource.setDriverClassName(className);
hikariDataSource.setJdbcUrl(url);
hikariDataSource.setUsername(username);
hikariDataSource.setPassword(password);
return hikariDataSource;
}
}
4.3 纯注解开发IOC需要的注解
无XML配置文件beans.xml
4.3.1@Configuration注解
标记在类上
注解作用:作用等同于beans.xml配置文件,当前注解声明的类中,编写配置信息,所以我们把@Configuration声明的类称之为配置类
4.3.2@Import注解
标记在类上
注解作用:导入其他配置类(对象)
相当于XML配置文件中的标签
<import resource="classpath:applicationContext-dao.xml"/>
4.3.3@PropertySource注解
标记在类上
注解作用:引入外部属性文件(db.properties)
相当于XML配置文件中的context:property-placeholder标签
<context:property-placeholder location="classpath:jdbc.properties"/>
4.3.4@Value注解
标记在成员变量或set方法上,有点类似于@Autowired
注解作用:给简单类型变量赋值
相当于XML配置文件中的标签
<property name="driverClass" value="${jdbc.driver}"/>
4.3.5@Bean注解
标记在配置类中的方法上
注解作用:将方法的返回值存储到Spring IOC容器中
相当于XML配置文件中的标签
<bean id="accountDao" class="com.itheima.dao.AccountDaoImpl"/>
4.3.6@ComponentScan(“com.itheima”)注解
标记在配置类上
注解作用:扫描注解,相当于beans.xml中的注解扫描配置<context:component-scan base-package="com.itheima"/>
相当于XML配置文件中的context:component-scan标签
<context:component-scan base-package="com.itheima"/>
注意:扫描的包路径不写,扫描当前包及其子包!
其他了解的注解
@Scope(“prototype”)
标记在类上,配合@Component使用
注解作用:指定对象的作用范围:单例模式(singleton)还是多例模式(prototype)
生命周期注解
@PostConstruct ==> init-method
@PreDestroy ==> destroy-method
五、掌握spring跟junit测试适配
5.1 导入maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<!-- junit版本至少是4.12以上-->
<!-- junit版本至少是4.12以上-->
<!-- junit版本至少是4.12以上-->
<!-- junit版本至少是4.12以上-->
<!-- junit版本至少是4.12以上-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
5.2 编写测试类
package com.itheima;
import com.itheima.pojo.User;
import com.itheima.service.UserService;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* spring 想好了 已经封装了
*/
@RunWith(SpringJUnit4ClassRunner.class)
///xml方式用这个
@ContextConfiguration(locations = "classpath:beans.xml")
//注解方式用这个
//@ContextConfiguration(classes = SpringConfig.class)
public class App1Test {
@Autowired
private UserService userService;
@Test
public void test01() {
userService.login("zhansgan","123");
}
@Test
public void test02() {
userService.save(new User());
}
}