In a word:Spring是一个轻量级的控制反转(IoC-Inversion of Control)和
面向切面(AOP-Aspect Oriented Programming)的容器(框架)。
特点
(1)方便解耦,简化开发
(2)Aop 编程支持
(3)方便程序测试
(4)方便和其他框架进行整合
(5)方便进行事务操作
(6)降低 API 开发
Spring框架至今已集成了20多个模块,这些模块分布在以下模块中:
核心容器(Core Container)数据访问/集成(Data Access/Integration)层Web层AOP(Aspect Oriented Programming)模块植入(Instrumentation)模块消息传输(Messaging)测试(Test)模块
1.2 核心容器(Core Container)
Spring的核心容器是其他模块建立的基础,有Spring-core、Spring-beans、Spring-context、Spring-context-support和Spring-expression(String表达式语言)等模块组成。
Spring-core模块:提供了框架的基本组成部分,包括控制反转(Inversion of Control,IoC)和依赖注入(Dependency Injection,DI)功能。Spring-beans模块:提供了BeanFactory,是工厂模式的一个经典实现,Spring将管理对象称为Bean。它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。Spring-context模块:建立在Core和Beans模块的基础之上,提供一个框架式的对象访问方式,它以一种类似于 JNDI 注册的方式访问对象。是访问定义和配置的任何对象的媒介。ApplicationContext接口是Context模块的焦点。Spring-context-support模块:支持整合第三方库到Spring应用程序上下文,特别是用于高速缓存(EhCache、JCache)和任务调度(CommonJ、Quartz)、邮件(JavaMail)、调度(CommonJ, Quartz)、模板引擎(FreeMarker, JasperReports, Velocity)的支持。Spring-expression模块:提供了强大的表达式语言去支持运行时查询和操作对象图。这是对JSP2.1规范中规定的统一表达式语言(Unified EL)的扩展。该语言支持set和get属性值、属性分配、方法调用、访问数组、集合和索引器的内容、逻辑和算术运算、变量命名以及通过Spring的IOC容器中以名称检索对象。它还支持列表投影、选择以及常用的列表聚合。
依赖图
依赖图1.2.1
依赖图1.2.2
实例依赖图1.2.3
注:其中spring框架不知道aop是注解方式中必须加的一个依赖
1.3 Spring 配置文件--》applicationContext.xml
1.2.1 控制反转和依赖注入(IOC-DI)控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。DL
依赖注入(DI),是指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入。Spring的依赖注入对调用者和被调用者几乎没有任何要求,完全支持对POJO之间依赖关系的管理。
传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;
IOC是由专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建,程序被动接受对象,这就叫控制反转:将对象的创建权反转给(交给)Spring
在Spring中,我们可以把IOC容器与Spring容器等同于一个东西,及IOC容器=Spring容器,我们也可以把Spring容器看做配置文件xxx.xml来简单记忆
容器:一个Java 所编写的程序,可以管理对象的生命周期、对象与对象之间的依赖关系,在启动容器之后,所有的对象都可以直接取用,可以直接产生对象,或是建立对象与对象之间的依赖关系(不用编写任何程序代码)。
(注::框架:是开发程序的一部分,没有框架是必须存在的。)
IOC -- Inverse of Control, 控制反转,将对象的创建权反转给Spring!!DI -- Dependency Injection,依赖注入,在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件中!!IoC的技术实现
DI和IOC的关系: DI不能单独存在,DI需要在IOC的基础上来完成.
这样做得好处:做到了单一职责,并且提高了复用性,解耦了之后,任你如何实现,使用接口的引用调用的方法,永远不需要改变
解耦
以下是一个使用xml配置文件实现IOC的图例:
1.2.2 DI:给属性赋值
spring调用类的无参构造方法,创建对象。对象创建后给属性赋值。
给属性赋值可以使用
1)xml配置文件中的标签和属性;
2)使用注解。
DI分类 :1 set注入,也叫设值注入;
2 构造注入。
package com.bjpowernode;
import com.bjpowernode.service.SomeService;
import com.bjpowernode.service.impl.SomeServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AppMain {
public static void main(String[] args) {
// SomeService service = new SomeServiceImpl();
// service.doSome();
//1.指定spring配置文件:从类路径(classpath)之下开始的路径
String config="beans.xml";
//2.创建容器对象。 ApplicationContext 表示spring容器对象。通过ctx来获取某个java对象
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
//这是个接口 然后通过这个实现类ClassPathXmlApplicationContext的构造方法中负责读这个配置文件 当遇到bean标签后 就创建对象 从这个类路径下寻找这个内容
//3.从容器中获取指定名称的对象 使用getBean方法 //又因为是SomeService接口类型的对象所以还要转一下
SomeService service = (SomeService) ctx.getBean("someService");
//拿到这个someservice对象然后用其方法
//4.调用对象的方法,接口的方法
service.doSome();
}
}
package com.bjpowernode.service;
public interface SomeService {
void doSome();
}
package com.bjpowernode.service;
public class OtherService {
public void doOther(){
System.out.println("执行otherService的doOther()");
}
}
resources下配置文件
测试文件
package com.bjpowernode;
import com.bjpowernode.service.OtherService;
import com.bjpowernode.service.SomeService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Date;
public class Mytest {
@Test
public void test01(){
//1.先指定配置文件路径
String config="beans.xml";
//2.创建容器对象
//ApplicationContext是个接口 用他的这个ClassPathXmlApplicationContext这个实现类 从类路径中来读取加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
// SomeService service = ctx.getBean(SomeService.class);
// service.doSome();
SomeService service=(SomeService)ctx.getBean("someService");
service.doSome();
}
@Test
public void test02(){
//1.先指定配置文件路径
String config="beans.xml";
//2.创建容器对象
//ApplicationContext是个接口 用他的这个ClassPathXmlApplicationContext这个实现类 从类路径中来读取加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
// SomeService service=(SomeService)ctx.getBean("someService");
// service.doSome();
}
@Test
public void test03(){
//1.先指定配置文件路径
String config="beans.xml";
//2.创建容器对象
//ApplicationContext是个接口 用他的这个ClassPathXmlApplicationContext这个实现类 从类路径中来读取加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
// SomeService service=(SomeService)ctx.getBean("someService");
// service.doSome();
}
@Test
public void test04(){
String config="beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
//获取容器中定义对象的数量
int nums = ctx.getBeanDefinitionCount();
System.out.println("容器中定义对象的数量=="+nums);
//获取容器中定义的对象名称
String names[] = ctx.getBeanDefinitionNames();
for(String name:names){
System.out.println("容器中对象的名称=="+name);
}
// new java.util.Date();
}
// 让spring创建非自定义类的对象
// 有class就能让spring创建对象
@Test
public void test05() {
//1.先指定配置文件路径
String config = "beans.xml";
//2.创建容器对象
//ApplicationContext是个接口 用他的这个ClassPathXmlApplicationContext这个实现类 从类路径中来读取加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
Date date =(Date) ctx.getBean("mydate");
System.out.println("date=="+date);
// 从容器中拿对象
OtherService service =(OtherService) ctx.getBean("otherService");
service.doOther();
}
}
测试结果 解释 如下
解释:spring默认使用无参构造方法,创建对象 若定义了有参一定要定义无参
因为配置文件中有两个bean标签
所以创建了两个对象
//2.创建容器对象 //ApplicationContext是个接口 用他的这个ClassPathXmlApplicationContext这个实现类 从类路径中来读取加载配置文件 把对象创建出来 ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
实现类
package com.bjpowernode.service.impl;
import com.bjpowernode.service.SomeService;
public class SomeServiceImpl implements SomeService {
public SomeServiceImpl(){
System.out.println("SomeServiceImpl的无参数构造方法");
//无参构造执行了说明对象创建了 意味着spring框架默认执行的是无参构造方法
}
@Override
public void doSome(){
System.out.println("执行了业务方法doSome");
}
}
看注释无参构造执行了说明对象创建了 意味着spring框架默认执行的是无参构造方法
SomeService service=(SomeService)ctx.getBean("someService");
service.doSome();
从容器中获取指定名称的对象,使用getBean()
getBean(括号里是"引号中的是对象的名字 也是就
创建spring容器对象的时候创建的,会读取配置文件,创建文件中声明的java对象。 * 优点:获取对象速度快,因为对象已经创建好了 * 缺点:占用内存spring容器创建对象 一次创建几个? Test03
* 在创建容器对象时,会把配置文件中所有对象创建出来(spring默认规则)
获取容器中对象的信息Test04 如图
@Test
public void test04(){
String config="beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
//获取容器中定义对象的数量
int nums = ctx.getBeanDefinitionCount();
System.out.println("容器中定义对象的数量=="+nums);
//获取容器中定义的对象名称
String names[] = ctx.getBeanDefinitionNames();
for(String name:names){
System.out.println("容器中对象的名称=="+name);
}
// new java.util.Date();
}
控制台: 为什么输出前两行看实现类写了一个无参构造里sout
spring创建非自定义类的对象
// 让spring创建非自定义类的对象
// 有class就能让spring创建对象
@Test
public void test05() {
//1.先指定配置文件路径
String config = "beans.xml";
//2.创建容器对象
//ApplicationContext是个接口 用他的这个ClassPathXmlApplicationContext这个实现类 从类路径中来读取加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
Date date =(Date) ctx.getBean("mydate");
System.out.println("date=="+date);
// 从容器中拿对象
OtherService service =(OtherService) ctx.getBean("otherService");
service.doOther();
}
Spring属性赋值的分类
pojo类
因为是set注入所以只要set方法就行
package com.bjpowernode.ba01;
public class Student {
private String name;
private int age;
public Student() {
System.out.println("Student无参数构造方法");
}
public void setName(String name) {
System.out.println("setName=="+name);
this.name ="Hello"+name;
}
public void setAge(int age) {
System.out.println("setAge=="+age+"也就是先创建对象再进行set注入");
this.age = age;
}
public void setEmail(String email){
// email属性
System.out.println("setEmail==="+email);
}
public void setGender(String gender){
System.out.println("setGender=="+gender);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
配置文件
Test测试类
package com.bjpowernode.ba01;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Date;
public class MyTest01 {
@Test
public void test01(){
String config = "ba01/applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
Student student = (Student) ctx.getBean("myStudent");
System.out.println("student=="+student);
Date date = (Date) ctx.getBean("mydate");
System.out.println("date=="+date);
}
}
运行结果
解释分析
第一行是因为spring默认使用无参构造方法,创建对象
第三行是因为spring和咱们约定的是只调用set方法 而set方法里由自己决定 我在里面加了一条sout如图b
2-5行都是set注入
第六行 在测试类中进行的输出 Hello李四是我在setName()方法中this.name=name;改成了
this.name="Hello"+name;
spring创建对象自动调用set方法 set方法里面的内容加不加都可以 在set代码里面可以对赋值进行改变加东西
给属性赋值看得是set方法和有没有属性无关
名
第七行是 给非自定义类属性赋值 只要能找到该class就可以对其在配置文件中配置然后进行赋值
前三行是因为 配置文件中有三个Bean标签需要创建三个对象
给引用类型赋值
测试类
byName()自动注入
怎么实现的 按名称来进行比较来完成属性赋值
String config="applicationContext,xml"
当我们执行ApplicationContext ctx = new ClassPathXmlApplicationContext(config);时
会去识别这个配置文件
读到
然后再给两个属性赋值
byType()自动注入
怎么实现的 按类型来进行比较来完成属性赋值
java类中引用类型的数据类型和spring容器中的bean的class值是同源关系的,这样的bean赋值给引用类型。
同源关系:
1.java中引用类型的数据类型和bean的class值是一样的。
2.java中引用类型的数据类型和bean的class值是父子类关系的。
3.java中引用类型的数据类型和bean的class值是接口和实现类关系的。
语法:
简单类型属性赋值
注意:在xml配置文件中,符合条件的对象,只能有一个。
多余一个是报错的。
然后再给两个属性赋值
缺点:(引入注解的原因)一个大型项目中 应用多个配置文件 主要目的是 能够减小单一文件大小 让编写配置文件更多一点更方便
2.2 基于注解的DI基于注解的DI:使用spring提供的注解,完成java对象创建,属性赋值。
注解使用的核心步骤:
1)在源代码中加入注解,eg:Component
2)在spring的配置文件,加入组件扫描器的标签
注解是对程序代码的一个说明
1.创建对象的注解
@Component
@Respository
@Service
@Controller
2.简单类型属性赋值
@Value
3.引用类型赋值
@Autowired:Spring提供的注解,支持byName,byType
@Autowired:默认是byType
或者
@AutoWired
@Qualifier:使用byName
@Resource:来自jdk中的注解,给引用类型赋值的,默认是byName
@Resource:先使用byName,在byType
若@Resource(name="bean的名称"):只能使用byName注入
2.3IoC总结IoC:管理对象的,把对象放在容器中,创建,赋值,管理依赖关系。
IoC:通过管理对象,实现解耦合。IoC解决处理业务逻辑对象之间的解耦合关系,也就是Servlet和dao之间的解耦合。
spring作为容器管理什么对象?
1) service对象,dao对象。
2)工具类对象。
不适合交给spring的对象?
1)实体类
2)servlet,listener,filter等web中的对象。他们上tomcat创建和管理的。
代码和配置文件分离 若对象要调整只需该配置文件



