IOC:Inversion of Control 控制反转。(底层原理:反射)
所谓的控制反转,就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责,这样控制权就用应用内部转移到了外部容器,这样做的目的是为了获得更好的扩展性和良好的可维护性。
DI:Dependency Injection 依赖注入 。(底层原理:内省)
所谓的依赖注入,就是在运行期,由外部容器动态地将依赖对象注入到组建中
以下是在bean.xml容器中,依赖注入的代码↓
<bean id="boy" class="com.dueeast.a_ioc.Boy" scope="prototype">
</bean>
<bean id="girl" class="com.dueeast.a_ioc.Girl">
<property name="boy">
<ref bean="boy"/>
</property>
</bean>
前提是在com.dueeast.a_ioc.Girl 中,有对com.dueeast.a_ioc.Boy这个类的set方法↓
public class Girl {
Boy boy;
public void setBoy(Boy boy) {
this.boy = boy;
}
public void kiss(){
boy.display();
System.out.println("kiss");
}
}
就可以这样使用了↓
public class App {
public static void main(String[] args) {
BeanFactory ac = new XmlBeanFactory(new FileSystemResource("D:\10.7MyEclipseSpace\BlogTest\src\beans.xml"));
Girl girl = (Girl) ac.getBean("girl");
girl.kiss();
}
}
以上是DI依赖注入的简单演示
-----------------------------------------------------------------------------------------------------------------------
在楼上代码中,下面这一句实例化了Spring的容器。
BeanFactory ac = new XmlBeanFactory(new FileSystemResource("D:\10.7MyEclipseSpace\BlogTest\src\beans.xml"));
实例化Spring容器一共有四种方式↓
(1)加载一个spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext("容器全路径");
(2)加载多个spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"容器全路径"});
(3)从外部文件系统加载容器
ApplicationContext ac = new FileSystemXmlApplicationContext("容器在本地磁盘的绝对路径");
(4)使用BeanFactory的用法
BeanFactory ac = new XmlBeanFactory(new FileSystemResource("容器在本地磁盘的绝对路径"));
项目中最常用是使用ApplicationContext和ClassPathXmlApplicationContext,一般不使用BeanFactory
ApplicationContext是对BeanFactory扩展,提供了更多功能
1、国际化处理
2、事件传递
3、Bean自动装配
4、各种不同应用层的Context实现
---------------------------------------------------------------------------------------------
创建对象的作用于模式:
单例模式singleton(默认值)
l 如果是单例的话,将spring中bean元素节点的scope设置成singleton,加载spring容器的时候,就会加载对应的构造方法,此时构造方法只执行1次,表示单例
l 在spring容器中配置:lazy-init="false"(默认值);表示只要加载spring容器,此时就会立即加载构造对象的方法。
l 在spring容器中配置:lazy-init="true";表示只有调用对应对象的时候,才会初始化对应的构造方法。
l 如果在spring容器中的beans节点配置default-lazy-init="false"(默认值),对全局所有的bean都有效
多例模式prototype(整合由于struts2是多例,在spring容器创建Action对象的时候,将其设置多例)
l 如果是单例的话,将spring中bean元素节点的scope设置成prototype,加载spring容器的时候,不会加载执行对应对象的构造方法,此时只有调用对应对象的时候,才会执行对应的构造方法,执行多次,表示多例
l 多例中不会存在lazy-init属性,因为没有意义
* request每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境(一个系统request.setAttribute () )
* session同一个HTTP Session 共享一个Bean,不同Session使用不同Bean,仅适用于WebApplicationContext 环境(一个系统session.setAttribute())
* global session一般用于Porlet应用环境,该作用域仅适用于WebApplicationContext 环境(多个系统共享一个session)
------------------------------------------------------------------------------------------
依赖注入详解
1、在类中的属性需要设置set方法(用以下javabean演示,set方法因过多而省略)
private Integer id;
private String name;
private Person person;
private List<Object> list;
private Object[] arrays;
private Set<Object> set;
private Map<String, Object> map;
private Properties properties;
//spring整合hibernate的时候,都可以在容器中使用Properties集合完成对hibernate的操作
private List<Object> listnull = new ArrayList<Object>();
2、在spring的容器中定义:
<bean id="person" class="h_setXml.Person" p:pid="30" p:pname="酸菜"></bean>
<bean id="userService" class="h_setXml.UserServiceImpl">
<!-- 1:配置bean的简单属性,基本数据类型和String。 -->
<property name="id" value="10"></property>
<property name="name" value="翠花"></property>
<!--
2:注入对象,引用其它bean(外部bean)
结论:项目开发时都会使用外部注入,因为由外部创建对象,容器中的其他对象都可以调用
如果是内部调用,只能在当前bean中才能使用
-->
<property name="person" ref="person"></property>
<!-- 2:注入对象,内部bean
<property name="person">
<bean class="cn.itcast.h_setXml.Person"></bean>
</property>-->
<!-- 3:测试p空间,为对象中的属性赋值 -->
<!-- 4:注入集合,A、装配List和数组(通用): -->
<property name="list">
<list>
<value>list001</value>
<value>list002</value>
<ref bean="person"/>
</list>
</property>
<property name="arrays">
<array>
<value>array001</value>
<value>array002</value>
<ref bean="person"/>
</array>
</property>
<!-- 4:注入集合, B、 装配set: -->
<property name="set">
<set>
<value>set001</value>
<value>set002</value>
<ref bean="person"/>
</set>
</property>
<!-- 4:注入集合,装配集合 C、 装配map: -->
<property name="map">
<map>
<entry key="key001">
<value>mapValue001</value>
</entry>
<entry key="key002">
<value>mapValue002</value>
</entry>
<entry key="key003">
<ref bean="person"/>
</entry>
</map>
</property>
<!-- 5:注入集合,D、装配Properties:值不可以是对象 -->
<property name="properties">
<props>
<prop key="prop001">propValue001</prop>
<prop key="prop002">propValue002</prop>
</props>
</property>
<!-- 6:设置空值 -->
<property name="listnull">
<null/>
</property>
</bean>
3、注入构造器并在类中使用构造器
在spring容器中定义:
<bean id="userService" class="i_constructorXml.UserServiceImpl">
<!--
constructor-arg:构造器函数注入的方式
* index:构造器方法中参数的位置,0表示第1个位置
* type:表示构造器方法中参数的类型,类型可以写成java的类型
* 要求:
1:按照位置注入:如果使用参数的位置注入,需要注入的值要符合构造方法参数的类型
2:按照参数类型注入:根据构造函数参数的位置不同,可能会注入到不同的构造方法
<!-- 结论:当使用构造器函数的时候,可以使用即按照类型指定,同时也按照参数的位置指定 -->
<constructor-arg type="java.lang.String" index="1">
<value>1</value>
</constructor-arg>
<constructor-arg type="java.lang.String" index="0">
<value>翠花</value>
</constructor-arg>
</bean>
在类中使用构造函数,注入参数的值
public UserServiceImpl(String name,Integer id){
System.out.println("先String再Integer");
this.id = id;
this.name = name;
}
public UserServiceImpl(Integer id,String name){
System.out.println("先Integer再String");
this.id = id;
this.name = name;
}
public UserServiceImpl(String name,String education){
System.out.println("先String再String");
this.name = name;
this.education = education;
}