目录
Spring
的ioc
操作
- 把对象的创建交给
Spring
管理 ioc
操作分为两种
- 配置文件方式
- 注解方式
ioc
底层使用的技术
xml
配置文件dom4j
解析xml
文件、- 工厂设计模式
- 反射
ioc
底层原理
需求
:创建一个类,并其调用其非静态方法;、
- 没有使用
Spring
之前
我们知道不能在servlet
中,直接new
services
层对象,导致 web
层和 services
层的耦合太高;没接触Spring之前,我们一般使用工厂来解耦web
层和 services
层 ;
但是这样做,又导致services
层和 工厂
紧紧的关联在一起,它们的耦合又变得太高了!比如,现在services
层,有类的名字发生了改变,那么工厂类中,也需要相应的改变类的名字;因此本质上,并没有解决耦合的问题;
- 使用
Spring
之后
假如我们在,配置文件
中,配置要创建对象的类,然后创建一个工厂
类,在工厂类中,使用dom4j
解析xml
配置文件,然后利用反射
,创建对象;
这样,后期即使要改动,比如改动了类的名字,我们也只需要在配置文件改动类的名字,其他地方的代码是不需要改变的;
Spring
的ioc
,就是这样帮我们创建对象的;上面也就是IOC
的底层原理;
ioc
入门案例
导入
Spring jar
包做
spring
最基本的功能时,只需要导入四个核心
的jar
包:Beans
、Core
、Context
、SpEL
即可;导入支持日志的
jar
包因为,Spring本身没有支持日志;
日志 jar
:log4j
、commons-logging
;spring
配置文件(1) 配置文件的名字和位置,不是固定的,可以随便放置;官方建议放在
src
目录下,取名为ApplicationContext.xml
;(2) 引入
schema
约束文件<?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 " default-autowire="byName"> <bean id="user" class="xin.ijava.domian.User"/> </beans>
代码实例
@Test public void testIoc(){ // 1、加载Spring配置文件,参数配置文件的路径+名字;从src开始写 ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); // 2、获取配置文件中配置的对象 User user = (User) context.getBean("user"); System.out.println(user); user.speak(); } ------------------- 输出 ------------------------------- xin.ijava.domian.User@6c1ec7a3 User 说话、、
bean
管理(xml方式)
也就是 ioc 操作
bean
实例化(三种方式实现)实例化,就是通过配置文件由 Spring 来创建对象; 基本上只用第一种方式创建对象;
第一种
:使用类的无参构造器
创建(重点)只需要写出一个
bean
类即可;配置文件中写法
<!--无参构造器创建bean实例--> <bean id="user" class="xin.ijava.domian.User"/>
第二种
:使用静态工厂
创建(没有创建工厂对象)除了
bean
类,还需要写一个bean
的工厂,工厂中含有静态方法,返回bean
;配置文件中写法:
class
属性为:工厂类;factory-method
属性为:工厂静态方法<!--静态工厂方法创建bean实例--> <bean id="bean2" class="xin.ijava.domian.Bean2Factory" factory-method="getBean2"/>
第三种
:使用实例工厂
创建(创建工厂了对象)配置文件中写法:先创建工厂实例,再利用工厂实例创建
bean
实例<!--实例工厂方法创建bean实例--> <bean id="bean3Factory" class="xin.ijava.domian.Bean3Factory"/> <bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3"/>
bean
标签常用属性id
:起名字,名字可以为任意名字,但是名字中不可以有特殊字符; 可以根据 id,获取配置对象;
class
:创建对象所在类的全路径;
name
:功能和 id 一样,但是可以包含特殊字符,主要是为了整合 Struts1 的遗留问题 现在也不再使用,推荐使用 id ;
scope
:Bean 的作用范围 ;有几个可选值 ; singleton :默认值,单例 prototype :多例 request:Spring创建的对象,保存在request域中 ; session:Spring创建的对象,保存在session域中 ; globalSession:应用在 Porlet 环境,如果没有 Porlet 环境,则globalSession相当于 session ; 最后的 globalSession ,用于单点登录的时候;
属性注入
属性注入:创建对象的时候,往类里面属性设置值; 属性注入有三种方式;
第一种
:使用set
方法注入(重点)使用这样方式,类中必须要有无参构造器,因为底层实现的时候,也是先创建对象,再赋值属性的;
配置文件写法:
<!--set 方法注入,需要有无参的构造器存在,因为是先new对象出来,再复制的--> <bean id="book2" class="xin.ijava.domian.Book" > <property name="name" value="哆啦A梦"></property> </bean>
第二种
:使用有参构造器
方法注入这样注入,不需要有无参构造器存在,因为底层实现的时候,是直接调用有参构造器;
配置文件写法:
<!--属性注入。使用有参构造器--> <bean id="book1" class="xin.ijava.domian.Book" > <constructor-arg name="name" value="肥嘟嘟左卫门"></constructor-arg> </bean>
注入
对象类型
属性使用场景:在 Services 层调用 Dao 层方法,我们将dao的创建工作交给 Spring
/** * Dao层代码 */ package xin.ijava.domian; public class UserDao { public void add(){ System.out.println("UserDao ... add"); } } ------------------------------------------- package xin.ijava.domian; /** * Service层代码 */ public class Service { // 将dao层作为属性 private UserDao userDao ; public UserDao getUserDao() { return userDao; } // 设置set 方法,便于 set 注入 public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void add(){ System.out.println("Service ... add"); userDao.add(); } }
配置文件写法:
<!--对象属性注入--> <!--创建dao层对象--> <bean id="userDao" class="xin.ijava.domian.UserDao"></bean> <!--创建services层对象,将dao层对象注入进去--> <bean class="xin.ijava.domian.Service" id="service"> <!--对于引用类型,使用 ref ,不可使用value--> <property name="userDao" ref="userDao"></property> </bean>
P名称空间
注入<beans xmlns="http://www.springframework.org/schema/beans" <!--自定义名称空间P--> xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <!--P名称空间注入--> <bean id="book3" class="xin.ijava.domian.Book" p:name="啦啦啦"/>
复杂类型
属性注入涉及
数组
、map
、list
、properties
等类型 ;<!--复杂类型属性注入--> <bean class="xin.ijava.domian.Bean4" id="bean4"> <!--为数组赋值。使用list,就是list一脉下面的集合,就是有list赋值--> <!--list下面使用value--> <property name="strings"> <list> <value>那么多唱歌动听的人呦。。。</value> <value>千秋直美</value> <value>村下孝藏</value> <value>那么多唱歌动听的人呦。。。</value> </list> </property> <!--为list集合赋值--> <property name="list"> <list> <value>哈哈</value> <value>呵呵</value> </list> </property> <!--为map赋值--> <!--使用键值对一脉的,都是用map赋值--> <!--而map使用 entry--> <property name="map"> <map> <entry key="driverClass" value="com.mysql.jdbc.driver"></entry> </map> </property> <!--为properties赋值--> <!--使用props赋值--> <property name="properties"> <props> <prop key="name" >root</prop> <prop key="password" >root</prop> </props> </property> </bean>
IOC
和DI
的区别
IOC
:控制反转,是将对象的创建交给 Spring
来完成 ;
DI
:依赖注入,是为对象的属性赋值 ;
关系
:DI
不能单独存在,必须依赖于 IOC
;
Spring
整合WEB
的原理
加载
Spring
的核心配置文件// 1、加载Spring配置文件,参数配置文件的路径+名字;从src开始写 ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
new
对象的效率问题假如每个地方需要用到配置文件的话,都new 一个对象的话,那么效率会低到爆炸;
你可能会想到在
静态代码块
里面new
,然后复用它,这样第一次使用的时候,还是需要等待的;在服务器启动的时候,创建
配置文件对象
将压力扔给服务器,在服务器启动的时候,让服务器创建
配置文件对象
,这样第一次用的时候,对象就已经被创建好了;共享
配置文件对象
服务器在启动的时候,会为每一个项目,创建一个
servletContext
对象,使用监听器,监听servletContext
对象的创建 ,就监听到服务器的启动,在监听器里面创建配置文件对象
,然后将其添加进servletContext
域中,就可以共享配置文件对象
了 ;上面说的,也就是
Spring
自动创建配置对象
的原理
Spring
整合的具体操作
Spring
中具体操作步骤上面说到,我们可以通过
监听器
、servletContext
实现在服务器启动的时候,加载配置文件,创建配置文件对象 ;但是在
Spring
中,不需要我们自己动手写上面的代码。Spring
对其做了封装 ;Spring
自己封装了一个监听器
,我们那只需要去配置这个监听器
即可,配置之前,确保导入了Spring-web
的包 ;<!--配置Spring的监听器--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
加上监听器以后,这时候会报错:
Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/applicationContext.xml]
告诉我们,在
WEB-INF
目录下,找不到名字叫applicationContext.xml
的配置文件 ;这时候,我们可以将配置文件放在对应的目录下面,起对应的名字 ;
但是,我们刚学
Spring
的时候,就被告知配置文件是可以随便放在哪里的,名字随便起的 ;这时候,需要我们在 Web.xml 中再配置一下:<!--配置Spring的配置文件路径--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:ApplicationContext.xml</param-value> </context-param>
其中:
<param-name>
属性的值是固定的 ;<param-value>
属性的值是classpath:
后面跟上Spring
配置文件的位置和名字 ;然后运行项目,在控制台可以看到:
INFO XmlBeanDefinitionReader:317 - Loading XML bean definitions from class path resource [ApplicationContext.xml]
可以看到,我们的
Spring
配置文件被加载了 ;