<>IOC 控制反转

Inversion of Control
控制反转 依赖注入
1 控制什么?
控制对象的创建以及销毁
2 反转什么?
将对象的控制权交给IOC容器
举例说明:

张三要回家
对象:

* 小明 人
* 车 奔驰 宝马

Audi.java public class Audi{ public void start(){
System.out.println("Audi.start"); } public void turnLeft(){
System.out.println("Audi.start"); } public void trunRight(){
System.out.println("Audi.start"); } public void stop(){
System.out.println("Audi.start"); } }
<>传统方式

张三控制车辆的流程:
1 创建一辆车
Audi audi = new Audi();
2 控制车辆的启动 直行 左右转
audi.start(); audi.turnLeft(); audi.trunRight(); turn.stop();
3 销毁车辆

java的jcc组织垃圾回收处理掉

<>张三的其他需求

比如看电影
public void goMovice(){ public void start(){ System.out.println("Audi.start");
} public void stop(){ System.out.println("Audi.start"); } }
现在张三要换一辆Buick车

在Zhangsan.java当就需要全部更改
产生了高耦合性

<>改进方案 1

把车升级到张三的属性域里面
这样就降低了耦合度
public class ZhangSan { Buick car = new Buick(); public void goHome(){
car.start(); car.turnRight(); car.turnLeft(); car.stop(); } }
<>改进方案 2

接口Car
public interface Car { public void start(); public void turnLeft(); public
void turnRight(); public void stop(); }
奔驰车实现这个车的接口
public class Audi implements Car{ public void start(){
System.out.println("Audi.start"); }
在ZhangSan当中用构造方法传进去Car
private Car car; public ZhangSan(Car car){ this.car = car; }
到现在Car已经不用ZhangSan来创建了 由IOC来创建了

车辆的控制权完全交给了IOC

<>实现自己编写一个IOC的容器



<>约定

* 所有的Bean的生命周期交由IOC容器管理
* 所有被依赖的Bean通过构造方法执行注入
* 被依赖的Bean需要优先创建(创建张三前先创建奥迪)
所有被依赖的Bean通过构造方法执行注入
public HumanWithCar(Car car) { this.car = car; } private Car car;
Class003Test.java//测试IOC容器
public class Class003Test { private IoCConteainer ioCConteainer = new
IoCConteainer(); @Before//创建bean public void before(){
ioCConteainer.setBean(Audi.class, "Audi"); ioCConteainer.setBean(Buick.class,
"Buick"); ioCConteainer.setBean(ZhangSan.class, "ZhangSan","Audi");
ioCConteainer.setBean(Lisi.class, "Lisi","Buick"); } @Test//使用bean public void
test(){ Human ZhangSan = (Human) ioCConteainer.getBean("ZhangSan");
ZhangSan.goHome(); Human Lisi = (Human) ioCConteainer.getBean("Lisi");
Lisi.goHome(); } }
<>Spring IOC入门

1 创建一个javabean
public class Bean{ public Bean(){ System.out.println("Bean.bean"); } }
2 在pom中加入spring的依赖
spring-core spring-context
3 在resources文件夹下建立一个spring.xml文件
//class = 1 中创建的Bean 并给一个唯一标示id <bena class = "bean"
class="com.imooc.spring.ioc.class004.Bean">
//测试
public class Class004Test { @Test public void test(){ ApplicationContext
context = new ClassPathXmlApplicationContext("spring.xml); Bean bean =
context.getBean("bean",Bean.class); System.out.println("bean = " + bean); } }


<>实例化Bean方式

* 构造方法实例化
* 静态方法
* 实例方法
<>构造方法实例化

1 创建Bean.java
public class Bean { public Bean(){ System.out.println("Bean.bean"); } }
2 在spring.xml中配置bean
<bean class = "com.spring.ioc.class05.Bean1" id = "bean1"/>
3 在class005Test.java中实例
public class class005Test { @Test public void test(){ //取上下文
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
//通过context get一个Bean Bean bean = context.getBean("bean", Bean.class);
System.out.println("bean = " + bean); } }
<>静态方法实例化

1 创建一个BeanFactory.java
通过BeanFactory的getBean方法实例化Bean
public class Bean2Factory { public static Bean2 getBean2(){ return new
Bean2(); } }
2 spring.xml中进行配置
<bean class = "com.spring.ioc.Class05.Bean2Factroy" factory-method =
"getBean2" id = "bean2"/>
3 Class005Test.java
Bean2 bean2 = context.getBean("bena2", Bean2.class);
<>实例方法实例化Bean

1 创建一个Bean3Factory.java
通过BeanFactory的getBean方法实例化Bean
public class Bean3Factory { public static Bean3 getBean3(){ return new
Bean3(); } }
2 spring.xml中进行配置
<bean class = "com.spring.ioc.Class05.Bean3" factory-bean = "bean3Factory"
factory-method = "getBean3" id = "bean3"/>
3 Class005Test.java
Bean3 bean3 = context.getBean("bean3",Bean3.class); System.out.println("bean3
= " + bean3);
<>给Bean取一个别名

1 name属性
<bean class = "myspring.Bean" name ="bean1_1,bean1_2 " id = "bean1"/>
2 alias属性
<alias name = "bean1" alias="bean1_3,bean1_4"/>
测试
Bean1 bean1_1 = context.getBean("bean1_1",Bean1.class);
System.out.println("bean1_1 = " + bean1_1); Bean1 bean1_2 =
context.getBean("bean1_2",Bean1.class); System.out.println("bean1_2 = " +
bean1_2);
但是这些名字不同的都是同一个Bean




<>注入Bean的方式

* 构造方法注入Bean
* set方法注入Bean
* 集合类Bean的型注入
* List
* Set
* Map
* Propertise
* null值注入
* 注入时创建内部Bean
前期准备
AnotherBean.java
public class AnotherBean { }
Bena.java
public class Bean { private AnotherBean anotherBean; private String string;
public AnotherBean getAnotherBean() { return anotherBean; } public void
setAnotherBean(AnotherBean anotherBean) { this.anotherBean = anotherBean; }
public String getString() { return string; } public void setString(String
string) { this.string = string; } }
<>构造方法注入Bean

在Bean.java中写入构造方法
public Bean(AnotherBean anotherBean, String string) { this.anotherBean =
anotherBean; this.string = string; }
spring.xml
//index:参数是构造方法中的第几个参数 //name:当前参数的参数名字 //type:参数的类型 //value: 给参数赋值 适合简单的数据类型
string integer double float //ref:复杂数据类型赋值 对应anotherbean的id <bean class =
"com.example.controller.Bean" id = "bean"> <constructor-arg index="0" name =
"anotherBean" type="com.example.controller.AnotherBean" ref="anotherBean"/>
<constructor-arg index="1" name="string" type="java.lang.String"
value="aaaaa"/> </bean>

简单写法
<bean class="com.example.controller.AnotherBean" id = "bean"
c:anotherBean-ref="bean1" c:string="ccccc" p:anotherBean1-ref="bean1_1"
P:string1="ddddd" /> <util:property name="anotherBean1" ref = "anotherBean"/>
<util:property name = "String1" value="ddddd"/>


<>set方法注入Bean



<>集合类型的Bean的注入

* list
* set
* map
* propertise
List
spring.xml
<util:property name = "stringList"> <list> <value>aaaaa</value>
<value>ddddd</value> </list> </util:property> <util:property> <list> <ref bean
= "anotherBean"/> <ref bean = "anotherBean"/> </list> </util:property>
<util:propertiy name="properties"> <prop key="aaaaa">bbbbb</prop>
</util:propertiy>
class005Test.java
Bean bean = context.getBean("bean",Bean.class);
System.out.println("bean.getStringList() = " + bean.getSring());
System.out.println("bean.getProperties() = " + bean.getProperties());



<>null注入

Bean.java
public AnotherBean getAnotherBean2() { return anotherBean2; } public void
setAnotherBean2(AnotherBean anotherBean2) { this.anotherBean2 = anotherBean2; }
private AnotherBean anotherBean2;
spring.xml
<util:properties name = "anotherBean2"> <null/> </util:properties>
class005Test.java
System.out.println("bean.getAnotherBean2()" + bean.getAnotherBean2());


<>注入的时候创建内部Bean
<util:properties> <bean class = "com.example.controller.AnotherBean"/>
</util:properties>


<>Bean的作用域的问题

*
Sinleton作用域

*
prototype作用域

*
Web环境作用域

* requset
* session
* application
* websocket
*
自定义作用域

* SimpleThreadScope作用域
<>Singleton作用域(单例模式)


右侧的Bean会通过Spring注入左侧三个Bean中 只会创建一个Bean

Bean.java
public class Bean { public Beanb getBeanb() { return beanb; } public void
setBeanb(Beanb beanb) { this.beanb = beanb; } private Beanb beanb; @Override
public String toString() { return "Bean{" + "beanb=" + beanb + '}'; } }
spring.xml
<bean class = "com.example.controller.People.Beanb" id = "bean2"
scope="prototype"/> <bean class = "com.example.controller.People.Bean" id =
"bean" scope="prototype"> <property name="beanb" ref="bean2"></property> </bean>
public class Class007Test { ApplicationContext context = new
ClassPathXmlApplicationContext("spring.xml"); Beanb bean2_1 =
context.getBean("Beanb",Beanb.class); System.out.println("bean2_1 = " +
bean2_1); Beanb bean2_2 = context.getBean("bean2_2 = " + bean2_2);
System.out.println("bean2_2 = " bean2_2); bean bean1 =
context.getBean("bean",Bean.class); System.out.println("bean = " + bean); }



<>Prototype作用域(多例模式)





<>Web相关作用域

* requset作用域
* sessiong作用域
* applicatiton作用域
* websocker作用域(很少使用)
SpringWeb上下文环境

如果使用DispatcherServlet 不需要增加其他配置



web.xml

RequsetController.java

spring.xml
<bean class="com.spring.ioc.class08.RequestController"/> <bean
class="com.spring.ioc.class08.SessionController"/> <bean
class="com.spring.ioc.class08.ApplicationController"/>

每次刷新@contraller不变
<bean class="com.spring.ioc.class08.RequestController" scope = "requset"/>
<bean class="com.spring.ioc.class08.SessionController" scope = "requset"/>
<bean class="com.spring.ioc.class08.ApplicationController" scope = "requset"/>
每次刷新@contraller改变
回顾

* request:每个requset请求斗湖创建一个单独的实例
* session:每个session都会创建一个单独的实例
* application:每个servletContext都会创建一个单独的实例
* websocket:每个websocket链接都会创建一个单独实例
<>自定义作用域

* SimpleThreadScope作用域
MyScope.java

spring.xml

<>Bean的懒加载

Spring容器会在创建容器时提前初始化Singleton作用域的bean
但如果Bean被标记了lazy-init = “true”
那么该Bean只有在其被需要的时候才会初始化

只对singleton作用域的bean有效
多例模式不知道bean什么时候被实例化

单一的Bean需要懒加载
<bean class = "com.example.controller.People.Beanb" id = "bean2"
scope="singleton" lazy-init="true"/>
所有的bean需要懒加载
<beans default-lazy-init="true">



位所有的bean都设置默认的


<>Bean初始化及销毁逻辑处理

如果Bean实例化之后执行一些逻辑 有两种方法

* bean标签里的属性 initmethod
* 让Bean实现InitializingBean接口
如果Bean在销毁之前需要执行一些逻辑 两种方法

* destory-method
* DisposableBean接口
<>Bean属性继承

场景1

简化代码

场景2



<>注解

spring2.5之后用注解取代xml

<>xml 与 annotation对比


MyConfiguration.java
import org.springframework.context.annotation.Bean; import
org.springframework.context.annotation.Configuration; @Configuration public
class MyConfiguration { @Bean //这里也可以用(value=“bean1命名”) public Bean bean1(){
return new Bean(); } }
Test.java
import com.example.controller.People.MyConfiguration; import org.junit.Test;
import org.springframework.context.ApplicationContext; import
org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Class008Test { @Test public void test(){ ApplicationContext
context = new AnnotationConfigApplicationContext(MyConfiguration.class); Bean1
bean1 = context.getBean("bean",Bean.class); System.out.println("bean1 = " +
bean1); } }


<>简化代码

conpoent-scan包扫描

@ component注解


<>给Bean取别名



<>通过注解注入Bean


构造方法和Set方法注入Bean

通过属性直接注入

实例化和注入时指定Bean的id

List/Set注入
直接注入List实例

将多个泛型实例注入到List

Map注入

多个泛型实例注入Map

String Integer类型的直接赋值

Spring Ioc容器内置借口实例注入


可以直接将ApplicationContext注入进来,也可以注入BeanFactory、Environment、ResourceLoader、ApplicationEventPublisher\MessagerSource及其实现类

<>SpringIoc注解设定Scope(作用域)

Spring预定义作用域

自定义作用域



方法注入



<>通过注解开启Bean的懒加载



<>通过注解编写Bean初始化及销毁





友情链接
ioDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信