# spring介绍
1、spring是什么?
一个开源的用来简化应用开发的框架。
spring是J2EE应用程序框架,是轻量级的IoC和AOP的容器框架,主要是针对javaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,ibatis框架等组合使用。
2、作用
##简化开发
spring对常用的api做了封装和简化(比如,对jdbc做了封装,使用spring jdbc来访问数据库,就不用考虑获取连接和关闭连接。)
##简化管理
spring提供一个容器。帮我们创建以及建立对象之间的依赖关系。
好处:降低对象之间的耦合度,方便代码的维护。
##集成其他框架
spring可以将其它的一些框架集成进来。(比如,集成用于任务调度的框架Quartz)。
1)IoC(Inversion of Control)控制反转,对象创建责任的反转,在spring中BeanFacotory是IoC容器的核心接口,负责实例化,定位,配置应用程序中的对象及建立这些对象间的依赖。XmlBeanFacotory实现BeanFactory接口,通过获取xml配置文件数据,组成应用对象及对象间的依赖关系。
spring中有三种注入方式,一种是set注入,一种是接口注入,另一种是构造方法注入。
2)AOP面向切面编程
aop就是纵向的编程,业务1和业务2都需要一个共同的操作,与其往每个业务中都添加同样的代码,不如写一遍代码,让两个业务共同使用这段代码。
spring中面向切面编程的实现有两种方式,一种是动态代理,一种是CGLIB,动态代理必须要提供接口,而CGLIB实现是有继承。
# 为什么使用spring框架
在不使用spring框架之前,我们的service层中要使用dao层的对象,不得不在service层中new一个对象。如下:
//dao层对象 public class UserDao{ publicvoid insert(User user){} } //service层对象 public classUserService{ publicvoid insert(User user){ UserDaouserdao = new UserDao(); userdao.insert(user); } }存在的问题:层与层之间的依赖。
使用框架后:
//dao层对象 public class UserDao{ public void insert(User user){} } //service层对象 public class UserService{ private UserDao userdao; public UserDao getUserdao() { returnuserdao; } public void setUserdao(UserDao userdao) { this.userdao= userdao; } public void insert(User user){ userdao.insert(user); } }service层要用dao层对象需要配置到xml配置文件中,至于对象是怎么创建的,关系是怎么组合的都交给了spring框架去实现。
4、框架优点
轻量级的容器框架没有侵入性
使用IoC容器更加容易组合对象直接间关系,面向接口编程,降低耦合
Aop可以更加容易的进行功能扩展,遵循ocp开发原则
创建对象默认是单例的,不需要再使用单例模式进行处理
5、缺点:业务功能依赖spring特有的功能,依赖于spring环境。
# spring容器(IOC)
##什么是spring容器?
spring框架的一个核心模块,用于管理对象。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。
Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些对象被称为 Spring Beans。IOC 容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
下图是 Spring 如何工作的高级视图。 Spring IoC 容器利用 Java 的 POJO 类和配置元数据来生成完全配置和可执行的系统或应用程序。
##Spring 提供了两种不同类型的容器。
它是最简单的容器,给 DI 提供了基本的支持,它用 org.springframework.beans.factory.BeanFactory 接口来定义。BeanFactory 或者相关的接口,如 BeanFactoryAware,InitializingBean,DisposableBean,在 Spring 中仍然存在具有大量的与 Spring 整合的第三方框架的反向兼容性的目的。
该容器添加了更多的企业特定的功能,例如从一个属性文件中解析文本信息的能力,发布应用程序事件给感兴趣的事件监听器的能力。该容器是由 org.springframework.context.ApplicationContext 接口定义。
注:ApplicationContext 容器包括 BeanFactory 容器的所有功能,所以通常建议超过 BeanFactory。
##启动spring容器
step1:导包。(spring-webmvc)
step2:添加配置文件。
step3:启动spring容器。
##创建对象
方法1:使用无参构造器。
1.给类添加无参构造器(或者缺省构造器)
2.配置<bean>元素。
3.调用容器的getBean方法来获得对象。
方法2:使用静态工厂方法。
通过调用类的静态方法来创建对象。
方法3:使用实例工厂方法。
通过调用对象的实例方法来创建对象。
package first; public class Student { public Student() { System.out.println("Student()"); } }package first;
public class FirstSpring { public static void main(String[] args) { //1.启动spring容器 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Student stu = ac.getBean("stu1",Student.class);
System.out.println(stu);
Date date = ac.getBean("date",Date.class);
System.out.println(date);
Calendar cal1 = ac.getBean("cal1",Calendar.class);
System.out.println(cal1);
Date time1 = ac.getBean("time1",Date.class);
System.out.println(time1);
}
}<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="" xmlns:xsi=""xmlns:context="" xmlns:jdbc="" xmlns:jee="" xmlns:tx="" xmlns:aop="" xmlns:mvc="" xmlns:util="" xmlns:jpa="" xsi:schemaLocation=""> <!-- 使用无参构造器创建对象。 id属性:bean的名称,要求唯一。 class属性:类的全限定名(即要求包名)。 --> <bean id="stu1" class="first.Student"></bean> <bean id="date" class="java.util.Date"></bean> <!-- 使用静态工厂方法创建对象 factory-method属性:指定一个静态方法。 spring容器会调用这个静态方法来创建对象。 --> <bean id="cal1" class="java.util.Calendar" factory-method="getInstance"></bean> <!-- 使用实例工厂方法创建对象 factory-bean属性:指定一个bean的id。 factory-method属性:指定一个方法,spring容器会调用这个bean的对应的方法来创建对象。 --> <bean id="time1" factory-bean="cal1" factory-method="getTime"></bean> </beans>
##作用域
默认情况下,容器对于某个bean,只会创建一个实例。
可以设置scope属性值为prototype,这样,容器对于某个bean会创建多个实例。
package scope; public class ScopeBean { public ScopeBean() { System.out.println("ScopeBean()"); } }<!-- scope属性:用来配置作用域,缺省值是singleton(单例), 如果值为prototype(原型)。--> <bean id="s1" class="scope.ScopeBean" scope="prototype"/>package test;public class TestCase { @Test//测试作用域 public void test1() { ApplicationContext ac = new ClassPathXmlApplicationContext("scope.xml");//启动spring容器
//创建对象
ScopeBean s1 = ac.getBean("s1",ScopeBean.class);
ScopeBean s2 = ac.getBean("s1",ScopeBean.class);
System.out.println(s1 == s2);
}
}测试结果: ScopeBean()
false
##生命周期
初始化方法:
使用init-method属性来指定初始化方法名。
销毁方法:
使用destroy-method属性来指定初始化方法名。
注:spring容器在关闭前,会销毁对象,在销毁对象之前,会先调用对象的销毁方法。
package scope; public class MessageBean { public MessageBean() { System.out.println("MessageBean()"); } public void init() { System.out.println("init()"); } public void sendMsg() { System.out.println("sendMsg()"); } public void destroy() { System.out.println("destroy()"); } }<!-- init-method属性:指定初始化方法。 destroy属性:指定销毁方法。 --> <bean id="mb1" class="scope.MessageBean" init-method="init" destroy-method="destroy" />@Test //测试生命周期 public void test2() { //ApplicationContext 接口 //ClassPathXmlApplicationContext 实现类 //AbstractApplicationContext 是ApplicationContext的子接口 AbstractApplicationContext ac = new ClassPathXmlApplicationContext("scope.xml"); MessageBean mb1 = ac.getBean("mb1",MessageBean.class); mb1.sendMsg(); ac.close(); }
###延迟加载
spring容器启动后会将所有作用域为单例的bean创建好。
注:只有作用域为单例时,销毁方法才会执行。
<!—lazy-init属性:指定是否延迟加载,如果为true,表示延迟加载。 -->
<bean id="mb1" class="scope.MessageBean" init-method="init" destroy-method="destroy" lazy-init="true" />
##IOC
###什么是IOC?
对象之间的依赖关系由容器来建立。
###DI(依赖注入)
容器通过调用对象提供的set方法或构造器来建立依赖关系。
IOC是目标,DI是手段。
1.set方式注入
package ioc; public class A { private IB ib; public void setB(IB ib) { System.out.println("setB()"); this.ib = ib; } public A() { System.out.println("A()"); } public void execute() { System.out.println("execute()"); ib.f1(); } }package ioc; public class B implements IB { public B() { System.out.println("B()"); } public void f1() { System.out.println("B's f1()"); } } package ioc; public class C implements IB { public C() { System.out.println("C()"); } public void f1() { System.out.println("C's f1()"); } } package ioc; public interface IB { public void f1(); }<bean id="b1" class="ioc.B" /> <bean id="c1" class="ioc.C"></bean> <!-- property元素:表示使用set方法注入依赖关系。 其中,name属性指定属性名,ref属性指定属性值(是被注入的bean的id) --> <bean id="a1" class="ioc.A"> <property name="b" ref="b1"></property> </bean>@Test //测试set方式的注入 public void test5() { ApplicationContext ac = new ClassPathXmlApplicationContext("ioc.xml"); A a1 = ac.getBean("a1",A.class); a1.execute(); }2.构造器方法
package ioc2; public class A { private B b; public A() { System.out.println("A()"); } public A(B b) { System.out.println("A(B)"); this.b = b; } public void execute() { System.out.println("execute()"); b.f1(); } }package ioc2; public class B { public B() { System.out.println("B()"); } public void f1() { System.out.println("B's f1()"); } }<bean id="b1" class="ioc2.B" /> <!-- constructor-arg元素:用来配置构造器方式的注入,其中, index属性指定参数的下标(从0开始)。 --> <bean id="a1" class="ioc2.A"> <constructor-arg index="0" ref="b1"></constructor-arg> <!-- <constructor-arg index="1" ref="c1"></constructor-arg> --> </bean>@Test public void test1() { ApplicationContext ac = new ClassPathXmlApplicationContext("ioc2.xml"); A a1 = ac.getBean("a1",A.class); a1.execute(); }3.自动装配
指的是spring容器依据某种规则,自动建立对象间的依赖关系。
注:a.默认情况下,容器不会自动装配。
b.可以通过指定autowire属性,来告诉容器进行自动装配
(容器仍需要通过set方法或构造器来完成依赖关系的建立)。
package ioc2; public class Waiter { public Waiter() { System.out.println("Waiter()"); } }package ioc2; public class Restaurant { private Waiter wt; public void setWt(Waiter wt) { System.out.println("setWt()"); this.wt = wt; } public Restaurant() { System.out.println("Restaurant()"); } @Override public String toString() { return "Restaurant [wt=" + wt + "]"; } }<!-- autowire属性:自动装配,有3个属性值: byName:容器依据属性名查找对应的bean,然后调用对应的set方法来完成注入。 注:a.如果找不到对应的bean,注入null。 b.不可能找到多个符合条件的bean。 byType:容器依据属性类型查找对应的bean,然后调用对应的set方法来完成注入。 注:a.如果找不到对应的bean,注入null。 b.有可能找到多个符合条件的bean,此时会出错。 constructor:与byType类似,不同的是调用对应的构造器来完成注入。 --> <bean id="wt" class="ioc2.Waiter"></bean> <!-- <bean id="rest" class="ioc2.Restaurant" autowire="byName" /> --> <bean id="rest" class="ioc2.Restaurant" autowire="byType" />@Test//测试自动装配 public void test2() { ApplicationContext ac = new ClassPathXmlApplicationContext("ioc2.xml"); Restaurant rest = ac.getBean("rest",Restaurant.class); System.out.println(rest); }###注入基本类型的值(使用value属性即可)
<bean id="vb1" class="value.ValueBean"> <property name="name" value="张三"></property> <property name="age" value="30"></property> </bean>###注入集合类型的值(List Set Map Properties)
package value; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; public class ValueBean { private String name; private int age; private List<String> city; private Set<String> interest; private Map<String,Double> score; private Properties db; public ValueBean() { System.out.println("ValueBean()"); } public void setScore(Map<String, Double> score) { this.score = score; } public void setDb(Properties db) { this.db = db; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } public void setCity(List<String> city) { this.city = city; } public void setInterest(Set<String> interest) { this.interest = interest; } @Override public String toString() { return "ValueBean [name=" + name + ", age=" + age + ", city=" + city + ", interest=" + interest + ", score=" + score + ", db=" + db + "]"; } }<bean id="vb1" class="value.ValueBean"> <property name="name" value="张三"></property> <property name="age" value="30"></property> <property name="city"> <list> <value>北京</value> <value>南京</value> <value>西京</value> </list> </property> <property name="interest"> <set> <value>小说</value> <value>小品</value> </set> </property> <property name="score"> <map> <entry key="english" value="60"></entry> <entry key="math" value="66"></entry> </map> </property> <property name="db"> <props> <prop key="username">Tiger</prop> <prop key="password">1234</prop> </props> </property> </bean>@Test public void test3() { ApplicationContext ac = new ClassPathXmlApplicationContext("value.xml"); ValueBean vb1 = ac.getBean("vb1",ValueBean.class); System.out.println(vb1); }输出:ValueBean()
ValueBean [name=张三, age=30, city=[北京, 南京, 西京], interest=[小说, 小品], score={english=60.0, math=66.0}, db={password=1234, username=Tiger}]###将集合类型的值配置成一个bean
<!-- 将集合类型的值配置成一个bean --> <util:list id="cityBean"> <value>上海</value> <value>武汉</value> <value>深圳</value> </util:list> <!-- 引用的方式注入集合类型的值 --> <bean id="vb2" class="value.ValueBean"> <property name="city" ref="cityBean"></property> </bean>@Test public void test4() { ApplicationContext ac = new ClassPathXmlApplicationContext("value.xml"); ValueBean vb2 = ac.getBean("vb2",ValueBean.class); System.out.println(vb2); }list、set、map、properties的情况和list相仿,此处不做重复。
###读取properties文件的内容
<!-- 读取properties文件的内容 classpath:按照类路径来搜索。 spring容器会依据路径找到对应的properties文件, 然后读取该文件的内容到properties对象。 --> <util:properties id="config" location="classpath:config.properties"></util:properties>pagesize=10@Test public void test5() { ApplicationContext ac = new ClassPathXmlApplicationContext("value.xml"); Object config = ac.getBean("config"); System.out.println(config); }
###spring表达式
可以使用spring表达式读取其它bean的属性,它的语法类似于el表达式。