概念
Spring IOC
Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些对象被称为 Spring Beans。
IOC 容器具有依赖注入功能的容器,它可以创建对象,IOC 容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。通常new一个实例,控制权由程序员控制,而”控制反转”是指new实例工作不由程序员来做而是交给Spring容器来做。
Spring的容器:
- Spring BeanFactory 容器
- Spring ApplicationContext 容器
BeanFactory
这个容器从一个 XML 文件中读取配置元数据,由这些元数据来生成一个被配置化的系统或者应用。1
2
3
4
5
6
7
8
9
10
11
12
13import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
// 注册
BeanFactory factory=new DefaultListableBeanFactory();
BeanDefinitionReader reader=new XmlBeanDefinitionReader((BeanDefinitionRegistry) factory);
reader.loadBeanDefinitions(new ClassPathResource("beans.xml"));
// getbean
ServiceBean service = (ServiceBean)factory.getBean("service");
ApplicationContext
Application Context 是BeanFactory的子接口,也被成为Spring上下文。与BeanFactory类似,但是它增加了企业所需要的功能,比如,从属性文件中解析文本信息和将事件传递给所指定的监听器。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
ApplicationContext context = new FileSystemXmlApplicationContext("Beans.xml");
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
obj.getMessage();
....
public class HelloWorld {
private String message;
public void setMessage(String message){
this.message = message;
}
public void getMessage(){
System.out.println("Your Message : " + message);
}
}
Bean
被称作 bean 的对象是构成应用程序的支柱也是由 Spring IoC 容器管理的。bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。
bean的配置需要元数据信息。包括
- 作用域:
- singleton:在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,默认值
- prototype:每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()
- request:每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
- session:同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境
- global session:一般用于Portlet应用环境,该运用域仅适用于WebApplicationContext环境
生命周期
初始化回调
1
2
3
4
5
6
7
8import org.springframework.beans.factory.InitializingBean
public class ExampleBean implements InitializingBean {
public void afterPropertiesSet() {
// do some initialization work
}
}
// 或者在xml定义
<bean id="exampleBean" class="examples.ExampleBean" init-method="afterPropertiesSet"/>销毁回调
1
2
3
4
5
6
7
8import org.springframework.beans.factory.DisposableBean
public class ExampleBean implements DisposableBean {
public void destroy() {
// do some destruction work
}
}
// 或者在xml定义
<bean id="exampleBean" class="examples.ExampleBean" destroy-method="destroy"/>
后置处理器:
BeanPostProcessor- 继承
Spring Bean 定义的继承与 Java 类的继承无关,但是继承的概念是一样的。你可以定义一个父 bean 的定义作为模板和其他子 bean 就可以从父 bean 中继承所需的配置。1
<bean id="helloIndia" class="com.tutorialspoint.HelloIndia" parent="helloWorld">
Spring 依赖注入
基于构造函数的依赖注入
当容器调用带有一组参数的类构造函数时,基于构造函数的 DI 就完成了,其中每个参数代表一个对其他类的依赖。1
2
3
4
5
6package x.y;
public class Foo {
public Foo(Bar bar, Baz baz) {
// ...
}
}
beans.xml1
2
3
4
5
6
7
8
9<beans>
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
</bean>
<bean id="bar" class="x.y.Bar"/>
<bean id="baz" class="x.y.Baz"/>
</beans>
main.java1
2
3
4
5
6
7public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Foo te = (Foo) context.getBean("foo");
te.xxxx();
}
}
基于设值函数的依赖注入
当容器调用一个无参的构造函数或一个无参的静态 factory 方法来初始化你的 bean 后,通过容器在你的 bean 上调用设值函数,基于设值函数的 DI 就完成了。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16package com.tutorialspoint;
public class TextEditor {
private SpellChecker spellChecker;
public void setSpellChecker(SpellChecker spellChecker) {
System.out.println("Inside setSpellChecker." );
this.spellChecker = spellChecker;
}
public SpellChecker getSpellChecker() {
return spellChecker;
}
public void spellCheck() {
spellChecker.checkSpelling();
}
}
beans.xml1
2
3
4
5<bean id="textEditor" class="com.tutorialspoint.TextEditor">
<property name="spellChecker" ref="spellChecker"/>
</bean>
<bean id="spellChecker" class="com.tutorialspoint.SpellChecker"></bean>
main.java1
2
3
4
5
6
7public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
TextEditor te = (TextEditor) context.getBean("textEditor");
te.spellCheck();
}
}
内部bean
Java 内部类是在其他类的范围内被定义的,同理,inner beans 是在其他 bean 的范围内定义的 bean。1
2
3
4
5<bean id="outerBean" class="...">
<property name="target">
<bean id="innerBean" class="..."/>
</property>
</bean>
注入集合
包括 Java Collection 类型 List、Set、Map 和 Properties1
2
3
4
5
6
7
8
9
10
11 <bean id="javaCollection" class="com.tutorialspoint.JavaCollection">
<!-- results in a setAddressList(java.util.List) call -->
<property name="addressList">
<list>
<value>INDIA</value>
<value>Pakistan</value>
<value>USA</value>
<value>USA</value>
</list>
</property>
</bean>
Spring Bean 的自动装配
在上面说明了通过\
也可以使用\
模式:
- no: 这是默认的设置,它意味着没有自动装配,你应该使用显式的bean引用来连线。
byName: 由属性名自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byName。
1
2
3
4
5
6<bean id="textEditor" class="com.tutorialspoint.TextEditor" autowire="byName">
<property name="name" value="Generic Text Editor" />
</bean>
<bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
</bean>byType: 由属性数据类型自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byType。
- constructor: 类似于 byType,但该类型适用于构造函数参数类型。
- autodetect: Spring首先尝试通过 constructor 使用自动装配来连接,如果它不执行,Spring 尝试通过 byType 来自动装配。
基于注解的配置
从 Spring 2.5 开始就可以使用注解来配置依赖注入。而不是采用 XML 来描述一个 bean 连线,你可以使用相关类,方法或字段声明的注解,将 bean 配置移动到组件类本身。
打开注解配置需要在bean.xml中配置1
<context:annotation-config/>
@Required
@Required 注释应用于 bean 属性的 setter 方法,它表明受影响的 bean 属性在配置时必须放在 XML 配置文件中,否则容器就会抛出一个 BeanInitializationException 异常。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import org.springframework.beans.factory.annotation.Required;
public class Student {
private Integer age;
private String name;
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
beans.xml1
2
3
4<bean id="student" class="com.tutorialspoint.Student">
<property name="name" value="Zara" />
<property name="age" value="11"/> // 如果没有写这个属性会报错
</bean>
@Autowired
@Autowired 注释对在哪里和如何完成自动连接提供了更多的细微的控制。
可以在beans.xml文件中配置autowired。当Spring遇到一个在 setter方法中使用的 @Autowired 注释,它会在方法中视图执行 byType 自动连接。1
2
3
4
5
6
7
8
9
10
11
12
13
14import org.springframework.beans.factory.annotation.Autowired;
public class TextEditor {
private SpellChecker spellChecker;
public TextEditor() {
System.out.println("Inside TextEditor constructor." );
}
public SpellChecker getSpellChecker( ){
return spellChecker;
}
public void spellCheck(){
spellChecker.checkSpelling();
}
}
beans.xml1
2
3
4
5<bean id="textEditor" class="com.tutorialspoint.TextEditor">
</bean>
<bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
</bean>
@Qualifier 注释
当你创建多个具有相同类型的 bean 时,并且想要用一个属性只为它们其中的一个进行装配,在这种情况下,你可以使用 @Qualifier 注释和 @Autowired 注释通过指定哪一个真正的 bean 将会被装配来消除混乱。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Profile {
"student1") (
private Student student;
public Profile(){
System.out.println("Inside Profile constructor." );
}
public void printAge() {
System.out.println("Age : " + student.getAge() );
}
public void printName() {
System.out.println("Name : " + student.getName() );
}
}
beans.xml1
2
3
4
5
6
7
8
9
10
11
12 <bean id="profile" class="com.tutorialspoint.Profile">
</bean>
<bean id="student1" class="com.tutorialspoint.Student">
<property name="name" value="Zara" />
<property name="age" value="11"/>
</bean>
<bean id="student2" class="com.tutorialspoint.Student">
<property name="name" value="Nuha" />
<property name="age" value="2"/>
</bean>
JSR-250 注释
- @PostConstruct: 初始化回调函数的一个替代
- @PreDestroy: 销毁回调函数的一个替代
- @Resource: 使用一个 ‘name’ 属性,该属性以一个 bean 名称的形式被注入。你可以说,它遵循 by-name 自动连接语义
1
2
3
4
5
6
7
8
9
10
11
12
13public class TextEditor {
private SpellChecker spellChecker;
"spellChecker") (name=
public void setSpellChecker( SpellChecker spellChecker ){
this.spellChecker = spellChecker;
}
public SpellChecker getSpellChecker(){
return spellChecker;
}
public void spellCheck(){
spellChecker.checkSpelling();
}
}
基于JAVA的配置
@Configuration 和 @Bean 注解
- @Configuration 的注解类表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源。
@Bean 注解告诉 Spring,一个带有 @Bean 的注解方法将返回一个对象,该对象应该被注册为在 Spring 应用程序上下文中的 bean。
一个例子:
1
2
3
4
5
6
7
8import org.springframework.context.annotation.*;
public class HelloWorldConfig {
public HelloWorld helloWorld(){
return new HelloWorld();
}
}等同于xml中
1
2
3<beans>
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld" />
</beans>带有 @Bean 注解的方法名称作为 bean 的 ID,它创建并返回实际的 bean。你的配置类可以声明多个 @Bean。
- @import 注解允许从另一个配置类中加载 @Bean 定义。
生命周期
Spring 的核心是 ApplicationContext,它负责管理 beans 的完整生命周期。当加载 beans 时,ApplicationContext 发布某些类型的事件。
由于 Spring 的事件处理是单线程的,所以如果一个事件被发布,直至并且除非所有的接收者得到的该消息,该进程被阻塞并且流程将不会继续。
Spring AOP
Spring 框架的一个关键组件是面向方面的编程(AOP)框架。
AOP中的术语
Spring JDBC
Spring JDBC 框架负责所有数据库的低层细节,从开始打开连接,准备和执行 SQL 语句,处理异常,处理事务,到最后关闭连接。
Spring 事务管理
Spring 事务抽象的关键是由 org.springframework.transaction.PlatformTransactionManager 接口定义。
Spring MVC
参考:
W3C School