IoC
:Inversion of Control,控制反转。是指 把创建对象的控制权交给框架:要想得到一个对象,由原来的主动创建对象,变成自己被动接收 框架创建的对象。IoC
是Spring的核心思想之一UserDao
接口和UserDaoImpl
实现类UserDaoImpl
的实例对象(IoC方式)UserDao
及实现UserDaoImpl
UserDaoImpl
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.1.2.RELEASEversion>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
dependencies>
UserDao
及实现UserDaoImpl
UserDao
public interface UserDao {
void save();
}
UserDaoImpl
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("UserDaoImpl.save......");
}
}
UserDaoImpl
applicationContext.xml
<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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">bean>
beans>
public class SpringIocQuickStartTest {
@Test
public void test(){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = context.getBean("userDao", UserDao.class);
userDao.save();
}
}
导入依赖:spring-context
编写自己的业务代码:UserDao, UserDaoImpl
创建配置文件:applicationContext.xml
<bean id="唯一标识" class="全限定类名">bean>
创建容器,加载配置文件,从容器里获取bean对象
ApplicationContext app = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
Object obj = app.getBean("唯一标识");
bean
标签的基本配置<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">bean>
介绍
用于配置:把对象交给Spring进行控制
默认情况下,Spring是调用类的无参构造来创建对象的;如果没有无参构造,则不能创建成功
基本属性
id
:唯一标识class
:bean的全限定类名了解:bean的id和name的区别
- 一个bean只能有一个id;一个bean可以有多个name
- bean的name值:多个name之间以
,
;
空格
隔开,第1个name作为id,其它作为别名
bean
标签的作用范围配置<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" scope="singleton">bean>
取值 | 说明 |
---|---|
singleton |
默认,表示单例的,一个Spring容器里,只有一个该bean对象 |
prototype |
多例的,一个Spring容器里,有多个该bean对象 |
request |
web项目里,Spring创建的bean对象将放到request 域中:一次请求期间有效 |
session |
web项目里,Spring创建的bean对象将放到session 域中:一次会话期间有效 |
globalSession |
web项目里,应用在Portlet环境/集群环境;如果没有Portlet/集群环境,那么globalSession相当于session(新版本中已删除) |
不同scope的bean,生命周期:
singleton:bean的生命周期和Spring容器的生命周期相同
prototype:bean的生命周期和Spring容器无关。Spring创建bean对象之后,交给JVM管理了
何时创建:调用getBean
方法获取bean对象时,bean对象创建
bean
生命周期相关方法的配置【了解】<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"
init-method="" destroy-method="">bean>
init-method
:指定类中初始化方法名称,该方法将在bean对象被创建时执行
destroy-method
:指定类中销毁方法名称,该方法将在bean对象被销毁时执行
注意:
- prototype类型的bean:Spring容器销毁时,也不会执行销毁方法,因为Spring不负责它的销毁
- singleton类型的bean:在Spring容器显式关闭时,会执行destroy-method指定的方法
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao userDao = context.getBean("userDao", UserDao.class); //显式的关闭Spring容器 ((ClassPathXmlApplicationContext)context).close();
bean
实例化的三种方式<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">bean>
com.itheima.factory.StaticFactory
public class StaticFactory{
public static UserDao createUserDao(){
return new UserDaoImpl();
}
}
<bean id="userDao" class="com.itheima.factory.StaticFactory"
factory-method="createUserDao">bean>
com.itheima.factory.InstanceFactory
public class InstanceFactory{
public UserDao createUserDao(){
return new UserDaoImpl();
}
}
<bean id="instanceFactory" class="com.itheima.factory.InstanceFactory">bean>
<bean id="userDao" factory-bean="instanceFactory" factory-method="createUserDao">bean>
<bean id="唯一标识" class="全限定类名">bean>
bean对象的作用范围。使用bean标签的scope属性进行设置的
bean对象生命周期相关的方法配置:
bean实例化方式:
<bean id="" class="">bean>
<bean id="" class="工厂类全限定类名" factory-method="生成对象的静态方法">bean>
<bean id="" factory-bean="工厂bean对象" factory-method="生成对象的非静态方法">bean>
<bean id="工厂bean" class="工厂bean的全限定类名">bean>
依赖注入:Dependency Injection,是Spring的Ioc核心的具体实现。
我们需要进行配置:告诉Spring,依赖什么
我们通过Ioc把bean对象交给了Spring容器进行管理,降低了耦合性。
但是耦合性不能彻底消除,bean之间还是有一些依赖关系。比如:业务层userService要依赖于持久层userDao。
这样的依赖关系,可以交给Spring帮我们进行依赖的注入,而不用我们自己注入依赖
UserDao
和UserDaoImpl
UserService
和UserServiceImpl
UserServiceImpl
中的方法依赖于UserDaoImpl
UserDaoImpl
注入给UserServiceImpl
UserDao
及UserDaoImpl
、service层UserService
和UserServiceImpl
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.1.2.RELEASEversion>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
dependencies>
UserDao
public interface UserDao {
void save();
}
UserDaoImpl
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("UserDaoImpl.save......");
}
}
UserService
public interface UserService {
void save();
}
UserServiceImpl
public class UserServiceImpl implements UserService {
//依赖于dao层的UserDao,定义一个成员变量
private UserDao userDao;
@Override
public void save() {
userDao.save();
}
//提供userDao的get/set方法
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
<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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">bean>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
bean>
beans>
public class UserTest {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.save();
}
}
UserServiceImpl里有userDao,需要注入UserDaoImpl对象
private UserDao userDao;
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
<bean id="" class="UserServiceImpl全限定类名">
<property name="userDao" ref="要注入的bean对象"/>
bean>
在类中提供需要注入的成员(依赖项)的set方法,在配置文件中注入属性的值
<bean id="" class="">
<property name="属性名" value="属性值">property>
<property name="属性名" ref="bean的id">property>
bean>
property
标签:用在bean标签内部,表示要给某一属性注入数据
name
:属性名称value
:要注入的属性值,注入简单类型值ref
:要注入的属性值,注入其它bean对象优势:创建bean对象时没有明确的限制,可以使用无参构造直接创建
缺点:如果某个成员必须有值,则获取对象时,有可能set方法未执行
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.1.2.RELEASEversion>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
dependencies>
UserDao
public interface UserDao {
void save();
}
UserDaoImpl
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("UserDaoImpl.save......");
}
}
UserService
public interface UserService {
void save();
}
UserServiceImpl
public class UserServiceImpl implements UserService {
//依赖于dao层的UserDao,定义一个成员变量
private UserDao userDao;
@Override
public void save() {
userDao.save();
}
//提供userDao的get/set方法
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
<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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">bean>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
bean>
beans>
public class UserTest {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.save();
}
}
在类中提供构造方法,构造方法的每个参数就是一个依赖项,通过构造方法给依赖项注入值。
<bean id="" class="">
<constructor-arg name="构造参数名称" value="构造参数的值">constructor-arg>
<constructor-arg name="构造参数名称" ref="bean的id">constructor-arg>
bean>
name
:构造参数的名称type
:构造参数的类型index
:构造参数的索引value
:要注入的值,注入简单类型值ref
:要注入的值,注入其它bean对象优势:在获取bean对象时,注入数据是必须的操作,否则无法创建成功。
缺点:改变了bean对象的实例化方式,如果在创建对象时用不到这些数据,也必须要提供
p名称空间注入,本质仍然是set方法注入
在xml中引入p名称空间的约束
然后通过p:属性名称=""
来注入简单数据、使用p:属性名称-ref=""
注入其它bean对象,它的本质仍然是set方法注入
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="" class="" p:属性名="简单值" p:属性名-ref="bean的id">bean>
beans>
通过set方法注入(注入属性)
<bean id="" class="" >
<property name="属性名称" value="注入简单值"/>
<property name="属性名称" ref="注入其它bean对象"/>
bean>
通过构造方法注入
<bean id="" class="">
<constructor-arg name="属性名称" value="注入简单值"/>
<constructor-arg name="属性名称" ref="注入其它bean对象"/>
bean>
通过p名称空间注入
p:属性名
或者 p:属性名-ref
注入值<bean id="" class="" p:属性名="注入简单值" p:属性名-ref="注入其它bean对象">bean>
UserDaoImpl
需要注入数据public class UserDaoImpl implements UserDao {
private String[] arr;
private List<String> list;
private Set<String> set;
private Map<String,String> map;
private Properties properties;
// get/set...
public void show(){
System.out.println(Arrays.toString(this.arr));
System.out.println(this.list);
System.out.println(this.set);
System.out.println(this.map);
System.out.println(this.properties);
}
}
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<property name="arr">
<array>
<value>avalue>
<value>bvalue>
<value>cvalue>
array>
property>
<property name="list">
<list>
<value>a1value>
<value>b1value>
<value>c1value>
list>
property>
<property name="set">
<set>
<value>a2value>
<value>b2value>
<value>c2value>
set>
property>
<property name="map">
<map>
<entry key="a3" value="a3"/>
<entry key="b3" value="b3"/>
<entry key="c3" value="c3"/>
map>
property>
<property name="properties">
<props>
<prop key="a4">a4prop>
<prop key="b4">b4prop>
<prop key="c4">c4prop>
props>
property>
bean>
所有单列结构的数据集合,标签可以互换使用。例如:List、Set、数组等
所有键值对结构的数据集合,标签可以互换使用。例如:Map、Properties等
array/list/set
中任一标签均可map/props
中任一标签均可ApplicationContext
的继承体系ApplicationContext
:接口,代表应用上下文,可以通过其实例对象获取Spring容器中的bean对象ApplicationContext
BeanFactory
和 ApplicationContext
的区别ApplicationContext 是现在使用的工厂
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
XmlBeanFactory是老版本使用的工厂,目前已经被废弃【了解】
BeanFactory beanFactory =
new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
两者的区别:
ApplicationContext加载方式是框架启动时就开始创建所有单例的bean,存到了容器里面
BeanFactory加载方式是用到bean时再加载(目前已经被废弃)
ApplicationContext
的实现类ClassPathXmlApplicationContext
FileSystemXmlApplicationContext
AnnotationConfigApplicationContext
getBean()
方法方法 | 参数 | 返回值 |
---|---|---|
getBean(String beanId) |
bean的id | Object ,bean对象 |
getBean(String beanId,Class beanType) |
bean的Class类型 | bean对象 |
getBean(Class beanType) |
bean对象 |
创建Maven的Java项目,项目坐标自定,然后引入依赖如下:
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
<dependency>
<groupId>com.mchangegroupId>
<artifactId>c3p0artifactId>
<version>0.9.5.2version>
dependency>
<dependency>
<groupId>commons-dbutilsgroupId>
<artifactId>commons-dbutilsartifactId>
<version>1.7version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.1.2.RELEASEversion>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
dependencies>
创建JavaBean:Account类如下:
public class Account {
private Integer id;
private String name;
private Float money;
//get/set...
//toString...
}
Service层接口:AccountService
public interface AccountService {
List<Account> queryAll() throws SQLException;
void save(Account account) throws SQLException;
void edit(Account account) throws SQLException;
void delete(Integer id) throws SQLException;
}
Service实现类:AccountServiceImpl
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
/***************业务功能方法*****************/
@Override
public List<Account> queryAll() throws SQLException {
return accountDao.queryAll();
}
@Override
public void save(Account account) throws SQLException {
accountDao.save(account);
}
@Override
public void edit(Account account) throws SQLException {
accountDao.edit(account);
}
@Override
public void delete(Integer id) throws SQLException {
accountDao.delete(id);
}
/***************get/set方法*****************/
public AccountDao getAccountDao() {
return accountDao;
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
}
dao层接口:AccountDao
public interface AccountDao {
List<Account> queryAll() throws SQLException;
void save(Account account) throws SQLException;
void edit(Account account) throws SQLException;
void delete(Integer id) throws SQLException;
}
dao实现类:AccountDaoImpl
public class AccountDaoImpl implements AccountDao {
private QueryRunner runner;
/***************功能方法*****************/
@Override
public List<Account> queryAll() throws SQLException {
return runner.query("select * from account", new BeanListHandler<>(Account.class));
}
public void save(Account account) throws SQLException{
runner.update("insert into account (id,name,money) values (?,?,?)", account.getId(), account.getName(), account.getMoney());
}
public void edit(Account account) throws SQLException{
runner.update("update account set name = ?, money = ? where id = ?", account.getName(), account.getMoney(), account.getId());
}
public void delete(Integer id) throws SQLException{
runner.update("delete from account where id = ?", id);
}
/***************get/set方法*****************/
public QueryRunner getRunner() {
return runner;
}
public void setRunner(QueryRunner runner) {
this.runner = runner;
}
}
创建Spring的核心配置文件:applicationContext.xml
<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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
bean>
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
<property name="runner" ref="runner"/>
bean>
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="dataSource"/>
bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///spring"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
bean>
beans>
编写单元测试类AccountTest
如下:
public class AccountTest {
private AccountService accountService;
@Before
public void before(){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
accountService = context.getBean("accountService", AccountService.class);
}
@Test
public void testQueryAll() throws SQLException {
List<Account> accounts = accountService.queryAll();
for (Account account : accounts) {
System.out.println(account);
}
}
@Test
public void testSave() throws SQLException {
Account account = new Account();
account.setName("tom");
account.setMoney(10000f);
accountService.save(account);
}
@Test
public void testEdit() throws SQLException {
Account account = new Account();
account.setId(3);
account.setName("jerry");
account.setMoney(5000f);
accountService.edit(account);
}
@Test
public void testDelete() throws SQLException {
accountService.delete(3);
}
}
properties
文件如果需要在applicationContext.xml
中引入properties文件:
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring
jdbc.username=root
jdbc.password=root
applicationContext.xml
中引入并使用jdbc.properties
<beans
xmlns:名称空间="http://www.springframework.org/schema/名称空间"
xsi:scehmaLocation="
http://www.springframework.org/schema/名称空间
http://www.springframework.org/schema/名称空间/spring-名称空间.xsd">
beans>
<context:property-placeholder location="classpath:jdbc.properteis"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
bean>
在大型项目开发中,如果把所有的配置都写在一个配置文件applicationContext.xml
中,会导致:
Spring提供了分模块配置的方式,即:每个模块提供一个配置文件,在核心配置文件中引入模块配置:
applicationContext-dao.xml
只配置dao相关的对象applicationContext-service.xml
只配置service相关的对象applicationContext.xml
如下<import resource="classpath:applicationContext-service.xml"/>
<import resource="classpath:applicationContext-dao.xml"/>
在上边的CURD中,单元测试类里还需要我们自己去创建ApplicationContext
,并自己去获取bean对象。Spring提供了整合Junit的方法,让单元测试更简洁方便。
注解 | 说明 |
---|---|
@RunWith |
用在测试类上,用于声明不再使用Junit,而是使用Spring提供的运行环境 |
@ContextConfiguration |
用在测试类上,用于指定Spring配置类、或者Spring的配置文件 |
Spring提供了单元测试的运行环境:SpringJunit4ClassRunner,配置到
@RunWith
注解上:
@RunWith(SpringJunit4ClassRunner.class)
spring-test
和 junit
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.1.2.RELEASEversion>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
在pom.xml文件中增加依赖:spring-test
和 junit
修改单元测试类
在单元测试类上增加注解:@RunWith(SpringJunit4ClassRunner.class)
目的:使用Spring的单元测试运行器,替换Junit原生的运行器
在单元测试类上增加注解:@ContextConfiguration()
目的:指定配置文件或配置类
在测试类里的依赖项上,直接使用@Autowired
注入依赖
在pom.xml文件中增加依赖:spring-test
和 junit
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.1.2.RELEASEversion>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
修改单元测试类
@RunWith(SpringJUnit4ClassRunner.class)//使用Spring的单元测试运行器
@ContextConfiguration("classpath:applicationContext.xml")//指定核心配置类/核心配置文件
public class AccountTest {
@Autowired
private AccountService accountService;
@Test
public void queryAll() throws SQLException {
List<Account> accounts = accountService.queryAll();
for (Account account : accounts) {
System.out.println(account);
}
}
//......
}