文章目录
一、Spring中IOC常用注解
1.用于创建对象
他们的作用和在xml中编写一个bean标签实现的功能是一样的
@Component作用:用于把当前类对象存入spring容器中(beans.xml配置约束context)
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 告知spring在创建容器的时候要扫描的包,配置conext名称空间和约束,在croe中搜索xmlns:context-->
<context:component-scan base-package="com.ming"></context:component-scan>
</beans>
value属性:用于指定bean的id,不写时默认是当前类名首字母小写
@Component衍生的注解:
@controller:一般用在表现层
@service:一般用在业务层
@Repository:一般用在持久层
这三个注解作用和属性与component一样,spring框架提供的明确的三层使用注解,使我们的三层对象更加清晰
2.用于注入数据的
他们的作用和在xml中的bean标签内写一个property标签作用是一样的
@Autowired作用:自动按照类型注入。先按类型找,然后按名称找。只要容器中有唯一的一个bean对象类型和注入的变量类型匹配,就可以注入成功
出现位置:变量和方法上
@Qualifier作用:按照类型注入的基础之上再按照名称注入。它在给类成员注入的时候不能单独使用必须和Autowired组合一起使用,在给方法参数注入的时候可以单独使用。
@Resource作用:按照名称注入,可以单独使用。先按名称找,然后按类型找
属性name:用于指定bean的id
总结:以上三个注解注入数据的时候只能注入bean类型的数据,而基本类型和String类型无法使用上述注解实现,另外集合类型的注入只能通过xml来实现
@value:注入基本数据类型和String类型的数据
属性:value用于指定数据的值,可以使用SpEL(EL表达式),spel写法:${}
3.用于改变作用范围的
他们的作用和在bean标签上使用scpoe属性是一样的
@scope作用:用于指定bean的作用范围
value:指定范围的取值 singleton prototype
4.生命周期相关的
他们的作用就和在bean标签中使用init-method和destroy-method是一样的
@PreDestroy作用用于销毁方法 @PostConstruct用于初始化方法
二、基于xml的IOC案例
1.引入依赖
持久层用的是dbutils
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
</dependencies>
mysql:创建表
CREATE TABLE account (
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(40),
money float
)CHARACTER SET utf8 COLLATE utf8_general_ci;
2.案例代码
创建业务层接口:
package com.ming.service;
import com.ming.model.Account;
import java.util.List;
/**
* 账户业务层接口
*/
public interface IAccountService {
/**
* 查找所有的账户
*
* @return
*/
List<Account> findAll();
/**
* 按照id查找账户
*
* @param id
* @return
*/
Account findById(Integer id);
/**
* 保存
*
* @param account
*/
void saveAccount(Account account);
/**
* 更新
*
* @param account
*/
void updateAccount(Account account);
/**
* 删除
*
* @param id
*/
void deleteAccount(Integer id);
/**
* @param sourceName 转出账户
* @param targetName 转入账户
* @param money 金额
*/
public void transfer(String sourceName, String targetName, Float money);
}
业务层实现类:
package com.ming.service.impl;
import com.ming.dao.IAccountDao;
import com.ming.model.Account;
import com.ming.service.IAccountService;
import com.ming.util.TransacationManger;
import java.util.List;
/**
* 账户的业务层实现类
*/
public class AccountServiceImpl implements IAccountService {
//最早的写法
//private IAccountDao accountDao = new AccountDaoImpl();
//BeanFactory读取配置的bean.properties的dao
//private IAccountDao accountDao= (IAccountDao) BeanFactory.getBean("accountDao");
private IAccountDao accountDao;
private TransacationManger tx;
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
public void setTx(TransacationManger tx) {
this.tx = tx;
}
@Override
public List<Account> findAll() {
return accountDao.findAll();
}
@Override
public Account findById(Integer id) {
return accountDao.findById(id);
}
@Override
public void saveAccount(Account account) {
accountDao.saveAccount(account);
}
@Override
public void updateAccount(Account account) {
accountDao.updateAccount(account);
}
@Override
public void deleteAccount(Integer id) {
accountDao.deleteAccount(id);
}
@Override
public void transfer(String sourceName, String targetName, Float money) {
Account sourceAccount = accountDao.findAccountByName(sourceName);
sourceAccount.setMoney(sourceAccount.getMoney() - money);
accountDao.updateAccount(sourceAccount);
Account targetAccount = accountDao.findAccountByName(targetName);
int a = 4 / 0;
targetAccount.setMoney(targetAccount.getMoney() + money);
accountDao.updateAccount(targetAccount);
}
}
账户持久层接口:
package com.ming.dao;
import com.ming.model.Account;
import java.util.List;
/**
* 账户的持久层接口
*/
public interface IAccountDao {
List<Account> findAll();
Account findById(Integer id);
void saveAccount(Account account);
void updateAccount(Account account);
void deleteAccount(Integer id);
//根据账户名称查询账户,为了演示事物准备
Account findAccountByName(String accountName);
}
账户持久层实现类:
package com.ming.dao.impl;
import com.ming.dao.IAccountDao;
import com.ming.model.Account;
import com.ming.util.ConnectionThredUtil;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import java.util.List;
public class AccountDaoImpl implements IAccountDao {
private QueryRunner queryRunner;
private ConnectionThredUtil conn;
public void setQueryRunner(QueryRunner queryRunner) {
this.queryRunner = queryRunner;
}
public void setConn(ConnectionThredUtil conn) {
this.conn = conn;
}
public List<Account> findAll() {
try {
return queryRunner.query(conn.getThredConnection(), "select * from account ", new BeanListHandler<Account>(Account.class));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public Account findById(Integer id) {
try {
return queryRunner.query(conn.getThredConnection(), "select * from account where id = ? ", new BeanHandler<Account>(Account.class), id);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void saveAccount(Account account) {
try {
queryRunner.update(conn.getThredConnection(), "insert into account(name,money) values(?,?)", account.getName(), account.getMoney());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void updateAccount(Account account) {
try {
queryRunner.update(conn.getThredConnection(), "update account set name=? ,money=? where id=? ", account.getName(), account.getMoney(), account.getId());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void deleteAccount(Integer id) {
try {
queryRunner.update(conn.getThredConnection(), "delete account where id=?", id);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public Account findAccountByName(String accountName) {
try {
return queryRunner.query(conn.getThredConnection(), "select * from account where name = ? ", new BeanHandler<Account>(Account.class), accountName);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
bean.xml配置:
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- =============基于xml的IOC配置===============-->
<!-- 配置service对象-->
<bean id="accountService" class="com.ming.service.impl.AccountServiceImpl">
<!-- 注入dao对象-->
<property name="accountDao" ref="accountDao"></property>
</bean>
<!-- 配置dao对象-->
<bean id="accountDao" class="com.ming.dao.impl.AccountDaoImpl">
<!-- 注入queryRunner对象-->
<property name="queryRunner" ref="runner"></property>
</bean>
<!-- 配置QueryRunner,它是单例对象所以配置作用域scope-->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!--注入数据源没有提供set方法,只能用构造函数注入-->
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
<!--注入数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--注入连接数据库的必备信息-->
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>
</beans>
基于XML的IOC配置用Junit测试
package com.ming.test;
import com.ming.model.Account;
import com.ming.service.IAccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
/**
* 基于xml的IOC配置使用Junit单元测试
*/
public class AccountServiceTest {
@Test
public void testFindAll() {
//1.获取容器
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//2.得到业务层对象
IAccountService accountService = (IAccountService) context.getBean("accountService");
List<Account> accountList = accountService.findAll();
System.out.println(accountList);
}
@Test
public void testFindById() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
IAccountService accountService = (IAccountService) context.getBean("accountService");
Account account = accountService.findById(1);
System.out.println(account);
}
@Test
public void testSaveAccount() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
IAccountService accountService = (IAccountService) context.getBean("accountService");
Account account = new Account();
account.setName("aaa");
account.setMoney(1000f);
accountService.saveAccount(account);
}
@Test
public void testUpdateAccount() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
IAccountService accountService = (IAccountService) context.getBean("accountService");
Account account = new Account();
account.setName("aaa");
account.setMoney(1000f);
accountService.updateAccount(account);
}
@Test
public void testDeleteAccount() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
IAccountService accountService = (IAccountService) context.getBean("accountService");
accountService.deleteAccount(1);
}
}
三、Spring的新注解
@configuration
作用:指定当前类是一个配置类 等同于bean.xml
细节:当配置作为AnnotationConfigApplictionContext创建对象的参数时,可以不写。
扫描包的时候首先会扫描这个包下的类,首先这个类要是一个配置类,才会去扫描这个类中的注解
@ComponentScan
作用:用于通过注解告知spring在创建容器时要扫描的包
属性value和basePackages可以互换:它和beans.xml中base-package的作用是一样的,都是用于指定创建容器时要扫描的包。
等同于: <context:component-scan base-package=“com.ming”></context:component-scan>
@Bean
作用在方法上,表示通过方法来定义一个bean,默认方法的名称作为bean的名称,将方法的返回值作为bean对象,注册到spring容器中
@import
用于导入其他配置类
@PropertySource
用于指定properties文件的位置
纯注解的方式和xml的方式比起来更费劲,尽量选择xml和注解结合使用。
属性value:用于指定文件名称和路径 关键字classpath:类路径下的文件
总结:如果是第三方jar用xml,本地代码用注解方便
1.基于注解的IOC
1.bean.xml配置
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- =============基于注解的IOC配置===============-->
<!--告知spring创建容器时要扫描的包-->
<context:component-scan base-package="com.ming"></context:component-scan>
<!-- 配置QueryRunner,它是单例对象所以配置作用域scope-->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!--注入数据源没有提供set方法,只能用构造函数注入-->
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
<!--注入数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--注入连接数据库的必备信息-->
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3307/test"></property>
<property name="user" value="liming"></property>
<property name="password" value="liming"></property>
</bean>
</beans>
总结:bean.xml中有两个配置没有用注解(第三方jar和component-scan),用@Bean注解解决。
Spring配置类:
package com.ming.config;
import com.ming.util.JdbcProConfig;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
/**
* 该类是一个配置类,它的作用和bean.xml是一样的
*/
@Configuration
@ComponentScan(basePackages = {"com.ming"})
@PropertySource("classpath:jdbc.properties")
@Import(value = JdbcProConfig.class)
public class SpringConfiguration {
}
当 @ComponentScan(basePackages = {"com.ming"})注解出现时,bean.xml中的 <context:component-scan base-package="com.ming"></context:component-scan>配置可以注释掉,因为作用是相同的。
jdbc.properties文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3307/test
user=liming
pwd=liming
@Import导入类:
package com.ming.util;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import javax.sql.DataSource;
/**
* jdbc配置类,用于@import注解导入
*/
public class JdbcProConfig {
@Value("${driver}")
private String driver;
@Value("${url}")
private String url;
@Value("${user}")
private String user;
@Value("${pwd}")
private String pwd;
/**
* 该注解可以将一个方法的返回值注册到spring容器中
* @param dataSource
* @return
*/
@Bean(name="queryRunner")
@Scope("prototype")
public QueryRunner getQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
@Bean(name="dataSource")
public DataSource getDataSource() {
try {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(user);
dataSource.setPassword(pwd);
return dataSource;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
2.spring整合Junit
分析:
1.应用程序的入口 main方法
2.junit单元测试中,没有main方法也能执行,junit集成了main方法,该方法会判断当前类中哪些方法有@test注解,Junit就会让@test注解的方法执行
3.junit不会管我们是否采用spring框架,在执行测试方法的时候Junit根本不会知道我们使用了spring框架,所以也就不会为我们读取配置文件/配置类,也就不会为我们创建spring核心容器。
4。总结以上三点可知,当我们执行测试方法时,没有IOC容器,就算写了@AutoWired注解,也无法实现注入。
所以在执行test方法时,要创建spring核心容器。
spring整合Junit的配置:
1.导入spring整合Junit的jar(spring-test)
2.使用spring提供的一个注解把原有的main方法替换了,替换成spring提供的@RunWith(SpringJUnit4ClassRunner.class)
3.告知spring的运行器,spring的IOC创建时基于xml还是注解的,并说明位置 locations指定xml的文件位置 classes指定注解类所在的位置@ContextConfiguration(classes = SpringConfiguration.class)
package com.ming.test;
import com.ming.config.SpringConfiguration;
import com.ming.model.Account;
import com.ming.service.IAccountService;
import com.ming.util.AccountProxy;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AccountTest {
@Autowired
private IAccountService accountService;
@Test
public void addTest() {
Account account = new Account();
account.setName("ddd");
account.setMoney(1000f);
accountService.saveAccount(account);
}
@Test
public void findAllTest() {
List<Account> li = accountService.findAll();
System.out.println(li);
}
}