1、方便解耦,简化开发 通过 Spring 提供的 IoC 容器,可以将对象间的依赖关系交由 Spring 进行控制,避免硬编码所造 成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可 以更专注于上层的应用。 AOP 编程的支持 通过 Spring 的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付。
2、 声明式事务的支持 可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理, 提高开发效率和质量。
3、方便程序的测试 可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可 做的事情。
4、方便集成各种优秀框架 Spring 可以降低各种框架的使用难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、Quartz 等)的直接支持。 降低 JavaEE API 的使用难度 Spring 对 JavaEE API(如 JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些 API 的 使用难度大为降低。
5、Java 源码是经典学习范例 Spring 的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对 Java 设计模式灵活运用以 及对 Java 技术的高深造诣。它的源代码无意是 Java 技术的最佳实践的范例。
可以一句话概括:Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的框架
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式 。
图片和这一部分文本来源微信公众号狂神说。
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。
Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
文本来源参考链接:
IoC也称为依赖注入。在此过程中,对象仅通过构造函数参数,工厂方法的参数或在构造或从工厂方法返回后在对象实例上设置的属性来定义其依赖项(即,与它们一起使用的其他对象) 。然后,容器在创建bean时注入那些依赖项。此过程从根本上讲是通过使用类的直接构造或诸如服务定位器模式之类的控件来控制其依赖项的实例化或位置的bean本身的逆过程(因此称为Control的倒置)。
在Spring中,构成应用程序主干并由Spring IoC容器管理的对象称为bean。Bean是由Spring IoC容器实例化,组装和管理的对象。否则,bean仅仅是应用程序中许多对象之一。Bean及其之间的依赖关系反映在容器使用的配置元数据中。
(1)内容耦合。当一个模块直接修改或操作另一个模块的数据时,或一个模块不通过正常入口而转入另 一个模块时,这样的耦合被称为内容耦合。内容耦合是最高程度的耦合,应该避免使用之。
(2)公共耦合。两个或两个以上的模块共同引用一个全局数据项,这种耦合被称为公共耦合。在具有大 量公共耦合的结构中,确定究竟是哪个模块给全局变量赋了一个特定的值是十分困难的。
(3) 外部耦合 。一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传 递该全局变量的信息,则称之为外部耦合。
(4) 控制耦合 。一个模块通过接口向另一个模块传递一个控制信号,接受信号的模块根据信号值而进 行适当的动作,这种耦合被称为控制耦合。
(5)标记耦合 。若一个模块 A 通过接口向两个模块 B 和 C 传递一个公共参数,那么称模块 B 和 C 之间 存在一个标记耦合。
(6) 数据耦合。模块之间通过参数来传递数据,那么被称为数据耦合。数据耦合是最低的一种耦合形 式,系统中一般都存在这种类型的耦合,因为为了完成一些有意义的功能,往往需要将某些模块的输出数据作为另 一些模块的输入数据。
(7) 非直接耦合 。两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实 现的。 总结: 耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应采用以下原则:如果模块间必须 存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免使用内容耦合。
Ioc容器就是解决程序之间的耦合度,让每个部分的程序之间的联系减少,因为程序的耦合关系越大,到了后期代码量非常大,一旦修改了某些东西,那么基本所有的代码都要修改。
参考图片:
文本来源参考链接:
https://baike.baidu.com/item/%E6%8E%A7%E5%88%B6%E5%8F%8D%E8%BD%AC/1158025?fr=aladdin
https://blog.csdn.net/ivan820819/article/details/79744797
package com.BeanTest;
public class Pet {
private String petName;
private Integer petAge;
private String petHobby;
public Pet(String petName,Integer petAge,String petHobby){
this.petAge = petAge;
this.petHobby = petHobby;
this.petName = petName;
}
public Pet(){
/*this.petAge = 13;
this.petHobby = "溜达";
this.petName = "旺财";*/
System.out.println("Pet类的无参数构造方法");
}
public String getPetName() {
return petName;
}
public void setPetName(String petName) {
this.petName = petName;
}
public int getPetAge() {
return petAge;
}
public void setPetAge(int petAge) {
this.petAge = petAge;
}
public String getPetHobby() {
return petHobby;
}
public void setPetHobby(String petHobby) {
this.petHobby = petHobby;
}
@Override
public String toString() {
return "Pet{" +
"petName='" + petName + '\'' +
", petAge=" + petAge +
", petHobby='" + petHobby + '\'' +
'}';
}
}
package com.BeanTest;
public class Teacher {
private String teacherName;
private Integer teacherAge;
private Pet pet;
public String getTeacherName() {
return teacherName;
}
public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
public Integer getTeacherAge() {
return teacherAge;
}
public void setTeacherAge(Integer teacherAge) {
this.teacherAge = teacherAge;
}
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
@Override
public String toString() {
return "Teacher{" +
"teacherName='" + teacherName + '\'' +
", teacherAge=" + teacherAge +
", pet=" + pet +
'}';
}
}
创建测试类AllUser,所用的测试单元测试包为:import org.junit.Test;
这是Spring的单元测试组件,记住要在pom.xml里面导入Test的依赖。
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
package com.BeanTest;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AllUser {
@Test
public void TestAllUser(){
/*有参构造方法*/
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
Pet pet = applicationContext.getBean("pet",Pet.class);
System.out.println("基于xml配置的有参数构造:"+pet);
/*无参数构造方法*/
Pet pet1 = applicationContext.getBean("pet1",Pet.class);
System.out.println("无参数构造方法:"+pet1);
Teacher teacher = applicationContext.getBean("teacher",Teacher.class);
System.out.println(teacher);
}
}
<?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">
</beans>
<!--有参构造方法-->
<bean id="pet" class="com.BeanTest.Pet">
<!-- <!–第一种方法:根据index参数下标设置–>
<constructor-arg index="0" value="二货"></constructor-arg>
<constructor-arg index="1" value="3"></constructor-arg>
<constructor-arg index="2" value="吃东西"></constructor-arg>-->
<!-- <!–第二种方法:根据参数的名字设置值–>
<constructor-arg name="petAge" value="1"></constructor-arg>
<constructor-arg name="petName" value="傻狗"></constructor-arg>
<constructor-arg name="petHobby" value="睡觉"></constructor-arg>-->
<!--第三种方法:根据参数的类型设置值-->
<constructor-arg type="java.lang.String" value="小傻狗"></constructor-arg>
<constructor-arg type="java.lang.String" value="叼东西"></constructor-arg>
<constructor-arg type="java.lang.Integer" value="4"></constructor-arg>
</bean>
<!--
无参数构造方法:
其实无参数构造方法在调用类的toString的方法之前就已经创建了。
-->
<bean id="pet1" class="com.BeanTest.Pet">
<property name="petAge" value="5"></property>
<property name="petHobby" value="玩耍"></property>
<property name="petName" value="大黄"></property>
</bean>
Teacher类的对象创建:
<bean id="teacher" class="com.BeanTest.Teacher">
<property name="teacherAge" value="23"></property>
<property name="teacherName" value="小华"></property>
<!--Bean注入-->
<property name="pet" ref="pet1"></property>
</bean>
创建BookTest类
package com.BeanTest;
import java.util.*;
import java.util.List;
public class BookTest {
private String[] lesson;
private int price;
private List<String> bookName;
private Map<String,Object> map;
private List<Pet> petList;
private Set<String> stringSet;
private Properties properties;
private String book;
public String getBook() {
return book;
}
public void setBook(String book) {
this.book = book;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public String[] getLesson() {
return lesson;
}
public void setLesson(String[] lesson) {
this.lesson = lesson;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public List<String> getBookName() {
return bookName;
}
public void setBookName(List<String> bookName) {
this.bookName = bookName;
}
public Map<String, Object> getMap() {
return map;
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
public List<Pet> getPetList() {
return petList;
}
public void setPetList(List<Pet> petList) {
this.petList = petList;
}
public Set<String> getStringSet() {
return stringSet;
}
public void setStringSet(Set<String> stringSet) {
this.stringSet = stringSet;
}
@Override
public String toString() {
return "BookTest{" +
"lesson=" + Arrays.toString(lesson) +
", price=" + price +
", bookName=" + bookName +
", map=" + map +
", petList=" + petList +
", stringSet=" + stringSet +
", properties=" + properties +
", book='" + book + '\'' +
'}';
}
}
<bean id="pet1" class="com.BeanTest.Pet">
<property name="petAge" value="5"></property>
<property name="petHobby" value="玩耍"></property>
<property name="petName" value="大黄"></property>
</bean>
<!--有参构造方法-->
<bean id="pet" class="com.BeanTest.Pet">
<!--第一种方法:根据index参数下标设置-->
<constructor-arg index="0" value="二货"></constructor-arg>
<constructor-arg index="1" value="3"></constructor-arg>
<constructor-arg index="2" value="吃东西"></constructor-arg>
</bean>
创建BookTest对象:
List注入方法:
<property name="bookName">
<!--List注入-->
<list>
<value>红楼梦</value>
<value>水浒传</value>
<value>西游记</value>
<value>三国演义</value>
</list>
</property>
数组注入方法:
<property name="lesson">
<!--数组注入-->
<array>
<value>语文</value>
<value>数学</value>
<value>英语</value>
</array>
</property>
Map注入方法:
<property name="map">
<!--Map注入-->
<map>
<entry key="第一" value="预习名著"></entry>
<entry key="第二" value="朗读名著"></entry>
<entry key="第三" value="赏析名著"></entry>
<entry key="第四" value-ref="pet"></entry>
<entry key="第五" value-ref="pet1"></entry>
</map>
</property>
Int类型注入和Set注入:
<property name="price" value="200"></property>
<property name="stringSet">
<!--Set注入-->
<set>
<value>小明</value>
<value>小华</value>
<value>小红</value>
</set>
</property>
Properties注入:
<property name="properties">
<!--Properties注入-->
<props>
<prop key="学号">201920123</prop>
<prop key="姓名">小江</prop>
<prop key="性别">男</prop>
<prop key="年龄">23</prop>
</props>
</property>
NULL注入和List对象集合属性注入:
<!--NUll注入-->
<property name="book"><null/></property>
<!--List对象属性集合注入-->
<property name="petList">
<list>
<ref bean="pet1"></ref>
<ref bean="pet"></ref>
</list>
</property>
**
**
package com.BeanTest;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BookInjection {
@Test
public void TestInjection(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml");
BookTest bookTest = applicationContext.getBean("bookTest",BookTest.class);
System.out.println(bookTest);
}
}
1、通过构造器创建bean的实例(无参数构造法)
2、为bean的属性设置值和对于其他bean的调用(调用set方法)
3、调用bean的初始化方法
4、bean的使用对象(已经获取到对象了)
5、当bean容器关闭时,调用bean的销毁方法(需要配置销毁方法)
(声明:一下文字内容转自微信公众号狂神说!!)
当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。要在XML中将bean定义成singleton,可以这样配置:
<bean id="**" class="**" scope="singleton">
当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。在XML中将bean定义成prototype,可以这样配置:
<bean id="**" class="**" scope="prototype"/>
或者
<bean id="**" class="**" singleton="false"/>
创建Books实体类:
package com;
public class Books {
private int price;
private String bookName;
public Books(int price, String bookName) {
this.price = price;
this.bookName = bookName;
}
public Books() {
this.price = 0;
this.bookName = null;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
@Override
public String toString() {
return "Books{" +
"price=" + price +
", bookName='" + bookName + '\'' +
'}';
}
}
创建xml配置文件:(采用p命名注入和c命名注入,记得导入依赖,c 就是所谓的构造器注入!)
<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"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="books" class="com.Books" p:bookName="随风" p:price="23" scope="singleton"/>
<bean id="book" class="com.Books" c:bookName="hh" c:price="34" scope="prototype"/>
beans>
创建测试类:
import com.Books;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestBooks {
@Test
public void Test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Books books = (Books) context.getBean("books");
System.out.println(books);
}
@Test
public void Test02(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Books books = (Books) context.getBean("book");
System.out.println(books);
}
@Test
public void Test03(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Books books = (Books) context.getBean("books");
Books book = (Books) context.getBean("book");
System.out.println(books==book);
}
}
当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;即每个HTTP请求都会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:
<bean id="**" class="**" scope="request"/>
针对每次HTTP请求,Spring容器会根据loginAction bean的定义创建一个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据loginAction bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request作用域的bean实例将被销毁。
当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:
<bean id="**" class="**" scope="session"/>
针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建一个全新的userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效。与request作用域一样,可以根据需要放心的更改所创建实例的内部状态,而别的HTTP Session中根据userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化。当HTTP Session最终被废弃的时候,在该HTTP Session作用域内的bean也会被废弃掉。