目录
1. Spring简介
1. Spring框架结构
2. 下载Spring框架
3. 第一个Spring项目(Hello World)
2. IoC容器
3. 配置Bean (3种方式:XML、Java注解、Java代码)
4. 依赖注入
Spring是一款JavaEE轻量级开源框架(用于简化JavaEE企业级应用的开发)。
Spring分为
1. 狭义
Spring Framework(本篇文章介绍)
2个核心功能:Ioc、AOP。
2. 广义(以Spring Framework框架为核心的Spring技术栈)
1. Spring Framework
2. Spring MVC
3. Spring Boot(Spring团队提供的全新框架,用来简化Spring项目的搭建和开发)
以Spring为基础,提供了大量开箱即用的依赖包(自动管理依赖包中的依赖、提供了大量默认配置)使开发者更专注于业务逻辑。
4. Spring Cloud(一款基于Spring Boot实现的微服务框架)
用来开发高度可扩展、高性能、简单易懂、易部署、易维护的分布式微服务系统。
它并不是某一门技术,而是一系列微服务解决方案或框架的集合。它将市面上成熟的、经过验证的微服务框架整合后通过Spring Boot的思想进行再封装(屏蔽掉其中复杂的配置和实现原理)。
5. Spring Mobile(对Spring MVC进行了扩展,用来简化移动端Web应用的开发)
6. Spring Data
数据库访问模块。
通过它,开发人员可以使用一种相对统一的方式,来访问位于不同类型数据库中的数据。
7. Spring Security(前身为Acegi)
一款可以定制化的身份验证和访问控制框架。
8. Spring Batch(批处理)
一款专门针对企业级系统中的日常批处理任务的轻量级框架,能够帮助开发人员方便的开发出健壮、高效的批处理应用程序。
1. Spring简介
优点
1. 方便解耦,简化开发
将所有对象的创建和依赖关系的维护交给SpringIoC容器来管理。
2. 方便集成各种流行框架
Struts2、Hibernate、MyBatis等。
3. 降低JavaEE API的使用难度
对JavaEE开发中一些难用的API(如:JDBC、JavaMail、远程调用等)进行了封装。
4. 方便测试
支持JUnit4,可通过注解对Spring程序进行测试。
5. 支持AOP面向切面编程
降低通用功能(通常是一些可复用的功能,如:日志功能、事务功能、权限检查、参数检查、统计信息)和业务逻辑的耦合,减少代码的重复性。
6. 支持声明式事务处理
只需通过配置就可完成对事务的管理,而无需通过编程来完成。
在实际开发中,服务器端应用程序通常采用三层体系架构,分别为
1. 表现层(web)
Spring在表现层提供了对 Spring MVC、Struts2 等框架的整合;
2. 业务逻辑层(service)
Spring在业务逻辑层提供了管理事务和记录日志的功能;
3. 持久层(dao)
Spring在持久层还可以整合 MyBatis、Hibernate 和 JdbcTemplate 等技术,对数据库进行访问。
- Spring框架结构
说明:
1. 核心容器(CoreContainer)由4个模块组成:
1. Core核心模块(其他模块都依赖该模块)
提供了Spring框架基本的核心工具类(资源访问、类型转换、常用工具类等)。
2. Beans模块
提供了BeanFactory容器(一个工厂模式的复杂实现)实现基础IoC功能(访问配置文件、创建和管理bean、DI依赖注入等)
3. Context上下文模块(ApplicationContext接口可用于获取配置中的任何Java对象)
基于Core和Beans模块,添加了 资源绑定、数据验证、国际化、JavaEE支持、容器生命周期、事件传播等功能。
4. SpEL表达式语言模块
支持:访问和修改 属性值、数组、容器、索引器;方法调用;命名变量;算数和逻辑运算;从Spring容器获取Bean;列表投影、选择和一般的列表聚合等。
2. 数据访问/集成(DataAccess/Integration)由5个模块组成:
1. JDBC模块
提供了JDBC抽象层(对JDBC、事务等操作进行了封装)。
2. ORM模块
方便集成 对象/关系映射框架(JPA、JDO、Hibernate、MyBatis)。
3. OXM模块
方便集成 Object/XML映射(JAXB、Castor、XMLBeans、JiBX、XStream) 。
4. JMS模块(Java消息服务)
提供了一套“消息生产者、消息消费者”模板来方便使用JMS。
JMS用于在两个应用之间或分布式系统中发送消息,进行异步通信。
5. Transactions模块
支持编程和声明式事务管理。
3. Web(MVC/Remoting)由4个模块组成:
1. Web模块
提供了基本的Web开发功能(如:多文件上传功能、使用Servlet监听器的IoC容器初始化、Web应用上下文)。
2. Servlet模块
提供了Spring MVC Web框架实现(提供了基于注解的请求资源注入、更简单的数据绑定、数据验证、JSP标签等)。
3. WebSocket模块
提供了快速搭建WebSocket Server实现双向通讯的接口。
4. Portlet模块
提供了在Portlet环境中使用MVC实现类似Web-Servlet模块的功能。
4. 其他
1. AOP模块
提供了面向切面编程实现,降低通用功能和业务逻辑的耦合(提供 日志记录、权限控制、性能统计等通用功能和业务逻辑分离的技术)。
2. Aspects模块
提供与AspectJ(一个功能强大且成熟的面向切面编程AOP框架)的集成。
3. Instrumentation模块
提供了类工具的支持和类加载器的实现,可以在特定的应用服务器中使用。
4. Messaging模块
为STOMP提供了支持。
5. Test测试模块
支持JUnit、TestNG测试框架。
- 下载Spring框架
官网下载Spring框架、commons-logging-xxx.jar
目录说明:
1. docs目录
存放:Spring的API文档、开发规范。
2. libs目录
存放:开发需要的jar。
3. schema目录
存放:开发所需要的schema文件(定义了Spring相关配置文件的约束)。
libs目录下的jar说明
其中1、2、3、4分别对应Spring框架的核心容器的4个模块。
1. spring-core.jar(必须)
提供了基本的核心工具类(其它jar包的核心)。
依赖第三方jar包:commons-logging-xxx.jar。
2. spring-beans.jar(必须)
提供了基础IoC功能(提供了进行IoC/DI操作相关的所有类:访问配置文件、创建和管理bean、其他相关的类)。
3. spring-context.jar(必须)
在基础IoC功能上进行了扩展(邮件服务、任务调度、JNDI定位、EJB集成、远程访问、缓存、各种视图框架的封装等企业级功能)。提供了使用ApplicationContext时所需的全部类,JDNI所需的全部类,instrumentation组件以及校验Validation方面的相关类。
4. spring-expression.jar(必须)
提供了Spring表达式语言相关的所有类。
5. spring-aop.jar
提供了AOP特性相关的所有类。
6. spring-jdbc.jar
提供了SpringJDBC相关的所有类。
7. spring-tx.jar
提供了事务和异常处理相关的所有类(为JDBC、Hibernate、JDO、JPA等提供一致的声明式和编程式的事务管理)。
7. spring-web.jar
包含Web 应用开发时,用到Spring 框架时所需的核心类,包括自动载入Web Application Context 特性的类、Struts 与JSF 集成类、文件上传的支持类、Filter 类和大量工具辅助类。
外部依赖spring-context, Servlet API, (JSP API, JSTL, Commons FileUpload, COS)。
8. spring-webmvc.jar
包含Spring MVC 框架相关的所有类。包含国际化、标签、Theme、视图展现的FreeMarker、JasperReports、Tiles、Velocity、XSLT相关类。包括框架的Servlets,Web MVC框架,控制器和视图支持。
如果应用使用了独立的MVC 框架,则无需这个JAR 文件里的任何类。
外部依赖spring-web, (spring-support,Tiles,iText,POI)。
9. spring-aspects.jar
提供对AspectJ的支持,以便可以方便的将面向方面的功能集成进IDE中,比如Eclipse AJDT。
10. spring-context-support.jar
Spring context的扩展支持,用于MVC方面。
11. spring-instrument.jar
Spring对服务器的代理接口
12. spring-instrument-tomcat.jar
Spring对tomcat连接池的集成
13. spring-jms.jar
为简化jms api的使用而做的简单封装。
外部依赖spring-beans,spring-dao,JMS API。
14. spring-orm.jar
整合第三方的orm实现,如hibernate,ibatis,jdo以及spring 的jpa实现
15. spring-oxm.jar
Spring对于object/xml映射的支持,可以让JAVA与XML之间来回切换
16. spring-messaging.jar:
17. spring-test.jar
对JUNIT等测试框架的简单封装
19. spring-webmvc-portlet.jar
Spring MVC的增强
20. spring-websocket.jar:
- 第一个Spring项目(Hello World)
===》1. 导入依赖包
MyEclipse项目栏右击新建Java项目 | 点击项目右键 | Build Path | Config Build Path | Libraries | add External JARs | 1. 导入核心容器模块对应的4个jar(后期看需要再导入其他jar)或者 直接把spring的lib中所有的jar全部导入 ; 2. 导入commons-logging-xxx.jar
===》2. 新建HelloWorld.java文件(com.sst.cx包下)
package com.sst.cx;
public class HelloWorld {
private String message;
public void setMessage(String message){
this.message = message;
}
public void getMessage(){
System.out.println("Your Message : " + message);
}
public void init(){
System.out.println("Bean is going through init.");
}
public void destroy(){
System.out.println("Bean will destroy now.");
}
}
===》3. 新建HelloBeans.xml(src下)
定义各对象(分配唯一ID、属性赋值、依赖关系)。
<?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-3.0.xsd">
<bean id="helloWorld" class="com.sst.cx.HelloWorld">
<property name="message" value="Hello World!"/>
</bean>
</beans>
===》4. 新建Main.java
获取配置文件中的HelloWorld类实例,并调用其getMessage方法。
package com.sst.cx;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("HelloBeans.xml");
// HelloWorld obj = context.getBean("helloWorld", HelloWorld.class);
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
obj.getMessage();
}
}
说明:
1. ClassPathXmlApplicationContext类用于加载Spring配置文件,创建并初始化所有Bean对象。
2. ApplicationContext.getBean()方法用于获取Bean,返回类型为Object。
===》5. 运行
Main.java文件 右键 | Run As Java Application运行程序,控制台会输出:
Your Message : Hello World!
2. IoC容器
Spring通过IoC容器来管理(创建、初始化、依赖关系)所有Java对象(被称为SpringBean)。
1. IoC(Inversion of Control)控制反转
是一种设计思想,用来最大限度地降低耦合度。
传统Java应用中,A类中想调用B类的属性或方法时,需要在代码中通过new创建B类的对象然后才能调用其属性或方法。A称为调用者,B称为被调用者,调用者掌握着被调用者的创建控制权。
在Spring应用中,所有Java对象的创建控制权都由Ioc容器掌握。首先对各个对象及依赖关系进行配置(配置Bean的3种方式:XML配置文件、注解、Java代码,配置依赖注入的2种方式:基于构造函数、基于setter);Spring启动时,IoC容器会加载并解析这些配置文件,根据对象定义及依赖关系利用Java的反射机制创建并管理对象(被IoC容器创建并管理的对象被称为SpringBean);当需要使用某个Bean时直接从IoC容器中获取,而不是通过new方式创建。Ioc容器实现解耦的原理:对象的信息及依赖关系都是在配置文件中定义的,而不是在代码中紧密耦合,当对象发生改变后只需修改配置文件,而无需对Java代码进行修改。
原本调用者为主动的一方,需要什么资源就自己去创建,在Spring中由IoC容器掌握主动权,原本的调用者需要被动的等待IoC容器创建自己所需的对象,即所谓的控制反转(控制权反转)。
2. DI(Denpendency Injection)依赖注入
A类中有一个类型为B类的属性(A的对象依赖于B的对象),Spring的IoC容器在创建对象时会自动根据依赖关系,将依赖对象B注入到当前对象A中,即所谓的依赖注入。
IoC容器的2种实现:
1. BeanFactory容器
在org.springframework.beans.factory.BeanFactory接口中定义。BeanFactory相关的接口(BeanFactoryAware,InitializingBean,DisposableBean)向后兼容其他三方框架。
提供了IoC容器的基本功能(功能最简单的容器)。采用懒加载机制,Ioc容器在加载配置文件时并不会立即创建Java对象,只有在程序中使用到时才会创建。 移动设备或基于applet的应用的资源非常宝贵, 优先选择BeanFactory。
例:
BeanFactory factory = new ClassPathXmlApplicationContext("HelloBeans.xml");
HelloWorld obj = (HelloWorld) factory.getBean("helloWorld");
obj.getMessage();
2. ApplicationContext容器
在org.springframework.context.ApplicationContext接口(BeanFactory接口的子接口)中定义。对BeanFactory容器进行了扩展,增加了许多企业级功能(AOP、国际化、事务)。
常用的实现类:
1. FileSystemXmlApplicationContext
需提供XML文件的完整路径("/"代表项目根目录)。
2. ClassPathXmlApplicationContext
不需要提供XML文件的完整路径。
会在ClassPath下搜索XML文件(需正确配置ClassPath)。
3. WebXmlApplicationContext
在应用范围内搜索XML文件。
例:
// 创建和初始化所有对象(需提供XML文件的完整路径, /代表项目根目录)
ApplicationContext context = new FileSystemXmlApplicationContext("/src/HelloBeans.xml");
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
obj.getMessage();
// 容器销毁
// context.registerShutdownHook();
3. 配置Bean(3种方式:XML、Java注解、Java代码)
说明:
1. 当无法在类中添加注解时(如:DataSource、JdbcTemplate等第三方库中的类),使用xml方式配置。
2. 当前项目中的类使用注解方式配置更好。
3. 可一起联合使用。
- XML方式配置
根元素为beans,可包含多个子元素bean(每一个bean元素对应一个Bean对象)。
<bean id="唯一标识" class="包路径.类名"></bean>
bean元素的常用属性
1. id
指定 Bean的唯一标识符(必须以字母开始,由字母、数字、下划线组成)。
2. name
指定 Bean的名称(同一个Bean可指定多个名称,以,分隔)。
3. class
指定 Bean对应的类(Bean对应的具体实现类的完全限定名)。
4. scope
指定 Bean的作用域(5种)。
1. singleton(默认)
单例,每次获取时都是同一个实例(仅对于该容器 即该容器共享同一个实例,一个Web应用会有多个容器)。
2. prototype
每次获取时都创建新的实例。
// ---------以下只在web的ApplicationContext的上下文中有效(XmlWebApplicationContext) ,否则就会抛出一个 IllegalStateException 的异常---------
3. request
每次HTTP请求都会创建一个实例(其作用域为本次request)。
4. session
同一个会话共享同一个实例(其作用域为本次session)。
5. application
同一个Web应用共享同一个实例(其作用域为本应用application)。
6. websocket
在整个WebSocket中有效。
5. lazy-init(只在scope=singleton时有效)
延迟加载。
设置为true则首次使用时才会创建Bean实例;设置为false则容器启动时就创建Bean实例。
6. init-method
容器创建Bean时(在所有必需的属性被容器设置之后)会调用init-method属性中指定的方法(对应Bean类中创建的自定义初始化方法)。
7. destroy-method(只在scope=singleton时有效)
容器销毁Bean时(容器被销毁时会删除容器中的Bean)会调用destroy-method属性中指定的方法(对应Bean类中创建的自定义销毁方法)。
对于初始化方法和销毁非法,分为全局指定和单个类指定:
1. 全局指定:在beans元素中加 default-init-method="init" default-destroy-method="destroy"。
2. 单个类指定:在bean元素中加 init-method="init" destroy-method="destroy"。
8. parent
指定父Bean,与Java类的继承无关(子Bean和父Bean对应的实例不需要有继承关系)。子Bean可以继承父Bean的配置数据(构造方法参数值、属性值),也可以根据需要重写或添加属于自己的配置信息。
例:
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
<property name="message1" value="Hello"/>
<property name="message2" value="World"/>
</bean>
<bean id="helloIndia" class="com.sst.cx.HelloIndia" parent="helloWorld">
<property name="message1" value="Hi"/>
</bean>
9. abstract
设置为true则表示将Bean定义为抽象模版(表明这个Bean是抽象的,不能被实例化,也不能被其他Bean引用,只能在子Bean的parent中引用)。
例:
<bean id="beanTeamplate" abstract="true">
<property name="message1" value="Hello World!"/>
<property name="message2" value="Hello Second World!"/>
<property name="message3" value="Namaste India!"/>
</bean>
10. autowire(自动装配)
把Bean与Bean之间建立依赖关系的行为称为装配。
Spring容器可以在不使用<constructor-arg>和<property>的ref属性手动装配(但随着应用的不断发展,容器中包含的Bean会越来越多,Bean和Bean之间的依赖关系也越来越复杂,这就使得我们所编写的XML配置也越来越复杂繁琐,从而导致可读性差、代码极易出错、严重降低开发效率。可通过自动装配来解决)的情况下,通过bean元素的autowire自动装配属性(根据装配规则为Bean从应用上下文中查找它所依赖的Bean并建立依赖关系)来简化XML内容。仍然可以使用ref属性进行“重写”。
自动装配的局限性:不能自动装配基础数据类型;没有显式装配精确。
装配规则(5种)
1. no(默认)
不使用自动装配。
Bean的依赖关系必须通过<constructor-arg>和<property>元素的ref属性来定义。
2. byName
按属性名自动装配。
从所有IoC容器中寻找id/name和(使用自动装配bean对应实例的)属性名相同的bean,并建立依赖关系。
3. byType
按属性数据类型自动装配。
从所有IoC容器中寻找class和(使用自动装配bean对应实例的)属性类型相同的bean,并建立依赖关系(如果同时存在多个对应的bean则异常)。
4. constructor
类似于byType,按构造函数的参数类型自动装配。
从所有IoC容器中寻找class和(使用自动装配bean对应实例的)构造参数类型相同的bean,并建立依赖关系(如果不存在对应的构造函数参数类型的bean则异常)。
5. default
使用上一级元素beans中的自动装配规则(即 beans元素的default-autowire属性)。
bean元素的子元素(分别对应属性注入的2种方式)
1. constructor-arg
通过Bean实例的带参构造函数实现Bean的属性注入(一个constructor-arg元素对应一个需要注入的属性)。
name属性指定对应的构造参数名,value属性指定参数值。
index属性指定构造参数的序号(从0开始),type属性指定构造参数的类型。
2. property
通过Bean实例的setter方法实现Bean的属性注入(一个property元素对应一个需要注入的属性)。
name属性指定Bean实例相应的属性名,value属性指定属性值。
constructor-arg元素、property元素的常用属性
1. name
用于指定构造函数的参数名 或 属性名。
2. ref
用于注入 指定Bean实例(根据填入的 Bean元素的id或name)
3. value
用于注入 一个常量值。
constructor-arg元素、property元素的子元素
1. ref
用于注入 指定Bean实例(根据填入的 Bean元素的id或name)
2. value
用于注入 一个常量值。
3. list(允许重复)
用于注入 List或数组类型的属性。
4. set(不能重复)
用于注入 Set类型的属性。
5. map
用于注入 Map类型的属性。
子元素:entry(用于设置一个键值对。key属性指定字符串类型的键,ref或value子元素指定其值)
6. props元素
用于注入 键值对
7. array元素
用于注入
示例
<?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-3.0.xsd">
<!--
懒加载:lazy-init="true"
初始化方法:init-method
销毁方法:destroy-method
-->
<bean id="..." class="..." lazy-init="true" init-method="..." destroy-method="...">
</bean>
</beans>
- 注解方式配置(简化xml文件内容)
通过注解可以在不改变原有代码逻辑的情况下,在源代码中嵌入补充信息。
从Spring2.5开始,可以对类、方法、属性添加注解来实现:配置Bean,实现依赖注入(会在xml配置的注入之前执行,所以会被覆盖)、自动装配。
===》1. 首先需要在xml配置文件中,开启组件扫描功能。
<!-- 开启组件扫描功能。会扫描包下的类,从类的注解中获取Bean的定义信息(如:如果类使用了@Component注解,则将该类配置到容器中)。 -->
<context:component-scan base-package="com.sst.cx"></context:component-scan>
<!-- 开启注解功能 -->
<context:annotation-config/>
===》2. 配置Bean的注解(在类上添加如下注解,会将该类配置到IoC容器中)
1. @Component注解
将类标识为Bean。
可以作用在应用的任何层次(如:Service层、Dao层等)。
2. @Repository注解
将Dao层(数据访问层)的类标识为Bean。
3. @Service注解
将Service层(业务层)的类标识为Bean。
4. @Controller注解
将Controller层(控制层)的类标识为Bean(如:Struts2的Action、SpringMVC的Controller)。
例:@Component("helloBean")、@Repository("userDaoImpl")
5. @Scope注解
指定Bean的作用域
===》3. 实现依赖注入的注解
1. @Autowired注解(自动装配,默认使用byType自动装配规则)
可用在setter方法、非setter方法、构造函数、属性。
1. 用在setter方法上(会自动使用byType,不用设置property)
@Autowired
public void setHelloB(HelloB helloB) {
this.helloB = helloB;
}
2. 用在属性上(会自动使用byType,不用设置set方法)
@Autowired
HelloB helloB;
3. 用在构造函数上(会自动使用byType,不用设置property)
@Autowired
public HelloWorld(HelloB helloB) {
this.helloB = helloB;
}
4. 当没有匹配到时会报NoSuchBeanDefinitionException异常,可设置required属性为false来避免。
@Autowired(required=false) 设为非必须(默认是必须的)
2. @Qualifier注解(与@Autowired注解配合使用:@Autowired + @Qualifier)
当匹配到多个相同类型的bean时使用,将自动装配规则由默认的byType修改为byName。
例:
@Autowired
@Qualifier("helloB1")
private HelloB helloB;
3. @Resource注解(自动装配,默认使用byName自动装配规则)
如果指定name属性,则按byName进行装配;
如果指定type属性,则按byType进行装配;
如果都不指定,则先按byName进行装配,如果没有找到则再按byType进行装配;如果都无法匹配,则抛出NoSuchBeanDefinitionException异常。
4. @Value注解(注入普通属性值)
@Value("张三")
5. @Nullable注解(注入null)
4. 生命周期相关的注解
1. @PostConstruct注解
标识为初始化方法(指定为init-method)
2. @PreDestroy注解
标识为销毁方法(指定为destroy-method)
5. 其他
1. @Required注解
用于setter方法上。表示相应的bean属性必须进行注入,否则BeanInitializationException异常。
例:
@Required
public void setName(String name) {
this.name = name;
}
<bean id="helloWorld" class="com.sst.cx.HelloWorld">
<property name="name" value="cx"/>
</bean>
2. @Test注解
- Java代码方式配置
可以完全摆脱xml配置文件。
配置类相关的注解
1. @Configuration注解
标识该类为配置类(一个配置类等价于一个xml配置文件)。
获取容器:ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
当有多个配置类时:
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class, OtherConfig.class);
ctx.register(AdditionalConfig.class);
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
2. @Bean注解
将该类注册到IoC容器中(所修饰的方法相当于Bean的id属性,方法返回类型相当于Bean的class属性)。
获取容器中的对象:Foo foo = ctx.getBean(Foo.class);
3. @Import注解
导入其他配置类(从其他配置类中加载@Bean定义)。
例:
@Import(ConfigA.class)
@Configuration
public class AppConfig {
@Bean
public Foo foo() {
return new Foo(bar()); // 依赖注入
}
@Bean
public Bar bar() {
return new Bar();
}
@Bean(initMethod = "init", destroyMethod = "cleanup" )
public HelloB helloB(){ // HelloB类中有init、cleanup方法
return new HelloB();
}
@Bean
@Scope("prototype")
public HelloB helloB(){
return new HelloB();
}
}
Bean生命周期
主要分为
1. 实例化阶段
向容器请求一个尚未初始化的bean时 或 初始化bean时需要注入另一个尚末初始化的依赖时,容器就会调用doCreateBean()方法创建Bean并进行实例化(给属性赋值属性)。
2. 初始化阶段
1. 执行Aware接口的方法(如果Bean实现了xxxAware接口)。通过Aware类型的接口可以获取到Spring容器的一些资源。如:实现BeanNameAware接口可以获取到BeanName,实现BeanFactoryAware接口可以获取到工厂对象BeanFactory等。
2. 执行BeanPostProcessor的前置处理方法postProcessBeforelnitialization()方法(如果Bean实现了BeanPostProcessor接口),此时Bean已经创建但未初始化。
3. 执行afeterPropertiesSet()初始化方法(如果Bean实现了InitializingBean接口)
4. 执行自定义的初始化方法(如果在bean元素的init-method属性中进行了配置)。
5. 执行BeanPostProcessor的后置处理方法postProcessAfterinitialization()方法(如果Bean实现了BeanPostProcessor接口)此时Bean已经初始化。
3. 销毁阶段
1. 执行DestructionAwareBeanPostProcessor后置处理方法postProcessBeforeDestruction()方法(如果Bean实现了DestructionAwareBeanPostProcessor接口)。
2. 执行DisposableBean的destroy()方法(如果Bean实现了DisposableBean接口)。
3. 执行自定义的销毁方法(如果在bean元素的destroy-method属性中进行了配置)。
后置处理器
Spring提供了如下后置处理器
1. BeanFactoryPostProcessor
2. BeanPostProcessor
3. InitializingBean
如果bean实现了以上接口中的方法,这些方法会在bean初始化时调用,可以做一些前置、后置处理。
例(BeanPostProcessor)
===》InitHelloWorld.java
package com.sst.cx;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class InitHelloWorld implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeforeInitialization : " + beanName);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("AfterInitialization : " + beanName);
return bean;
}
}
4. 依赖注入(即给属性赋值)
分为2种:
1. 基于构造函数(通过Bean实例的带参构造函数实现Bean的属性注入)2种方式
方式1. 根据构造函数的参数名
<bean id="student" class="com.sst.cx.Student">
<constructor-arg name="id" value="2"></constructor-arg>
</bean>
方式2. 根据构造函数的参数顺序
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="2001"/>
<constructor-arg type="java.lang.String" value="Zara"/>
</bean>
或
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="2001"/>
<constructor-arg index="1" value="Zara"/>
</bean>
使用步骤:
1. 在Bean中创建一个带参构造函数(一个构造参数对应一个需要注入的属性)。
2. 在xml配置文件中使用<bean>元素对Bean进行定义,在<bean>元素内使用<constructor-arg>子元素对构造函数内的参数进行赋值(Bean的构造函数内有多少参数,就需要使用多少个 <constructor-arg> 元素)。
2. 基于setter(通过Bean实例的setter方法实现Bean的属性注入)
根据属性名
<bean id="student" class="com.sst.cx.Student">
<property name="id" value="1"></property>
<property name="grade" ref="grade"></property>
</bean>
使用步骤:
1. 在Bean中创建一个无参构造函数(若有其他带参构造函数时则需创建,若没有其他带参构造函数时则无需创建),并为所有需要注入的属性提供一个settter方法。
在Spring实例化Bean的过程中,IoC容器首先会调用默认的构造方法(无参构造方法)实例化Bean(Java对象),然后通过Java的反射机制根据属性名调用Bean的setter方法 将属性值注入到Bean中。
2. 在xml配置文件中使用<bean>元素对Bean进行定义,在<bean>元素内使用<property>子元素对各个属性进行赋值。
短命名空间注入(对上述2种方式进行简化)
1. c命名空间(构造函数方式注入的快捷实现)
需要在beans元素中引入XML约束xmlns:c="http://www.springframework.org/schema/c"
以bean属性的形式(c:普通属性="属性值" c:对象属性-ref="对象的引用")代替<constructor-arg> 元素。
2. p命名空间(setter方式注入的快捷实现)
需要在beans元素中引入XML约束xmlns:p="http://www.springframework.org/schema/p"
以bean属性的形式(p:普通属性="属性值" p:对象属性-ref="对象的引用")代替<property> 元素。
示例(基于构造函数的属性注入)
===》1. Grade.java 年级类
package com.sst.cx;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Grade {
private static final Log LOGGER = LogFactory.getLog(Grade.class);
private Integer gradeId;
private String gradeName;
public Grade(Integer gradeId, String gradeName) {
LOGGER.info("正在执行 Course 的有参构造方法,参数分别为:gradeId=" + gradeId + ",gradeName=" + gradeName);
this.gradeId = gradeId;
this.gradeName = gradeName;
}
@Override
public String toString() {
return "Grade{" +
"gradeId=" + gradeId +
", gradeName='" + gradeName + '\'' +
'}';
}
}
===》2. Student.java 学生类
package com.sst.cx;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Student {
private static final Log LOGGER = LogFactory.getLog(Student.class);
private int id;
private String name;
private Grade grade;
public Student(int id, String name, Grade grade) {
LOGGER.info("正在执行 Course 的有参构造方法,参数分别为:id=" + id + ",name=" + name + ",grade=" + grade);
this.id = id;
this.name = name;
this.grade = grade;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", grade=" + grade +
'}';
}
}
===》3. 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-3.0.xsd">
<bean id="student" class="com.sst.cx.Student">
<constructor-arg name="id" value="2"></constructor-arg>
<constructor-arg name="name" value="李四"></constructor-arg>
<constructor-arg name="grade" ref="grade"></constructor-arg>
</bean>
<bean id="grade" class="com.sst.cx.Grade">
<constructor-arg name="gradeId" value="4"></constructor-arg>
<constructor-arg name="gradeName" value="四年级"></constructor-arg>
</bean>
</beans>
===》4. 测试
package com.sst.cx;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
private static final Log LOGGER = LogFactory.getLog(MainApp.class);
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Student student = context.getBean("student");
LOGGER.info(student.toString());
}
}
示例(基于setter的属性注入)
===》1. Grade.java 年级类
package com.sst.cx;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Grade {
private static final Log LOGGER = LogFactory.getLog(Grade.class);
private Integer gradeId;
private String gradeName;
// 无参构造方法。在没有其他带参构造方法时可以省略。
public Grade() {
}
public void setGradeId(Integer gradeId) {
LOGGER.info("正在执行 Grade 类的 setGradeId() 方法…… ");
this.gradeId = gradeId;
}
public void setGradeName(String gradeName) {
LOGGER.info("正在执行 Grade 类的 setGradeName() 方法…… ");
this.gradeName = gradeName;
}
@Override
public String toString() {
return "Grade{" +
"gradeId=" + gradeId +
", gradeName='" + gradeName + '\'' +
'}';
}
}
===》2. Student.java 学生类
package com.sst.cx;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Student {
private static final Log LOGGER = LogFactory.getLog(Student.class);
private int id;
private String name;
private Grade grade;
// 无参构造方法。在没有其他带参构造方法时可以省略。
public Student() {
}
public void setId(int id) {
LOGGER.info("正在执行 Student 类的 setId() 方法…… ");
this.id = id;
}
public void setName(String name) {
LOGGER.info("正在执行 Student 类的 setName() 方法…… ");
this.name = name;
}
public void setGrade(Grade grade) {
LOGGER.info("正在执行 Student 类的 setGrade() 方法…… ");
this.grade = grade;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", grade=" + grade +
'}';
}
}
===》3. 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-3.0.xsd">
<bean id="student" class="com.sst.cx.Student">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="grade" ref="grade"></property>
</bean>
<bean id="grade" class="com.sst.cx.Grade">
<property name="gradeId" value="3"></property>
<property name="gradeName" value="三年级"></property>
</bean>
</beans>
示例(短命名空间注入)
c命名空间:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="student" class="com.sst.cx.Student" c:id="1" c:name="张三" c:grade-ref="grade" />
<bean id="grade" class="com.sst.cx.Grade" c:gradeId="3" c:gradeName="三年级" />
</beans>
p命名空间:
<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-3.0.xsd">
<bean id="student" class="com.sst.cx.Student" p:id="1" p:name="张三" p:grade-ref="grade" />
<bean id="grade" class="com.sst.cx.Grade" p:gradeId="3" p:gradeName="三年级" />
</beans>
- 注入内部Bean(属性类型为类类型)
将定义在property元素、constructor-args元素内部的bean称为内部bean。
例(HelloWorld类有一个HelloB类型属性helloB,HelloB类有个name属性)
方式1. setter方式注入(需要一个无参构造函数、一个set方法)
<bean id="helloWorld" class="com.sst.cx.HelloWorld">
<property name="helloB">
<bean class="com.sst.cx.HelloB">
<property name="name" value="张三"/>
</bean>
</property>
</bean>
方式2. 构造函数方式注入(构造函数需要一个HelloB类型的参数helloB)
<bean id="helloWorld" class="com.sst.cx.HelloWorld">
<constructor-args name="helloB">
<bean class="com.sst.cx.HelloB">
<constructor-args name="name" value="张三"/>
</bean>
</constructor-args>
</bean>
- 注入集合(属性类型为集合)
在property元素中添加如下子元素来配置集合值:
1. list元素
注入一列值(允许重复)
2. set元素
注入一列值(不能重复)
3. map元素
注入键值对(键值可以是任何类型)
4. props元素
注入键值对(键值都为字符串类型)
5. array元素
注入
注入引用(集合中的元素为类类型时)
<property name="addressSet或addressList">
<list>
<value>A</value>
<ref bean="helloBean"/>
</list>
</property>
<property name="addressMap">
<map>
<entry key="one" value="A"/>
<entry key ="two" value-ref="helloBean"/>
</map>
</property>
<property name="addressArray">
<array>
<ref bean="helloBean"/>
</array>
</property>
示例
===》1. HelloWorld.java
package com.sst.cx;
import java.util.*;
public class HelloWorld {
private List<String> addressList;
private Set<String> addressSet;
private Map<String,String> addressMap;
private Properties addressProp;
private String[] addressArray;
//
public List getAddressList() {
System.out.println("List Elements :" + addressList);
return addressList;
}
public void setAddressList(List<String> addressList) {
this.addressList = addressList;
}
public Set getAddressSet() {
System.out.println("Set Elements :" + addressSet);
return addressSet;
}
public void setAddressSet(Set<String> addressSet) {
this.addressSet = addressSet;
}
public Map getAddressMap() {
System.out.println("Map Elements :" + addressMap);
return addressMap;
}
public void setAddressMap(Map<String,String> addressMap) {
this.addressMap = addressMap;
}
public Properties getAddressProp() {
System.out.println("Property Elements :" + addressProp);
return addressProp;
}
public void setAddressProp(Properties addressProp) {
this.addressProp = addressProp;
}
public String[] getAddressArray() {
System.out.println("Array Elements :" + addressArray);
return addressArray;
}
public void setAddressArray(String[] addressArray) {
this.addressArray = addressArray;
}
}
===》2. 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-3.0.xsd">
<bean id="helloWorld" class="com.sst.cx.HelloWorld">
<property name="addressList">
<list>
<value>A</value>
<value>B</value>
<value>C</value>
<value>C</value>
</list>
</property>
<property name="addressSet">
<set>
<value>A</value>
<value>B</value>
<value>C</value>
</set>
</property>
<property name="addressMap">
<map>
<entry key="1" value="A"/>
<entry key="2" value="B"/>
<entry key="3" value="C"/>
<entry key="4" value="C"/>
</map>
</property>
<property name="addressProp">
<props>
<prop key="one">A</prop>
<prop key="two">B</prop>
<prop key="three">C</prop>
<prop key="four">C</prop>
</props>
</property>
<property name="addressArray">
<array>
<value>A</value>
<value>B</value>
<value>C</value>
<value>C</value>
</array>
</property>
</bean>
</beans>
===》3. Main.java
package com.sst.cx;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
HelloWorld helloW = (HelloWorld)context.getBean("helloWorld");
helloW.getAddressList();
helloW.getAddressSet();
helloW.getAddressMap();
helloW.getAddressProp();
}
}
- 注入其他类型
除了基础数据类型属性、类类型属性、集合外,也支持注入其他类型:Null值、特殊符号。
null值
<property name="nullValue">
<null/>
</property>
特殊符号
在XML配置文件中"<、>、"、'、&"等特殊字符是不能直接保存的,否则XML语法检查时就会报错。
解决:
方式1. 转义后保存。
1. 转义序列字符之间不能有空格;
2. 转义序列必须以“;”结束;
3. 单独出现的“&”不会被认为是转义的开始;
4. 区分大小写;
方式2. 将特殊符号包含在<![CDATA[特殊符号写在这里]]>中。
1. 不允许嵌套;
2. ]]>不能有空格或换行;
例:
<property name="num">
<![CDATA[<<12345678>>]]>
</property>