1.什么是sprig
Spring是一个开源框架。,它是由Rod Johson创建。它是为了解决定企业开发的复杂性的创建的
Spring使用基本的JavaBeam来完成以前只可能由EJB完成的事情。
然而,Spring的用途不仅局限于服务器端的开发,从简单性,可测试性,和松耦合的角度而言,任何java应用都可从中受益。
目的:解决企业应用开发的复杂性。
功能:使用基本的javaBean代替EJB,并提供更多的企业应用功能
范围:任何的Java应用
它是一个容器框架,用来装JAVABean(java对象),中间层框架可以起连接作用,比如说吧struts和hibernate粘合在一起运用,简单来说,Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架。
IOC:Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
AOP:AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
Spring的特点:1.方便解耦,简化开发 通过Spring提供的IoC容器,我们可以将对象之间的依赖 关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。有了Spring, 用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可 以更专注于上层的应用。
2.AOP编程的支持 通过Spring提供的AOP功能,方便进行面向切面的编程, 许多不容易用传统OOP实现的功能可以通过AOP轻松应付。
3.声明式事务的支持 在Spring中,我们可以从单调烦闷的事务管理代码中解脱出 来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
4.方便程序测试 可以用非容器依赖的编程方式进行几乎所有的测试工作,在 Spring里,测试不再是昂贵的操作,而是随手可做的事情。例如:Spring对 Junit4支持,可以通过注解方便的测试Spring程序。
5.方便集成各种优秀框架 Spring不排斥各种优秀的开源框架,相反,Spring可 以降低各种框架的使用难度,Spring提供了对各种优秀框架(如 Struts,Hibernate、Hessian、Quartz)等的直接支持。
6.降低java EE APL的使用难度 Spring对很多难用的Java EE API(如JDBC, JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装, 这些Java EE API的使用难度大为降低。
7.源码是经典的学习范例 Spring的源码设计精妙、结构清晰、匠心独用,处 处 体现着大师对Java设计模式灵活运用以及对Java技术的高深造诣。Spring 框架源码无疑是Java技术的最佳实践范例。如果想在短时间内迅速提高自己 的Java技术水平和应用开发水平,学习和研究Spring源码将会使你收到意想 不到的效果。
Spring的优点:1.低侵入式设计,代码污染极低
2.独立于各种应用服务器,基于Spring框架的应用,可以真正实现Write Once,Run Anywhere的承诺
3.Spring的DI机制降低了业务对象替换的复杂性,提高了组件之间的解耦
4.Spring的AOP支持允许将一些通用任务如安全、事务、日志等进行集中式管理, 从而提供了更好的复用
5.Spring的ORM和DAO提供了与第三方持久层框架的良好整合,并简化了底层的 数据库访问
6.Spring并不强制应用完全依赖于Spring,开发者可自由选用Spring框架的部分或 全部
2.耦合:
一个软件结构内不同模块之间互连程度的度量(耦合性也叫块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差,模块间耦合的高低取决于模块间接口的复杂性,调用的方式以及传递的信息。)
软件工程规定写代码的原则是“高内聚,低耦合”。内聚是代码块间的独立性,耦合是各个代码块间的联系。
3.Spring的核心:
控制反转(IOC):
实现将组件间的关系从程序内部提到外部容器(spring的xml)来管理。
首先外部容器(spring.xml)中会动态的注册业务所需的对象(接口/类)
依赖注入(DI):
组件之间的依赖关系由容器在应用系统运行期来决定, 也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中
范例:
如: 注入xml中
类:
通过获取容器注册的方法
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.openlab.opjo.Car;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
Car car=context.getBean("person", Car.class);
System.out.println(car);
//
System.out.println("=============");
}
}
面向切面编程(AOP):
利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
4.IOC含义
控制反转(IOC,Inversion of Control)
传统的JAVA开发模式中,当需要一个对象时,我们使用new或者通过getInstance等直接或者间接调用构造方法创建一个对象,而在Spring开发模式中,Spring容器使用工厂模式为我们创建了所需要的对象,不需要我们自己去创建了,直接调用Spring提供的对象就可以了,这就是控制反转
5.DI:
依赖注入,在创建对象的过程中Spring可以依据配置对象的属性进行设置,这个过程称为依赖注入(DI)
IOC和DI的区别:
IOC:控制反转,指将对象的创建权,反转到spring容器。
DI:依赖注入,指在创建对象的过程中,将对象依赖的属性通过配置进行注入。DI的实现依赖于IOC,先有控制反转才有依赖注入
6.属性注入的方式
构造方法注入:
<bean id="car" class="com.openlab.opjo.Car">
<constructor-arg name="baran" value="123we"></constructor-arg>
<constructor-arg name="corp" value="red"></constructor-arg>
<constructor-arg name="price" value="3425"></constructor-arg>
<constructor-arg name="maxpeed" value="12"></constructor-arg>
</bean>
set方法注入:
<bean id="car" class="com.openlab.opjo.Car">
<property name="baran" value="123we"></property>
<property name="corp" value="red"></property>
<property name="price" value="3425"></property>
<property name="maxpeed" value="12"></property>
</bean>
p名称空间注入
<bean id="car" class="com.openlab.opjo.Car" p:baran="123we" p:corp="red"
p:price="3425" p:maxpeed="12">
</bean>
7.注入集合属性:
Java.utils包中常用集合
(1)List
(2)Set
(3)Map
(4)Properties
Spring为集合提供了对应的标签:
<list> 注入 list元素
<set> 注入 set元素
<map> 注入 map元素
<props> 注入 properties 元素 (hashtable类的子类,是特殊的map,key和value都是String )
例子:
配置spring的核心容器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="listperson" class="com.openlab.opjo.Listperson">
<property name="Hobbies">
<list>
<value>吃饭</value>
<value>睡觉</value>
<value>打豆豆</value>
<value>喝水</value>
</list>
</property>
</bean>
</beans>
类:
package com.openlab.opjo;
import java.util.List;
public class Listperson {
public List<String> Hobbies;
public List<String> getHobbies() {
return Hobbies;
}
public void setHobbies(List<String> hobbies) {
Hobbies = hobbies;
}
@Override
public String toString() {
return "Listperson [Hobbies=" + Hobbies + "]";
}
}
实现:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.openlab.opjo.Listperson;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
Listperson listperson=context.getBean("listperson", Listperson.class);
System.out.println(listperson);
//
System.out.println("=============");
}
}
运行结果:
注意map配置(不是value而是entry):
<map>
<entry key="name" value="张三"/>
<entry key="age" value="22"/>
<entry key="car" value-ref="car"></entry>
</map>
<props> 注入 properties 元素是:
<props>
<prop key="name">李四</prop>
<prop key="age">33</prop>
</props>
其他的和List类似。
8.Spring管理Bean的作用域
Spring Bean 中所说的作用域,在配置文件中即是“scope”
在面向对象程序设计中作用域一般指对象或变量之间的可见范围。
而在Spring容器中是指其创建的Bean对象相对于其他Bean对象的请求可见范围。
1.singleton
<bean id="listperson" class="com.openlab.opjo.Listperson" scope="singleton"></bean>
当Bean作用域为singleton时,Spring容器中只会存在一个共享的Bean实例,所有对Bean的请求只要id与bean的定义相匹配,则只会返回bean的同一实例。单一实例会被存储在单例缓存中,为Spring的缺省作用域(即默认为singleton)。
2. prototype:
<bean id="listperson" class="com.openlab.opjo.Listperson" scope=" prototype "></bean>
当Bean作用域为prototype时,Spring IoC都会创建一个新的作用域(即每次获取的都是一个新对象)对于有状态的Bean应该使用prototype,对于无状态的Bean则使用singleton
3. request:
<bean id="listperson" class="com.openlab.opjo.Listperson" scope=" request "></bean>
Request作用域针对的是每次的Http请求,Spring容器会根据相关的Bean的
定义来创建一个全新的Bean实例。而且该Bean只在当前request内是有效的。
4. session:
<bean id="listperson" class="com.openlab.opjo.Listperson" scope=" session "></bean>
针对http session起作用,Spring容器会根据该Bean的定义来创建一个全新的Bean的实例。而且该Bean只在当前http session内是有效的。
5. globalsession:
<bean id="listperson" class="com.openlab.opjo.Listperson" scope="globalsession"></bean>
类似标准的http session作用域,不过仅仅在基于portlet的web应用当中才有意义。Portlet规范定义了全局的Session的概念。他被所有构成某个portlet外部应用中的各种不同的portlet所共享。在global session作用域中所定义的bean被限定于全局的portlet session的生命周期范围之内。
9.Spring管理的bean的生命周期:
案例:
package com.openlab.opjo;
public class Listperson {
public String name;
public Listperson() {
super();
System.out.println("无参构造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("set方法执行");
}
public void init(){
System.out.println("init方法执行");
}
public void destroy(){
System.out.println("destroy方法执行");
}
}
.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="listperson" class="com.openlab.opjo.Listperson" init-method="init"
destroy-method="destroy" p:name="若尘">
</bean>
测试类:
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.openlab.opjo.Listperson;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
Listperson listperson=context.getBean("listperson", Listperson.class);
System.out.println(listperson);
context.close();
//
System.out.println("=============");
}
}
结果:
例二:
package com.openlab.opjo;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.lang.Nullable;
public class Listperson1 implements BeanPostProcessor {
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之前");
return bean;
}
@Nullable
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之后");
return bean;
}
}
package com.openlab.opjo;
public class Listperson {
public String name;
public Listperson() {
super();
System.out.println("无参构造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("set方法执行");
}
public void init(){
System.out.println("init方法执行");
}
public void destroy(){
System.out.println("destroy方法执行");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="listperson1" class="com.openlab.opjo.Listperson1"></bean>
<bean id="listperson" class="com.openlab.opjo.Listperson" init-method="init"
destroy-method="destroy" p:name="若尘">
</bean>
</beans>
测试类:
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.openlab.opjo.Listperson;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
Listperson listperson=context.getBean("listperson", Listperson.class);
System.out.println(listperson);
context.close();
//
System.out.println("=============");
}
}
结果
10.Spring中bean的两种方式
BeanFactory:
BeanFactory是spring中比较原始,比较古老的Factory。因为比较古老,所以BeanFactory无法支持spring插件,例如:AOP、Web应用等功能。
利用BeanFactory获取bean
//XmlBeanFactory是典型的BeanFactory。
BeanFactory factory = new XmlBeanFactory("XXX.xml");
//获取一个叫做mdzz的bean。在这个时候进行实例化。
factory.getBean("xxxx");
重点:当我们使用BeanFactory去获取Bean的时候,我们只是实例化了该容器,而该容器中的bean并没有被实例化。当我们getBean的时候,才会实时实例化该bean对象。
ApplicationContext
ApplicationContext是BeanFactory的子类,因为古老的BeanFactory无法满足不断更新的spring的需求,于是ApplicationContext就基本上代替了BeanFactory的工作,以一种更面向框架的工作方式以及对上下文进行分层和实现继承,并在这个基础上对功能进行扩展:
<1>MessageSource, 提供国际化的消息访问
<2>资源访问(如URL和文件)
<3>事件传递
<4>Bean的自动装配
<5>各种不同应用层的Context实现
利用ApplicationContext获取bean
//当我们实例化XXX.xml的时候,该文件中配置的bean都会被实例化。(该bean scope是singleton)
ApplicationContext appContext = new ClassPathXmlApplicationContext("XXX.xml");
重点:当我们使用ApplicationContext去获取bean的时候,在加载XXX.xml的时候,会创建所有的配置bean。
三种获取ApplicationContext对象引用的方法
/第一种加载方法,加载的是classpath下的配置文件。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//第二种加载方法,加载的是磁盘路径下的文件。
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("applicationContext.xml");
//第三种加载方法,XmlWebApplicationContext,从web系统中加载。
//得到配置文件后,就能拿到想要的对象。例如:
HelloService helloService = (HelloService) applicationContext.getBean("userService");
//在这当中getBean中的参数为你在配置文件下,这个对象的id,一个标识。
区别总结
<1>如果使用ApplicationContext,如果配置的bean是singleton,那么不管你有没有或想不想用它,它都会被实例化。好处是可以预先加载,坏处是浪费内存。
<2>BeanFactory,当使用BeanFactory实例化对象时,配置的bean不会马上被实例化,而是等到你使用该bean的时候(getBean)才会被实例化。好处是节约内存,坏处是速度比较慢。多用于移动设备的开发。
<3>没有特殊要求的情况下,应该使用ApplicationContext完成。因为BeanFactory能完成的事情,ApplicationContext都能完成,并且提供了更多接近现在开发的功能。