一、spring:是分层的Java SE/EE应用full-stack轻量级框架,以IOC(翻转控制)和AOP(面向切面编程)为内核,提供了展现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术。
spring的优势:
a.方便解耦,简化开发。通过spring提供的IOC容器,可以将对象间的依赖关系交由spring进行控制,避免硬解码所造成的过度耦合.
b.AOP编程的支持。通过spring的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以用AOP实现。
c.声明式事务的支持。可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理, 提高开发效率和质量。
d.方便测试。可以用非容器依赖的编程方式进行几乎所有测试工作,测试不再是昂贵的操作。
e.方便集成各种优秀框架。spring可以降低各种框架的使用难度,提供了对各种优秀框架的直接支持。
f.降低Java EE API的使用难度。spring对Java EE API(如JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些API的使用难度大为降低。
g.spring 源码是经典学习范例。
程序间的耦合
耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差(降低耦合性,可以提高其独立性)。
二、控制反转 IOC:
IOC是解耦的一种思想,解耦的途径的有很多:比如 依赖注入DI(只是解耦的一种解决方案)。
程序中核心业务代码由主动创建对象变成被动的接受对象。
创建对象的控制权发生了转变 ==== >> 控制反转。
Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”:
谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)
为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
三、基于xml方式来创建spring核心容器对象
步骤:创建一个xml文件,导入spring核心容器相关的约束—>>创建核心容器对象—>>从容器中取出实例。
BeanFactory和ApplicationContext的区别:
1、BeanFactory才是spring容器的顶层接口,ApplicationContext是它的子接口。
2、创建对象的时间点不一样:
BeanFactory:什么时候使用什么时候创建
ApplicationContext:只要一读取配置文件,默认情况下就会创建。
四、在spring中,如何将一个类的实例装载到spring容器中?
1、基于xml配置的方式,使用核心容器对象ClassPathXmlApplicationContext
spring在获取实例时执行的流程:首先会解析xml文件,去读取每一个标签,如果发现有bean标签,那么会解析bean标签对应的属性,获取读取class 属性的值,然后通过反射机制创建实例,保存到容器中,会将id属性作为该实例的标识。
bean标签
bean标签作用:
用于配置对象让spring来创建的。默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。
属性:
id:给对象在容器中提供一个唯一标识。用于获取对象
class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
scope:指定对象的作用范围。
scope属性
singleton :默认值,单例的.
prototype :多例的.
request :WEB 项目中,Spring创建一个 Bean的对象,将对象存入到 request域中.
session :WEB 项目中,Spring创建一个 Bean的对象,将对象存入到 session域中.
global session :WEB 项目中,应用在 Portlet 环境.如果没有Portlet 环境那么globalSession相当于
session.
五、如何将一个实例存放进核心容器中,在程序中多次获取该实例,取得的实例是不是单例的?
public static void main(String[] args) {
//创建核心容器对象
ClassPathXmlApplicationContext con = new ClassPathXmlApplicationContext("com/jy/xml/beans.xml");
//从容器中取出对应实例
Object user1 = con.getBean("user");
Object user2 = con.getBean("user");
System.out.println(user1 == user2);
}
输出结果为true,说明默认情况下单例的,但我们可以将其修改为多例:
<bean id="user" class="com.beans.User" scope="prototype">
六、spring中基于xml配置的方式完成依赖注入
组件的依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件中。DI的目的不是为了给软件系统带来更多功能,而是为了提升组件重用的效率,并为系统搭建一个灵活、可扩展的平台。
1、基于set的注入方式:property标签,要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型 , 没有set方法 , 是 is .
<!--
property标签的作用:通过set方法完成对属性的注入
ref可以去引入容器中别的实例,属性值就是需要引入实例的唯一标识
-->
<bean id="user" class="com.beans.User" scope="prototype">
<!--给id属性赋值-->
<property name="id" value="1001"></property>
<property name="name" value="root"></property>
<property name="password" value="123456"></property>
<property name="object" value="123456"></property>
<!--给数组注入数据-->
<property name="objects">
<array value-type="java.lang.String">
<value>1111</value>
<value>2222</value>
<value>3333</value>
<value>4444</value>
</array>
</property>
<!--注入自定义的引用数据类型-->
<property name="student" ref="student"></property>
给list类型注入数据
<!--给list类型的属性注入数据-->
<property name="list">
<list>
<value>123456</value>
<value>true</value>
<value>false</value>
<value>11001</value>
</list>
</property>
给map类型注入数据
<property name="map">
<map>
<entry key="key1" value="value1"></entry>
<entry key="key2" value="value2"></entry>
<entry key="key3" value="value3"></entry>
<entry key="key4" value="value4"></entry>
</map>
</property>
特殊类型日期类型的数据注入
<!--注册一个日期实例-->
<bean id="date" class="java.util.Date"></bean>
<!--注入日期类型的数据-->
<property name="date" ref="date"></property>
beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
bean标签的作用:将一个类的实例通过反射机制创建出来,装载进核心容器中
id属性:唯一标识,不能重复的
class属性:属性值就是类的全限定类名
scope属性:可以去设置该实例的作用范围
-->
<!--
property标签的作用:通过set方法完成对属性的注入
ref可以去引入容器中别的实例,属性值就是需要引入实例的唯一标识
-->
<bean id="user" class="com.beans.User" scope="prototype">
<!--给id属性赋值-->
<property name="id" value="1001"></property>
<property name="name" value="root"></property>
<property name="password" value="123456"></property>
<property name="object" value="123456"></property>
<!--给数组注入数据-->
<property name="objects">
<array value-type="java.lang.String">
<value>1111</value>
<value>2222</value>
<value>3333</value>
<value>4444</value>
</array>
</property>
<!--注入自定义的引用数据类型-->
<property name="student" ref="student"></property>
</bean>
<!--将学生实例装载进核心容器中-->
<bean id="student" class="com.beans.Student">
<!--注入属性的值-->
<property name="name" value="jack"></property>
<property name="id" value="11001"></property>
<!--给list类型的属性注入数据-->
<property name="list">
<list>
<value>123456</value>
<value>true</value>
<value>false</value>
<value>11001</value>
</list>
</property>
<!--给map类型的属性注入数据-->
<property name="map">
<map>
<entry key="key1" value="value1"></entry>
<entry key="key2" value="value2"></entry>
<entry key="key3" value="value3"></entry>
<entry key="key4" value="value4"></entry>
</map>
</property>
<!--注入日期类型的数据-->
<property name="date" ref="date"></property>
</bean>
<!--注册一个日期实例-->
<bean id="date" class="java.util.Date"></bean>
</beans>