Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代 替xml配置文件可以简化配置,提高开发效率。
1. Spring常用注解
1.1 介绍
Spring常用注解主要是替代<bean> 的配置
注解 | 说明 |
@Component | 使用在类上用于实例化Bean |
@Controller | 使用在web层类上用于实例化Bean |
@Service | 使用在service层类上用于实例化Bean |
@Repository | 使用在dao层类上用于实例化Bean |
@Autowired | 使用在字段上用于根据类型依赖注入 |
@Qualifier | 结合@Autowired一起使用,根据名称进行依赖注入 |
@Resource | 相当于@Autowired+@Qualifier,按照名称进行注入 |
@Value | 注入普通属性 |
@Scope | 标注Bean的作用范围 |
@PostConstruct | 使用在方法上标注该方法是Bean的初始化方法 |
@PreDestroy | 使用在方法上标注该方法是Bean的销毁方法 |
说明:
JDK11以后完全移除了javax扩展导致不能使用@resource注解
需要maven引入依赖
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
注意
使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包 下的Bean需要进行扫描以便识别使用注解配置的类、字段和方法。
<!--注解的组件扫描-->
<context:component-scan base-package="com.lagou"></context:component-scan>
1.2 实现
(1)Bean实例化(IOC)
<bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"></bean>
使用@Compont或@Repository标识UserDaoImpl需要Spring进行实例化。
// @Component(value = "userDao")
@Repository // 如果没有写value属性值,Bean的id为:类名首字母小写
public class UserDaoImpl implements UserDao {
}
(2)属性依赖注入(DI)
<bean id="userService" class="com.lagou.service.impl.UserServiceImpl">
<property name="userDao" ref="userDaoImpl"/>
</bean>
使用@Autowired或者@Autowired+@Qulifier或者@Resource进行userDao的注入
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
// <property name="userDao" ref="userDaoImpl"/>
// @Autowired
// @Qualifier("userDaoImpl")
// @Resource(name = "userDaoImpl")
public void setUserDao(UserDao userDao) { this.userDao = userDao;
}
}
(3)@Value
使用@Value进行字符串的注入,结合SPEL表达式获得配置参数
@Service
public class UserServiceImpl implements UserService {
@Value("注入普通数据") private String str; @Value("${jdbc.driver}") private String driver;
}
(4)@Scope
<bean scope=""/>
使用@Scope标注Bean的范围
@Service @Scope("singleton")
public class UserServiceImpl implements UserService {{
}
(5)Bean生命周期
<bean init-method="init" destroy-method="destory" />
使用@PostConstruct标注初始化方法,使用@PreDestroy标注销毁方法
@PostConstruct public void init(){
System.out.println("初始化方法 ");
}
@PreDestroy
public void destroy(){ System.out.println("销毁方法 ");
}
1.3 Spring新注解
使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下:
- 非自定义的Bean的配置:<bean>
- 加载properties文件的配置:<context:property-placeholder>
- 组件扫描的配置:<context:component-scan>
- 引入其他文件:<import>
注解 | 说明 |
@Configuration | 用于指定当前类是一个Spring 配置类,当创建容器时会从该类上加载注解 |
@Bean | 使用在方法上,标注将该方法的返回值存储到 Spring 容器中 |
@PropertySource | 用于加载 properties 文件中的配置 |
@ComponentScan | 用于指定 Spring 在初始化容器时要扫描的包 |
@Import | 用于导入其他配置类 |
2. Spring纯注解整合DbUtils
2.1 编写Spring核心配置类
SpringConfig类
package com.lagou.config;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import javax.sql.DataSource;
@Configuration
@ComponentScan("com.lagou")
@Import(DataSourceConfig.class)
//@PropertySource("classpath:jdbc.properties")
public class SpringConfig {
@Bean("queryRunner")
public QueryRunner getQueryRunner(@Autowired DataSource dataSource){
QueryRunner queryRunner = new QueryRunner(dataSource);
return queryRunner;
}
}
DataSourceConfig类
package com.lagou.config;
import com.alibaba.druid.pool.DruidDataSource;
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:jdbc.properties")
public class DataSourceConfig {
@Value("${jdbc.driverClassName}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean("dataSource")
public DataSource getDataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(driver);
druidDataSource.setUrl(url);
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
return druidDataSource;
}
}
2.2 其它类采用纯注解方式
AccountDaoImpl类
package com.lagou.dao.impl;
import com.lagou.dao.AccountDao;
import com.lagou.domain.Account;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.sql.SQLException;
import java.util.List;
@Repository //相当于配置了bean标签
public class AccountDaoImpl implements AccountDao {
@Autowired
private QueryRunner queryRunner;
public List<Account> findAll() {
List<Account> list = null;
//编写sql
String sql = "select * from account";
try {
// 执行sql
list = queryRunner.query(sql, new BeanListHandler<Account>(Account.class));
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public Account findById(Integer id) {
Account query = null;
// 编写sql
String sql = "select * from account where id = ?";
try {
query = queryRunner.query(sql, new BeanHandler<Account>(Account.class),id);
} catch (SQLException e) {
e.printStackTrace();
}
return query;
}
public void save(Account account) {
String sql = "insert into account values(null,?,?)";
try {
queryRunner.update(sql,account.getName(),account.getMoney());
} catch (SQLException e) {
e.printStackTrace();
}
}
public void update(Account account) {
String sql = "update account set name = ?,money = ? where id = ?";
try {
queryRunner.update(sql,account.getName(),account.getMoney(),account.getId());
} catch (SQLException e) {
e.printStackTrace();
}
}
public void delete(Integer id) {
String sql = "delete from account where id = ?";
try {
queryRunner.update(sql,id);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
AccountServiceImpl类
package com.lagou.servlet.impl;
import com.lagou.dao.AccountDao;
import com.lagou.domain.Account;
import com.lagou.servlet.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service("accountService") //相当于配置了bean标签 id属性
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao aDao;
public List<Account> findAll() {
return aDao.findAll();
}
public Account findById(Integer id) {
return aDao.findById(id);
}
public void save(Account account) {
aDao.save(account);
}
public void update(Account account) {
aDao.update(account);
}
public void delete(Integer id) {
aDao.delete(id);
}
}
AccountServiceTest测试类
package com.lagou.test;
import com.lagou.config.SpringConfig;
import com.lagou.domain.Account;
import com.lagou.servlet.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class) //@RunWith指定junit的运行环境 SpringJUnit4ClassRunner是spring提供的作为junit运行环境的类
// @ContextConfiguration({"classpath:applicationContext.xml"})
@ContextConfiguration(classes = {SpringConfig.class})
public class AccountServiceTest {
//ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// AccountService accountService = (AccountService) classPathXmlApplicationContext.getBean("accountService");
// 当前改成了纯注解形式
/* AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
AccountService accountService = (AccountService) annotationConfigApplicationContext.getBean("accountService");*/
@Autowired
private AccountService accountService;
//测试添加
@Test
public void testSave(){
Account account = new Account();
account.setName("lucy");
account.setMoney(888d);
accountService.save(account);
}
//测试查询
@Test
public void testFindById(){
Account account = accountService.findById(3);
System.out.println(account);
}
//测试查询所有
@Test
public void testFindAll(){
List<Account> all = accountService.findAll();
for (Account account : all) {
System.out.println(account);
}
}
//测试更新
@Test
public void testUpdate(){
Account account = new Account();
account.setId(3);
account.setName("jack");
account.setMoney(2000d);
accountService.update(account);
}
//测试删除
@Test
public void testDelete(){
accountService.delete(3);
}
}
applicationContext.xml 与 jdbc.properties 直接删除
3. Spring整合Junit
3.1 普通Junit测试问题
在普通的测试类中,需要开发者手动加载配置文件并创建Spring容器,然后通过Spring相关API获得
Bean实例;如果不这么做,那么无法从容器中获得对象。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountService accountService = applicationContext.getBean(AccountService.class);
我们可以让SpringJunit负责创建Spring容器来简化这个操作,开发者可以直接在测试类注入Bean实 例;但是需要将配置文件的名称告诉它。
3.2 Spring整合Junit
步骤分析:
- 导入spring集成Junit的坐标
- 使用@Runwith注解替换原来的运行器
- 使用@ContextConfiguration指定配置文件或配置类
- 使用@Autowired注入需要测试的对象
- 创建测试方法进行测试
(1)导入spring集成Junit的坐标
(2)使用@Runwith注解替换原来的运行器
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringJunitTest {
}
(3)使用@ContextConfiguration指定配置文件或配置类
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(value = {"classpath:applicationContext.xml"}) 加载spring 核心配置文件
@ContextConfiguration(classes = {SpringConfig.class}) // 加载spring核心配置类
public class SpringJunitTest {
}
(4)使用@Autowired注入需要测试的对象
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfig.class})
public class SpringJunitTest {
@Autowired
private AccountService accountService;
}
(5)创建测试方法进行测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfig.class})
public class SpringJunitTest {
@Autowired
private AccountService accountService;
//测试查询@Test
public void testFindById() {
Account account = accountService.findById(3); System.out.println(account);
}
}
节选自拉钩教育JAVA系列课程