先上代码:项目源码下载(软件:IDEA):
1.[理解]自定义IOC实现程序解耦合
链接:https://pan.baidu.com/s/1in10JR4D_muZHyWGPzaj9Q
提取码:lvgt
2.[掌握]使用SpringIOC实现程序解耦合
链接:https://pan.baidu.com/s/1OU3YqT1FADIC8SagMumpWQ
提取码:pen8
[理解]IOC的概念和作用
注意:IOC和AOP不是从Spring开始才有的,在Spring之前更趋向于理论化,在Spring这才发扬光大的
IOC的概念
IOC:inverse of control (反转控制/控制反转),我们之前在一个java类中通过new的方式去引入外部资源(其他类等),这叫正向;现在Spring框架帮我们去new,你什么时候需要你去问Spring框架要,这就是反转(创建对象权利的一个反转)
我们丧失了一个权利(主动创建对象的权利),但是我们拥有了一个福利(我们不用考虑对象的创建、销毁等问题)
IOC的作用
IOC解决程序耦合问题
关于程序耦合(有一个认识即可)
耦合:耦合度的意思,程序当中:为了实现一个业务功能,不同的模块之间互相调用就会产生耦合。
注意:耦合是不能避免的,耦合尽可能去降低
“高内聚、低耦合”,内聚度过高不利于代码复用,内聚度往往通过增加方法来完成(麻烦自己、方便别人)
[理解]自定义IOC实现程序解耦合
pojo对象
package com.itheima.pojo;
public class Account {
private Integer id;
private String name;
private Float money;
public Account() {
}
public Account(Integer id, String name, Float money) {
this.id = id;
this.name = name;
this.money = money;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Float getMoney() {
return money;
}
public void setMoney(Float money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
service层
package com.itheima.service;
import com.itheima.pojo.Account;
public interface AccountService {
void saveAccount(Account account);
}
package com.itheima.service;
import com.itheima.dao.AccountDao;
import com.itheima.dao.AccountDaoImpl;
import com.itheima.pojo.Account;
public class AccountServiceImpl implements AccountService{
/*
这里有耦合
new AccountDaoImpl()把AccountServiceImpl对象和AccountDaoImpl耦合在一起
*/
AccountDao accountDao = new AccountDaoImpl();
@Override
public void saveAccount(Account account) {
accountDao.saveAccount(account);
}
}
dao层
package com.itheima.dao;
import com.itheima.pojo.Account;
public interface AccountDao {
/*
保存账户信息
*/
void saveAccount(Account account);
}
package com.itheima.dao;
import com.itheima.pojo.Account;
public class AccountDaoImpl implements AccountDao{
@Override
public void saveAccount(Account account) {
System.out.println("保存了账户信息");
}
}
bean工厂
/**
* bean工厂
* 读取xml信息
* 反射创建对象
* 存储到集合Map (对象容器)
*
* 提供一个方法,根据id获取对象
*/
public class BeanFactory {
private static Map<String,Object> map = new HashMap<String, Object>();
/**
* 读取xml配置文件
* 创建对象,存储Map集合
*/
static {
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
SAXReader saxReader = new SAXReader();
try {
Document document = saxReader.read(in);
Element rootElement = document.getRootElement();
List<Element> elementList = rootElement.selectNodes("//bean");
if(elementList != null && elementList.size() >0 ){
for(Element element : elementList){
String id = element.attributeValue("id");
String className = element.attributeValue("class");
Class clazz = Class.forName(className);
Object obj = clazz.newInstance();
map.put(id,obj);
}
}
}catch (Exception ex){
ex.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 根据id返回对象
*/
public static Object getInstance(String id){
return map.get(id);
}
}
beans.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!--
存储需要实例化的对象
id 唯一标识
class 类全限定名
-->
<beans>
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"></bean>
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
</beans>
[掌握]使用SpringIOC实现程序解耦合
- 引入jar坐标
<!--需要spring作为容器 完成IOC这种操作--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency>
Spring-context的依赖包会自动引入,这就是maven的依赖传递
service层和dao层的业务代码完善
实例化service和dao代码,把它们的信息写在spring配置文件中
引入spring的jar之后,idea中会自动有这个配置文件模板
applicationContext.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"></bean>
</beans>
测试类
/**
* 测试springIOC容器
*/
@Test
public void testIOC(){
// ApplicationContext对象容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// getBean方法获取对象
AccountService service = (AccountService) context.getBean("accountService");
AccountDao dao = (AccountDao)context.getBean("accountDao");
/*
接口class获取实现类对象,接口只有一个实现类
context.getBean(AccountService.class);
*/
/*
接口class获取实现类对象
id唯一标识
context.getBean("accountService",AccountService.class);
*/
System.out.println(service);
System.out.println(dao);
}
}
[掌握]SpringIOC的一些细节知识
ApplicationContext和BeanFactory
ApplicationContext:立即加载模式,在Spring启动的时候会立即实例化对象,等待使用,推荐使用
BeanFactory:使用到对象的时候(getBean等)才去实例化对象(延迟加载模式),不推荐的
简单说:
创建对象的时间点不一样
ApplicationContext:配置文件一旦读取完了,默认就会创建对象放到容器中。
BeanFactory:什么时候用对象,什么时候创建。
Bean标签
id:标识符
class :实例化类的全限定类名,供反射实例化使用
scope :对象的使用范围
singleton:默认值,单例,项目全局内存中只有一个对象,一般在使用Spring的时候保持默认值即可
prototype:原型的意思,在这里是多例,每引用或者getBean一次,Spring框架就返回一个新的对象,比如SqlSession这个特殊的对象
request:这种配置针对web应用,每一个request范围内只对应一个对象
session:这种配置针对web应用,每一次会话该bean只有一个对象
global session:针对的是portlet环境,等同于servlet下的session
生命周期属性
nit-method指定初始化时执行的方法
destory-method指定销毁时执行的方法
注意:容器的close方法在实现类当中
注意测试destory销毁方法的时候,scope配置为单例
对象创建的三种方式
1.通过配置class全限定类名框架底层使用反射技术来创建对象(经常使用,推荐)
<bean id="accountService" class="com.itheima.service.AccountServiceImpl"></bean>
<bean id="accountDao" class="com.itheima.dao.AccountDaoImpl"></bean>
2.静态方法(自己new对象,然后加入到Spring的对象容器中管理)
3.动态方法(自己new对象,然后加入到Spring的对象容器中管理)(需要首先定义工厂的bean,然后通过工厂bean对象调用里面的方法返回具体对象)
依赖注入(DI)
DI: dependance inject(依赖注入的意思)
IOC和DI的区别
IOC和DI是一个事情,只是描述的角度不同(面试题)
Set注入(也叫设值注入,这是常用和推荐的用法)(必须练习!!)
构造函数注入(了解 不常用)
p约束的注入方式
xmlns:p="http://www.springframework.org/schema/p"
在标签里面使用这个约束
<bean id="accountService" class="com.itheima.spring.service.AccountServiceImpl" p:name="翟天临" p:id="3" p:money="111.111" p:accountDao-ref="accountDao">
</bean>
<bean id="accountDao" class="com.itheima.spring.dao.AccountDaoImpl"/>
复杂对象注入
<!-- 完成 复杂类型的 set依赖注入-->
<property name="myStrs">
<array>
<value>翟天临</value>
<value>吴秀波</value>
<value>黄海波</value>
</array>
</property>
<property name="myList">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</list>
</property>
<property name="mySet">
<set>
<value>set1</value>
<value>set2</value>
<value>set3</value>
</set>
</property>
<property name="myMap">
<map>
<entry key="1" value="张三"></entry>
<entry key="2" value="李四"></entry>
</map>
</property>
<property name="myPros">
<props>
<prop key="1">王五</prop>
<prop key="2">钱七</prop>
</props>
</property>
private String[] myStrs;
private List<String> myList;
private Set<String> mySet;
private Map<String,String> myMap;
private Properties myProps;
注意:list、set和array是一类数据类型,单值型,所以在Spring注入的时候,<array><list><set>可以替换使用;map和properties都是key/value类型的,所以<map>和<props>标签可以替换使用。但是以上替换不建议,没有意义。