Spring学习总结一
以下几点:
- Spring是什么
- Spring的优点
- Spring的架构图
- Spring的应用场景
- Spring的入门案例
- 控制反转(Ioc)
- 依赖注入(DI)
- 更多依赖注入的方法
- bean的作用域
- 注解开发
1、Spring是什么
Spring 是一个开源的轻量级 Java SE( Java 标准版本)/Java EE( Java 企业版本)开发应用框架,其目的是用于简化企业级应用程序开发。在传统应用程序开发中,一个完整的应用是由一组相互协作的对象组成的。所以开发一个应用除了要开发业务逻辑之外,最多的是关注使这些对象协作来完成所需功能的同时,实现低耦合、高内聚。所以,业务逻辑开发是不可避免的。如果有个框架可以帮我们来创建对象及管理这些对象之间的依赖关系,能通过配置方式来创建对象,管理对象之间依赖关系,我们不需要通过工厂和生成器来创建及管理对象之间的依赖关系,这样我们必然会减少许多工作量,加快开发。Spring 框架问世之初主要就是来完成这个功能。
Spring 框架除了帮我们管理对象及其依赖关系,还提供像通用日志记录、性能统计、安全控制、异常处理等面向切面的能力,可以帮我们管理最头疼的数据库事务,同时,它本身提供了一套简单的 JDBC 访问实现,能与第三方数据库访问框架集成(如 Hibernate、JPA ),与各种 Java EE 技术整合(如 Java Mail、任务调度等等),提供一套自己的 web 层框架 Spring MVC 、而且还能非常简单的与第三方 web 框架集成。从这里我们可以认为 Spring 是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力,从而使我们可以更自由的选择到底使用什么技术进行开发。而且不管是 JAVA SE( C/S 架构)应用程序还是 JAVA EE( B/S 架构)应用程序都可以使用这个平台进行开发。
2、Spring的优点
Spring 能帮助我们简化应用程序开发,帮助我们创建和组装对象,为我们管理事务,简单的 MVC 框架,可以把 Spring 看作是一个超级粘合平台,能把很多技术整合在一起,形成一个整体,使系统结构更优良、性能更出众,从而加速我们程序开发,有如上优点,我们没有理由不考虑使用它。
2.1、关键概念
- 应用程序:能完成我们所需要功能的成品,比如购物网站、OA 系统。
- 框架:能完成一定功能的半成品,比如我们可以使用框架进行购物网站开发;框架做一部分功能,我们自己做一部分功能,辅助高效工作。而且框架规定了你在开发应用程序时的整体架构,提供了一些基础功能,还规定了类和对象的如何创建、如何协作等,从而简化我们的代码编写,让我们专注于业务逻辑开发。
- 非侵入式设计:从框架角度可以这样理解,无需继承框架提供的类,这种设计就可以看作是非侵入式设计,如果继承了这些框架类,就是侵入设计,如果以后想更换框架,之前写过的代码几乎无法重用,如果非侵入式设计则之前写过的代码仍然可以继续使用。
- 轻量级与重量级:轻量级是相对于重量级而言的,轻量级一般就是非入侵性的、所依赖的东西非常少、资源占用非常少、部署简单等等,其实就是比较容易使用,而重量级正好相反。
- POJO : POJO ( Plain Ordinary Java Object )简单的 Java 对象。它可以包含业务逻辑或持久化逻辑,但不担当任何特殊角色且不继承或不实现任何其它 Java 框架的类或接口。
- 容器:在日常生活中容器就是一种盛放东西的器具,从程序设计角度看就是装对象的的对象,因为存在放入、拿出等操作,所以容器还要管理对象的生命周期。
- 控制反转:即 Inversion of Control ,缩写为 IoC ,控制反转还有一个名字叫做依赖注入( Dependency Injection ),就是由容器控制程序之间的关系,而非传统实现中,由程序代码直接操控。
- Bean :一般指容器管理对象,在 Spring 中指 Spring IoC 容器管理对象。
2.2、Spring的优点
- 非常轻量级的容器:以集中的、自动化的方式进行应用程序对象创建和装配,除此之外还会负责管理对象生命周期,能组合成复杂的应用程序。Spring 容器是非侵入式的(不需要依赖任何 Spring 特定类),而且完全采用 POJOs 进行开发,使应用程序更容易测试、更容易管理。而且核心 JAR 包非常小,Spring3.0.5 不到 1 M ,而且不需要依赖任何应用服务器,可以部署在任何环境( Java SE 或 Java EE )。
- AOP: AOP 是 Aspect Oriented Programming 的缩写,意思是面向切面编程。从另一个角度来考虑程序结构以完善面向对象编程( OOP ),即可以通过在编译期间、装载期间或运行期间实现在不修改源代码的情况下给程序动态添加功能的一种技术。通俗点说就是把可重用的功能提取出来,然后将这些通用功能在合适的时候织入到应用程序中;比如安全,日志记录,这些都是通用的功能,我们可以把它们提取出来,然后在程序执行的合适地方植入这些代码并执行它们,从而完成需要的功能并复用了这些功能。
- 简单的数据库事务管理:在使用数据库的应用程序当中,自己管理数据库事务是一项很让人头疼的事,而且很容易出现错误,Spring 支持可插入的事务管理支持,而且无需 JavaEE 环境支持,通过 Spring 管理事务可以把我们从事务管理中解放出来来专注业务逻辑。
- JDBC 抽象及 ORM (对象关系映射)框架支持: Spring 使 JDBC 更加容易使用;提供 DAO(数据访问对象)支持,非常方便集成第三方 ORM 框架,比如 Hibernate 等;并且完全支持 Spring 事务和使用 Spring 提供的一致的异常体系。
- 灵活的 Web 层支持: Spring 本身提供一套非常强大的 MVC 框架,而且可以非常容易的与第三方 MVC 框架集成,比如 Struts 等。
- 简化各种技术集成:提供对 Java Mail 、任务调度、 JMX 、 JMS 、 JNDI 、 EJB 、动态语言、远程访问、 Web Service 等的集成。
3、Spring的架构图
简单来看,主要部分就是Core Container这个部分!
3.1、核心容器:包括 Core 、 Beans 、 Context 、 EL 模块
- Core 模块:封装了框架依赖的最底层部分,包括资源访问、类型转换及一些常用工具类。
- Beans 模块:提供了框架的基础部分,包括控制反转( IOC )和依赖注入( DI )。其中 BeanFactory 是容器核心,本质是“工厂设计模式”的实现,而且无需编程实现“单例设计模式”,单例完全由容器控制,而且提倡面向接口编程,而非面向实现编程;所有应用程序对象及对象间关系由框架管理,从而真正从程序逻辑中把维护对象之间的依赖关系提取出来,所有这些依赖关系都由 BeanFactory 来维护。
- Context 模块:以 Core 和 Beans 为基础,集成 Beans 模块功能并添加资源绑定、数据验证、国际化、 Java EE 支持、容器生命周期、事件传播等;核心接口是 ApplicationContext 。
- EL 模块:提供强大的表达式语言支持,支持访问和修改属性值,方法调用,支持访问及修改数组、容器和索引器,命名变量,支持算数和逻辑运算,支持从 Spring 容器获取 Bean, 它也支持列表投影、选择和一般的列表聚合等。
3.2、AOP 、 Aspects 模块:
- AOP 模块: Spring AOP 模块提供了符合 AOP Alliance 规范的面向切面的编程( aspect-oriented programming )实现,提供比如日志记录、权限控制、性能统计等通用功能和业务逻辑分离的技术,并且能动态的把这些功能添加到需要的代码中;这样各专其职,降低业务逻辑和通用功能的耦合。
- Aspects 模块:提供了对 AspectJ 的集成,AspectJ 提供了比 Spring ASP 更强大的功能。
- 数据访问/集成模块:该模块包括了 JDBC 、 ORM 、 OXM 、 JMS 和事务管理。
- 事务模块:该模块用于 Spring 管理事务,只要是 Spring 管理对象都能得到 Spring 管理事务的好处,无需在代码中进行事务控制了,而且支持编程和声明性的事务管理。
- JDBC 模块:提供了一个 JBDC 的样例模板,使用这些模板能消除传统冗长的 JDBC 编码还有必须的事务控制,而且能享受到 Spring 管理事务的好处。
- ORM 模块:提供与流行的“对象-关系”映射框架的无缝集成,包括 Hibernate 、JPA 、 MyBatis 等。而且可以使用 Spring 事务管理,无需额外控制事务。
- OXM 模块:提供了一个对 Object / XML 映射实现,将 java 对象映射成 XML 数据,或者将 XML 数据映射成 java 对象, Object / XML 映射实现包括 JAXB 、 Castor 、 XMLBeans 和 XStream 。
- JMS 模块:用于 JMS ( Java Messaging Service ),提供一套 “消息生产者、消息消费者”模板用于更加简单的使用 JMS , JMS 用于用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
- Web / Remoting 模块: Web / Remoting 模块包含了 Web 、 Web-Servlet 、 Web-Struts 、 Web-Porlet 模块。
- Web 模块:提供了基础的 web 功能。例如多文件上传、集成 IoC 容器、远程过程访问( RMI 、Hessian 、 Burlap )以及 Web Service 支持,并提供一个 RestTemplate 类来提供方便的 Restful services 访问。
- Web-Servlet 模块:提供了一个 Spring MVC Web 框架实现。Spring MVC 框架提供了基于注解的请求资源注入、更简单的数据绑定、数据验证等及一套非常易用的 JSP 标签,完全无缝与 Spring 其他技术协作。
- Web-Struts 模块:提供了与 Struts 无缝集成, Struts1.x 和 Struts2.x 都支持。
- Test 模块: Spring 支持 Junit 和 TestNG 测试框架,而且还额外提供了一些基于 Spring 的测试功能,比如在测试 Web 框架时,模拟 Http 请求的功能。
4、Spring的应用场景
Spring 可以应用到许多场景,从最简单的标准 Java SE 程序到企业级应用程序都能使用 Spring 来构建。以下介绍几个比较流行的应用场景:
- 典型 Web 应用程序应用场景。
- 远程访问应用场景。
- EJB 应用场景。
4.1、典型 Web 应用程序应用场景
4.2、远程访问应用场景
4.3、EJB 应用场景
5、Spring的入门案例
需要做的几件事情:
- 下载并导入Spring核心的jar。
- 创建一个对象。
- 配置applicationContext.xml。
- 测试类。
5.1、下载并导入Spring核心的jar
Spring官方下载地址
随便下载一个,建议下载4…以上的,3的版本好像并不支持jdk1.8。
还需要一个依赖的jar包,Spring依赖的logging下载地址
5.2、创建一个对象
package com.csa.domain;
public class User {
private String username;
private Integer age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User [username=" + username + ", age=" + age + "]";
}
}
5.3、配置applicationContext.xml
注意我是放在src下面:
<?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="user" class="com.csa.domain.User">
<!-- 依赖注入(DI) -->
<property name="username" value="hello"></property>
<property name="age" value="18"></property>
</bean>
</beans>
5.4、测试
package com.csa.app;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.csa.domain.User;
public class App {
@Test
public void app() {
// 1.加载applicationContext.xml
String xmlPath = "applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
// 2.获取user的bean --> 也叫控制反转(IoC)!
User user = (User) applicationContext.getBean("user");
System.out.println(user);
}
}
结果:
6、控制反转(IoC)
几个问题:
- 什么是控制反转。
- 控制反转容器。
- 第一个案例的哪个部分用到控制反转?
6.1、什么是控制反转
IoC 不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
其实 IoC 对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在 IoC/DI 思想中,应用程序就变成被动的了,被动的等待 IoC 容器来创建并注入它所需要的资源了。
IoC 很好的体现了面向对象设计法则之一的好莱坞法则:“别找我们,我们找你”;即由 IoC 容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。
6.2、控制反转容器
IoC 容器就是具有依赖注入(DI在下面会说明到)功能的容器,IoC 容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。 应用程序无需直接在代码中 new 相关的对象,应用程序由 IoC 容器进行组装。在 Spring 中 BeanFactory 是 IoC 容器的实际代表者。
Spring IoC 容器如何知道哪些是它管理的对象呢?
这就**需要配置文件,Spring IoC 容器通过读取配置文件中的配置元数据,通过元数据对应用中的各个对象进行实例化及装配。**一般使用基于 xml 配置文件进行配置元数据,而且 Spring 与配置文件完全解耦的,可以使用其他任何可能的方式进行配置元数据,比如注解、基于 java 文件的、基于属性文件的配置都可以。
在 Spring Ioc 容器的代表就是 org.springframework.beans 包中的 BeanFactory 接口, BeanFactory 接口提供了 IoC 容器最基本功能;而 org.springframework.context 包下的 ApplicationContext 接口扩展了 BeanFactory ,还提供了与Spring AOP 集成、国际化处理、事件传播及提供不同层次的 context 实现 (如针对 web 应用的 WebApplicationContext )。简单说, BeanFactory 提供了 IoC 容器最基本功能,而 ApplicationContext 则增加了更多支持企业级功能支持。 ApplicationContext 完全继承 BeanFactory ,因而 BeanFactory 所具有的语义也适用于 ApplicationContext。
6.3、第一个案例的哪个部分用到控制反转?
applicationContext.xml中配置了一个User的bean,说明User的管理权被applicationContext.xml给夺走。简单的说,User的获取交给Spring容器来处理。也就是说配置application其实就是配置了一个Spring,配置了Spring其实就配置了一个IoC。 IoC主要又是一种思想!真正起到作用的是我们导入的spring的bean这个jar。
上面2附图合起来就算是一个控制反转的例子!
7、依赖注入(DI)
解决下面几个问题:
- 什么是依赖注入?
- 案例中哪里用到了依赖注入?
- 注入的属性如果是一个对象,应该怎么编写xml?
7.1、什么是依赖注入?
DI—Dependency Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。 依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
理解 DI 的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:
- 谁依赖于谁:当然是某个容器管理对象依赖于 IoC 容器;“被注入对象的对象”依赖于“依赖对象”;
- 为什么需要依赖:容器管理对象需要 IoC 容器来提供对象需要的外部资源;
- 谁注入谁:很明显是 IoC 容器注入某个对象,也就是注入“依赖对象”;
- 注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
7.2、案例中哪里用到了依赖注入?
7.3、注入的属性如果是一个bean,应该怎么编写xml?
假设User多了Address属性!
Address类
package com.csa.domain;
public class Address {
private String province;
private String city;
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Address [province=" + province + ", city=" + city + "]";
}
}
修改applicationContext.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="user" class="com.csa.domain.User">
<!-- 依赖注入(DI) -->
<property name="username" value="hello"></property>
<property name="age" value="18"></property>
<!-- 注意不是value,而是ref哦 -->
<property name="address" ref="address"></property>
</bean>
<bean id="address" class="com.csa.domain.Address">
<property name="province" value="AA"></property>
<property name="city" value="BB"></property>
</bean>
</beans>
测试结果如下:
package com.csa.app;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.csa.domain.User;
public class App {
@Test
public void app() {
// 1.加载applicationContext.xml
String xmlPath = "applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
// 2.获取user的bean --> 也叫控制反转(IoC)!
User user = (User) applicationContext.getBean("user");
System.out.println(user);
}
}
8、更多依赖注入的方法
还有其他几种常见的依赖注入的方法:
- p命名空间。
- 属性注入。
- 构造函数注入。
- 集合属性的注入。
8.1、p命名空间
做下面几个步骤:
- 引入p命名空间的约束。
- 使用p命名空间。
例子:
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
<bean id="user" class="com.csa.domain.User">
<!-- 依赖注入(DI) -->
<property name="username" value="hello"></property>
<property name="age" value="18"></property>
<!-- 注意不是value,而是ref哦 -->
<property name="address" ref="address"></property>
</bean>
<!-- 注意约束上面加了一个xmlns:p的内容,并且这个时候是以"p:属性名"在bean中作为属性名的形式注入的 -->
<bean id="address" class="com.csa.domain.Address" p:province="CC" p:city="DD"></bean>
</beans>
最后测试:
package com.csa.app;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.csa.domain.User;
public class App {
@Test
public void app() {
// 1.加载applicationContext.xml
String xmlPath = "applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
// 2.获取user的bean --> 也叫控制反转(IoC)!
User user = (User) applicationContext.getBean("user");
System.out.println(user);
}
}
8.2、属性注入
<?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="user" class="com.csa.domain.User">
<!-- 依赖注入(DI) -->
<property name="username" value="hello"></property>
<property name="age" value="18"></property>
<!-- set方法注入 -->
<property name="address">
<bean class="com.csa.domain.Address">
<property name="province" value="hello"></property>
<property name="city" value="world"></property>
</bean>
</property>
</bean>
</beans>
8.3、构造函数注入
需要做下面4步:
- 修改Address类(主要是创建一个构造函数)。
- 修改User类。
- 修改struts.xml。
- 测试。
8.3.1、修改Address类
package com.csa.domain;
public class Address {
private String province;
private String city;
public Address(String province, String city) {
super();
this.province = province;
this.city = city;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Address [province=" + province + ", city=" + city + "]";
}
}
8.3.2、修改User类
package com.csa.domain;
public class User {
private String username;
private Integer age;
private Address address;
public User(String username, Integer age, Address address) {
super();
this.username = username;
this.age = age;
this.address = address;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "User [username=" + username + ", age=" + age + ", address=" + address + "]";
}
}
8.3.3、修改struts.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="user" class="com.csa.domain.User">
<!-- 第一种写法(我一般都这样玩):name指向的是属性名,value是对应的值 -->
<constructor-arg name="username" value="hello"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<!-- 这样注入一个依赖,我是有点不太适应的! -->
<constructor-arg name="address">
<bean class="com.csa.domain.Address">
<!-- 第二种写法(我一般不这样玩!):index按照全部参数情况下的第几个参数 -->
<!-- 按这个例子来说,第一个String是"省份" -->
<constructor-arg index="0" value="hello"></constructor-arg>
<!-- 第二个是"城市" -->
<constructor-arg index="1" value="world"></constructor-arg>
</bean>
</constructor-arg>
</bean>
</beans>
8.3.4、测试
package com.csa.app;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.csa.domain.User;
public class App {
@Test
public void app() {
// 1.加载applicationContext.xml
String xmlPath = "applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
// 2.获取user的bean --> 也叫控制反转(IoC)!
User user = (User) applicationContext.getBean("user");
System.out.println(user);
}
}
测试结果:
8.4、集合属性注入
做以下几个步骤:
- 编写一个CollectionTest类。
- 编写struts.xml(自己屡屡最后控制台出现的结果)。
- 测试结果。
8.4.1、编写CollectionTest类
package com.csa.domain;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class CollectionTest {
private Object[] arr;
private List<Object> list;
private Set<Object> set;
private Map<String,Object> map;
private Properties pros;
public Object[] getArr() {
return arr;
}
public void setArr(Object[] arr) {
this.arr = arr;
}
public List<Object> getList() {
return list;
}
public void setList(List<Object> list) {
this.list = list;
}
public Set<Object> getSet() {
return set;
}
public void setSet(Set<Object> set) {
this.set = set;
}
public Map<String, Object> getMap() {
return map;
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
public Properties getPros() {
return pros;
}
public void setPros(Properties pros) {
this.pros = pros;
}
@Override
public String toString() {
return "CollectionTest [\r\narr=" + Arrays.toString(arr) + ", \r\nlist=" + list +
",\r\nset=" + set + ",\r\nmap=" + map
+ ",\r\npros=" + pros + "]";
}
}
8.4.2、编写struts.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="user" class="com.csa.domain.User">
<!-- 第一种写法:name指向的是属性名,value是对应的值 -->
<constructor-arg name="username" value="hello"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="address">
<bean class="com.csa.domain.Address">
<!-- 第二种写法:index按照全部参数情况下的第几个参数 -->
<!-- 按这个例子来说,第一个String是"省份" -->
<constructor-arg index="0" value="hello"></constructor-arg>
<!-- 第二个是城市 -->
<constructor-arg index="1" value="world"></constructor-arg>
</bean>
</constructor-arg>
</bean>
<bean id="address" class="com.csa.domain.Address">
<constructor-arg index="0" value="hello"></constructor-arg>
<constructor-arg index="1" value="spring"></constructor-arg>
</bean>
<bean id="collectionBean" class="com.csa.domain.CollectionTest">
<property name="arr">
<array>
<value>1</value>
<ref bean="user"/>
<bean class="com.csa.domain.Address">
<constructor-arg index="0" value="spring"></constructor-arg>
<constructor-arg index="1" value="arr"></constructor-arg>
</bean>
</array>
</property>
<property name="list">
<list>
<value>2</value>
<ref bean="user"/>
<bean class="com.csa.domain.Address">
<constructor-arg index="0" value="spring"></constructor-arg>
<constructor-arg index="1" value="list"></constructor-arg>
</bean>
</list>
</property>
<property name="set">
<set>
<value>3</value>
<ref bean="address"/>
<bean class="com.csa.domain.Address">
<constructor-arg index="0" value="spring"></constructor-arg>
<constructor-arg index="1" value="set"></constructor-arg>
</bean>
</set>
</property>
<property name="map">
<map>
<entry key="1" value="4"></entry>
<entry key="2" value-ref="address"></entry>
<entry key="3">
<bean class="com.csa.domain.Address">
<constructor-arg index="0" value="spring"></constructor-arg>
<constructor-arg index="1" value="set"></constructor-arg>
</bean>
</entry>
</map>
</property>
<!-- Properties 类型类似于Map,但是Properties只能是字符串-->
<property name="pros">
<props>
<prop key="1">1</prop>
<prop key="2">2</prop>
<prop key="3">3</prop>
</props>
</property>
</bean>
</beans>
8.4.3、测试
package com.csa.app;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.csa.domain.User;
public class App {
@Test
public void app() {
// 1.加载applicationContext.xml
String xmlPath = "applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
// 2.获取user的bean --> 也叫控制反转(IoC)!
CollectionTest collection = (CollectionTest) applicationContext.getBean("collectionBean");
System.out.println(collection);
}
}
测试结果:
9、bean的作用域
使用方法就是:<bean name="bean名字" class="包名.类名" scope="作用域"></bean>。
在 Spring 中,支持以下5 种类型的作用域:
- singleton — 单例模式,由 IOC 容器返回一个唯一的 bean 实例。
- prototype — 原型模式,被请求时,每次返回一个新的 bean 实例。
- request — 每个 HTTP Request 请求返回一个唯一的 Bean 实例。
- session — 每个 HTTP Session 返回一个唯一的 Bean 实例。
- globalSession — Http Session 全局 Bean 实例。
注:大多数情况下,你可能只需要处理 Spring 的核心作用域 — 单例模式( singleton )和原型模式( prototype ),默认情况下,作用域是单例模式。
10、注解开发
注解开发需要做下面几个步骤:
- 在applicationContext.xml中开启注解扫描器。
- 在交给spring控制的bean上面写注解。
10.1、在applicationContext.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 第一种:太麻烦 -->
<context:component-scan base-package="com.csa.domain,com.csa.dao,com.csa.service,com.csa.controller"></context:component-scan>
<!-- 第二种:常用 -->
<!-- <context:component-scan base-package="com.csa"></context:component-scan> -->
</beans>
10.2、在交给spring控制的bean上面写注解
需要写的类,还需要注意,每个类不能允许有构造并且基本类型需要编写get/set方法:
- Address类。
- User类。
- UserDao类。
- UserService类。
- UserController类。
10.2.1、Address类
package com.csa.domain;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//等价于<bean name="address" class="com.csa.domain.Address"></bean>
@Component(value="address")
public class Address {
// 等价于<property name="province" value="hello"></property>
@Value(value="hello")
private String province;
// 等价于<property name="city" value="spring"></property>
@Value(value="spring")
private String city;
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Address [province=" + province + ", city=" + city + "]";
}
}
10.2.2、User类
package com.csa.domain;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
// 等价于<bean name="user" class="com.csa.domain.User"></bean>
@Component(value="user")
public class User {
// 等价于<property name="username" value="小A"></property>
@Value(value="小A")
private String username;
// 等价于<property name="age" value="18"></property>
@Value(value="18")
private Integer age;
// 等价于<property name="age" value="18"></property>
@Autowired
@Qualifier(value="address")
private Address address;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "User [username=" + username + ", age=" + age + ", \r\n\taddress=" + address + "]";
}
}
10.2.3、UserDao类
package com.csa.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import com.csa.domain.User;
// 等同于<bean name="userDao" class="com.csa.dao.UserDao"></bean>
@Repository(value="userDao")
public class UserDao {
// 这个相当于获取一个name为user的bean
@Autowired
// 不写,默认取user,写了更清晰
@Qualifier(value="user")
private User user;
public void printUser() {
System.out.println(user);
}
}
10.2.4、UserService类
package com.csa.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.csa.dao.UserDao;
//等价于<bean name="userService" class="com.csa.service.UserService"></bean>
@Service(value="userService")
public class UserService {
@Autowired
private UserDao userDao;
public void printUser() {
userDao.printUser();
}
}
10.2.5、UserController类
package com.csa.controller;
import javax.annotation.Resource;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.csa.service.UserService;
// 等价于<bean name="userController" class="com.csa.controller.UserController" scope="singleton"></bean>
@Controller(value="userController")
@Scope(value="singleton")
public class UserController {
// 第一种方式:
// 这个相当于获取一个name为userService的bean
// @Autowired
// @Qualifier(value="userService")
// 第二种方式:
// @Resource(name="userService")
// 第三种方式:不写name,则name的默认"类名首字母小写"
@Resource
private UserService userService;
public void printUser() {
userService.printUser();
}
}
10.2.6、测试
package com.csa.app;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.csa.controller.UserController;
public class App {
@Test
public void app() {
// 1.加载applicationContext.xml
String xmlPath = "applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
UserController userController = (UserController) applicationContext.getBean("userController");
userController.printUser();
}
}
测试结果: