Spring IOC容器也可以称为 控制反转 或者 依赖注入 ,IOC容器其实是一个超级大工厂, 简单来说,IOC容器里面含有任何所需要的对象, 将需要创建的对象都在IOC容器中创建(通过<bean>或者注解), 需要用对象的时候再从IOC容器拿, 控制反转 反转的是获取对象的方式,改变了获取对象的方式, 以前需要一个对象就必须自己去new一个, 现在不需要了,直接从IOC容器拿就可以了(通过getBean()), 依赖注入 就是 将属性值注入给了属性,在将属性注入给了<bean>(对象), 再将bean注入给IOC容器。
搭建一个IOC容器时或者搭建一个Spring环境时需要那些jar包呢?
开发spring至少需要使用的jar(5个+1个):
spring-aop.jar 开发AOP特性时需要的JAR
spring-beans.jar 处理Bean的jar <bean>
spring-context.jar 处理spring上下文的jar <context>
spring-core.jar spring核心jar
spring-expression.jar spring表达式
三方提供的日志jar
commons-logging.jar 日志
其中,我们经常看到的applicationContext.xml其实可以叫做IOC容器, 那么,如何去初始化IOC容器(applicationContext.xml),让所有的对象被创建呢?
对于一个普通的java项目,通过以下方式可以初始化applicationContext.xml:
ApplicationContext conext = new ClassPathXmlApplicationContext("applicationContext.xml") ;
将这行代码放在main()方法入口,可以实现只执行一次,所有的对象都被创建并且,其他类也可以使用
而对于一个Web项目的话,则需要在项目启动时自动去执行applicationContext.xml,思路:弄个监听器,监听tomcat是否已经启动,一旦启动立即初始化IOC容器,即applicationContext.xml。所幸的是,这个监听器已经有人帮我们写了,我们不用写,只需要导入spring-web.jar包,配置下web.xml文件,加上如下代码:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
classpath代表类文件,即src文件,将applicationContext.xml放在src文件下(前提是你没对src文件名字进行改动)
好了,说完如何在java项目和web项目初始化IOC容器,接下来我要讲下三种依赖注入的方式:
依赖注入:
1>. set注入: 通过setXxx()赋值,需要在类中的属性给出set的方法,依赖注入底层是通过反射实现的<property>
<bean id="student" class="org.lanqiao.entity.Student">
<property name="id" value="110"></property>
<property name="name" value="jack"></property>
<property name="grade" value="100"></property>
</bean>
对于类Student,属性id, name, grade在类中必须有相应的setXxx()方法, value为所赋的值id=100, name="jack", grade=100
2>.构造器注入:通过构造方法赋值
<constructor-arg value="ls" type="String" index="0" name="name"></constructor-arg>
需要注意:如果 <constructor-arg>的顺序 与构造方法参数的顺序不一致,则需要通过type或者index或name指定。
<constructor-arg>通过type/index/name找到对应的属性并赋上相应的值
type通过类型对应, name通过变量名来对应, index通过索引构造函数参数第几个来对应
如果都没加type/index/name,则<constructor-arg>则是按构造函数参数的顺序来对应
<bean id="course" class="org.lanqiao.teacher.Course">
<constructor-arg value="java" name="cname"></constructor-arg>
<constructor-arg value="001" name="id"></constructor-arg>
<constructor-arg ref="teacher" name="teacher"></constructor-arg>
</bean>
public Course() {
}
public Course(String cname, String id, Teacher teacher) {
this.cname = cname;
this.id = id;
this.teacher = teacher;
}
3>.p命名空间注入
引入p命名空间
xmlns:p="http://www.springframework.org/schema/p" 即将这个加载本配置文件xml,<beans>标签上
<bean id="course" class="org.lanqiao.entity.Course" p:courseHour="300" p:courseName="hadoop" p:teacher-ref="teacher">
简单类型:
p:属性名="属性值"
引用类型(除了String外):
p:属性名-ref="引用的id"
注意多个 p赋值的时候 要有空格。
注意:
无论是String还是Int/short/long,在赋值时都是 value="值" ,
因此建议 此种情况 需要配合 name\type进行区分
依赖注入 的三种情况也说了,再来说说集合数据类型: List 、 Set 、map 、properties、的注入
1、 对于List
<property name="listElement">
<list>
<value>足球</value>
<value>篮球</value>
</list>
</property>
2、对于Set
<property name="setElement">
<set>
<value>足球1</value>
<value>篮球1</value>
</set>
</property>
3、对于map
<property name="mapElement">
<map>
<entry>
<key><value>football</value></key>
<value>足球3</value>
</entry>
<entry>
<key><value>basketball</value></key>
<value>篮球</value>
</entry>
</map>
</property>
4、对于properties
<property name="propElement">
<props>
<prop key="football1">足球</prop>
<prop key="basketball1">篮球</prop>
</props>
</property>
5、数组
<property name="arrayElement">
<array>
<value>足球2</value>
<value>篮球2</value>
</array>
</property>
如何给对象赋null呢?
给对象类型赋值null :
<property name="name" >
<null/> -->注意 没有<value>
</property>
赋空值 ""
<property name="name" >
<value></value>
</property>
在ioc中定义bean的前提:该bean的类 必须提供了 无参构造
我们再讲下自动装配:
自动装配(只适用于 ref类型 ):
约定优于配置
<bean ... class="org.lanqiao.entity.Course" autowire="byName|byType|constructor|no" > byName本质是by Id
byName: 自动寻找:其他bean的id值=该Course类的属性名
byType: 其他bean的类型(class) 是否与 该Course类的ref属性类型一致 (注意,此种方式 必须满足:当前Ioc容器中 只能有一个Bean满足条件 )
constructor: 其他bean的类型(class) 是否与 该Course类的构造方法参数 的类型一致;此种方式的本质就是byType
我们以byName为例:
有teacher类 和course类 cousrse依赖于teacher ,不用自动装配为: <bean id="teacher" class="org.lanqiao.teacher.Teacher"></bean> <bean id="course" class="org.lanqiao.course.Course">
<property name="teacher" rel="teacher"></property> <!--rel里面的值为上面bean 的 id=teacher --> </bean>
现在用上自动装配,只需要 加上autowire="byName" 它就会自动根据id进行装配
<bean id="teacher" class="org.lanqiao.teacher.Teacher"></bean> <bean id="course" class="org.lanqiao.course.Course" autowire="byName"> </bean>
也可以在头文件中 一次性将该ioc容器的所有bean 统一设置成自动装配:
<beans xmlns="http://www.springframework.org/schema/beans"
...
default-autowire="byName">
自动装配虽然可以减少代码量,但是会降低程序的可读性,使用时需要谨慎。
最后,我们再讲下使用注解定义bean
通过注解的形式 将bean以及相应的属性值 放入ioc容器
首先要在applicationContext.xml中加入扫描语句
<context:component-scan base-package="org.lanqiao.dao">
</context:component-scan>
其次,在需要实例的类加上注解@Component("studentDao");studentDao只是个名字,可以随便命名,就像<bean>中的id属性一样,
Spring在启动的时候,会根据base-package在 该包中扫描所有类,查找这些类是否有注解@Component("studentDao"),如果有,则将该类 加入spring Ioc容器。
@Component细化:
dao层注解:@Repository
service层注解:@Service
控制器层注解:@Controller
(注明:@Repository、@Service、@Controller使用方式跟@Component一样的,这样写是为了方便理解,提高代码可读性)