Spring是一个开源框架,它由RodJohnson创建。它是为了解决****企业应用开发****的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,****任何Java应用****都可以从Spring中受益。
目的:解决企业应用开发的复杂性
功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
范围:任何Java应用
简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的****容器框架****。(海纳百川)
spring(控制反转(IoC),依懒注入(DI),面向切面(AOP),事务管理(transitions))
*Spring的优势*
1、方便解耦,简化开发
Spring 就是一个大工厂,可以****将所有对象创建和依赖关系维护交给 Spring 管理****
2、AOP 编程的支持
Spring 供面向切面编程,可以方便的实现对程序进行****权限拦截****、运行监控等功能
3、声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无需手动编程
4、方便程序的测试
Spring 对 Junit 支持,可以通过注解方便的测试 Spring 程序
5、方便集成各种优秀框架
****Spring 不排斥各种优秀的开源框架****,其内部 供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz 等)的直接支持
6、降低 JavaEE API 的使用难度
Spring 对 JavaEE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等),都供了封装,使这些 API 应用难度大大降低
*Spring的体系结构*
如果作为一个整体,这些模块为你提供了开发企业应用所需的一切。但你不必将应用完全基于Spring框架。你可以自由地挑选适合你的应用的模块而忽略其余的模块。
就像你所看到的,所有的Spring模块都是在核心容器之上构建的。容器定义了Bean是如何创建、配置和管理的——更多的Spring细节。当你配置你的应用时,你会潜在地使用这些类。但是作为一名开发者,你最可能对影响容器所提供的服务的其它模块感兴趣。这些模块将会为你提供用于构建应用服务的框架,
1) 引入spring依赖的jar文件
Jar包下载地址:http://repo.springsource.org/libs-release-local/org/springframework/spring/
解压后:
* docs :API 和开发规范.
* libs :jar 包和源码.
* schema :约束.
Spring 开发中所需的jar 包
spring-beans-4.3.6.jar
所有应用都要用到的,它包含访问配置文件、创建和管理 bean
及进行 Inversion of Control / Dependency Injection(IoC/DI)操作相关的所有类
spring-context-4.3.6.jar
Spring 供在基础 IoC 功能上的扩展服务,此外还 供许多企业级服务的支持 , 如邮件服务、任务调度、JNDI 定位、EJB 集成、远程访问、缓存以及各种视图 层框架的封装等。
spring-core-4.3.6.jar
包含 Spring 框架基本的核心工具类,Spring 其它组件要都要使用到这个包里 的类 , 是其它组件的基本核心。
spring-expression-4.3.6.jar
Spring 表达式语言
commons-logging-1.2.jar log4j
第三方的主要用于处理日志
2、创建一个对象 提供set和get方法
public class User {
private String name;
private Integer age;
}
3、书写配置注册对象到容器
建立xml文件,建议放在src下,文件名建议applicationContext.xml
配置文件头信息 (可以在api文件中bean.html查看)
4、编写代码测试
@Test
public void testDemo1() {
//1.创建容器对象,相对于src下的路径
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.向容器“要”user对象
User u=(User) ac.getBean("user");
//3.打印user对象
System.out.println(u);
}
*配置文件解析(applicationContext.xml)*
将User对象交给spring容器管理 ,其中name任意,class为全包名
class属性:被管理对象的完整类名
name属性:给被管理的对象起个名字,根据该名称获得对象可以重复,可以使用特殊字符
id属性:与name属性一模一样名称不可重复,不能使用特殊字符
结论:尽量使用name属性
springIOC:IOC是Inversion of Control的缩写,多数书籍翻译成“控制反转”,还有些书籍翻译成为“控制反向”或者“控制倒置”。
1996年,Michael Mattson在一篇有关探讨面向对象框架的文章中,首先提出了IOC 这个概念。对于面向对象设计及编程的基本思想,前面我们已经讲了很多了,不再赘述,简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的,从而降低了解决问题的复杂度,而且可以灵活地被重用和扩展。IOC理论提出的观点大体是这样的:借助于“第三方”实现具有依 赖关系的对象之间的解耦 如下图
由于引进了中间位置的“第三方”,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合关系,齿轮之间的传动全部依靠“第三方”了, 全部对象的控制权全部上缴给“第三方”IOC容器,所以,IOC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合 在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此失去联系,这就是有人把IOC容器比喻成“粘合剂”的由来
1) ApplicationContext:
ClassPathXmlApplicationContext :加载类路径下 Spring 的配置文件.
FileSystemXmlApplicationContext :加载本地磁盘下 Spring 的配置文件.
方法一: ApplicationContext的特点
每次容器启动时就会创建容器中配置的所有对象.并提供更多功能
从类路径下加载配置文件:ClassPathXmlApplicationContext
/**
* 方法一:
在类路径下寻找配置文件来实例化容器
*/
// 使用 applicationContext 加载 spring 容器
// 如果定义成数组一次可以加载多个 spring 容器
ApplicationContext ac = new ClassPathXmlApplicationContext(new String[] {"com/baike/di/beans.xml"});
方法二:从硬盘绝对路径下加载配置文件:FileSystemXmlApplicationContext(“d:/xxx/yyy/xxx”)
* 方法二: 在文件系统路径下寻找配置文件来实例化容器
*/
ApplicationContext ac = new FileSystemXmlApplicationContext(new String[] {"D:\\workspaceSpring\\SpringBean\\src\\com\\baike\\di\\beans.xml"});
2)BeanFactory(过时):
BeanFactory 接口的特点
spring原始接口.最底层的接口。针对原始接口的实现类功能较为单一
BeanFactory接口实现类的容器.特点是每次在获得对象时才会创建对象,为了节省内存
/**
方法三:使用 BeanFactory
*/
BeanFactory ac = new XmlBeanFactory(new FileSystemResource("D:\\ workspaceSpring\\SpringBean\\src\\com\\baike\\di\\beans.xml"));
总结
BeanFactory :是在 getBean 的时候才会生成类的实例
AlicationContext 在加载 applicationContext.xml(容器启动)时候就会创建类的实例
结论:web开发中,使用applicationContext. 在资源匮乏的环境(手机)可以使用BeanFactory.
*方式一:********空参构造方式(最主要方式)*
定义一个接口和实现类
接口
public interface UserDao {
int save();
}
实现类
public class UserDaoImpl implements UserDao {
@Override
public int save() {
System.out.println("添加用户成功");
return 1;
}
}
使用接口和类,直接在 spring 容器中创建一个类,使用接口进行操作
在容器中定义
*注意:class 一定要是类,不能使用接口,因为接口不能被实例化。*
测试类
@Test
public void testNew1() {
//1.创建容器对象,相对于src下的路径
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.向容器获取userDao对象
UserDao userDao=(UserDao) ac.getBean("userDao");
//3.调用方法
userDao.save();
}
方式二:使用****静态****工厂方法实例化 ( 简单工厂模式 )
新建UserDaoFactory类,供一个静态的的方法,用来创建对象
public class UserDaoStaticFactory {
// 静态的方法
public static UserDao createUserDao(){
return new UserDaoImpl();
}
}
Spring 容器中定义
测试
@Test
public void testStaticFactory() {
//1.创建容器对象,相对于src下的路径
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.向容器获取userDao对象
UserDao userDao=(UserDao) ac.getBean("userDaoStaticFactory ");
//3.调用方法
userDao.save();
}
方式三:使用实例工厂方法实例化 ( 工厂方法模式 )
新建UserDaoFactory提供非静态的方法创建对象
public class UserDaoFactory {
// 非静态的方法
public UserDao creatUserDao() {
return new UserDaoImpl();
}
}
Spring 容器中定义
测试类
@Test
public void testFactory() {
//1.创建容器对象,相对于src下的路径
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.向容器获取userDao对象
UserDao userDao=(UserDao) ac.getBean("userDaoByFactory");
//3.调用方法
userDao.save();
}
例:
scope属性
singleton(默认值):单例对象,被标识为单例的对象在spring容器中只会存在一个实例
prototype:多例原型,被标识为多例的对象,每次再获对象对象时都会调用UserServiceImpl构造方法,每次都是新的的对象。
lazy-init 属性(只针对单例有效):
azy-init="true" :表示加载 spring 容器,将不会执行 UserServiceImpl 类的构造方法,可以理解成单例中懒加载对象
lazy-init="false" :表示只要调用加载 spring 容器的代码,就会执行 UserServiceImpl 类的构造方法
配置类:
测试:
@Test
public void testScope() {
//1.创建容器对象,相对于src下的路径
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println(ac.getBean("userDao"));
System.out.println(ac.getBean("userDao"));
System.out.println(ac.getBean("userDao"));
System.out.println(ac.getBean("userDao"));
}
配置类:
重新运行测试代码
配置一个方法作为生命周期初始化方法.spring会在对象创建之后立即调用.
init-method
配置一个方法作为生命周期的销毁方法.spring容器在关闭并销毁所有容器中的对象之前调用.
destory-method
//并在User中实现此方法
public void init() {
System.out.println("初始化");
}
public void destroy() {
System.out.println("销毁");
}
2004年,Martin Fowler探讨了同一个问题,既然IOC是控制反转,那么到底是“哪些方面的控制被反转了呢?”,经过详细地分析和论证后,他得出了答案:“获得依赖对象的过程被反转了”。控制被反转之后,获得依赖对象的过程由自身管理变为了由IOC容器主动注入。于是,他给“控制反转”取了一个更合适的名字叫做“依赖 注入(Dependency Injection)”。他的这个答案,实际上给出了实现IOC的方法:注入。所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。
所以,依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。
(前提是set注入之前该对象提供setter方法)
元素的 < property > 子元素指明了使用它们的 set 方法来注入。可以注入任 何东西,从基本类型到集合类,甚至是应用系统的 bean。
1、建立User类与Car类
public class Car {
private String name;
//get/set/toString
}
public class User {
private String name;
private int age;
//引用Car类型
private Car car;
//get/set/toString
}
2、Spring容器配置
3、测试
@Test
public void testSetter() {
//1.创建容器对象,相对于src下的路径
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.向容器“要”user对象
User user=(User) ac.getBean("user");
//3.打印user对象
System.out.println(user);
}
(提前在类中提供匹配的构造方法)
1、新建Dog类
public class Dog {
private String name;
private Integer age;
//带参构造
public Dog(String name, Integer age) {
this.name = name;
this.age = age;
}
//toString
}
2、Spring容器配置
3、测试
@Test
public void testConstructor() {
//1.创建容器对象,相对于src下的路径
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.向容器“要”Dog对象
Dog dogName=(Dog) ac.getBean("dogName");
Dog dogIndex=(Dog) ac.getBean("dogIndex");
Dog dogType=(Dog) ac.getBean("dogType");
//3.打印dog对象
System.out.println(dogName);
System.out.println(dogIndex);
System.out.println(dogType);
}
上述三个属性不必全部出现,根据情况选择即可
1、构建类CollectionBean
public class CollectionBean {
private Object[] arr;//数组类型注入
private List list;//list/set类型注入
private Map map;//map注入
private Properties prop;// Properties 类型注入
//get,set
}
2、Spring容器配置-****数组****
tom
jerry
测试
@Test
public void testArr() {
//1.创建容器对象,相对于src下的路径
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.向容器“要”Dog对象
CollectionBean cb=(CollectionBean) ac.getBean("arr");
Object[] arr = cb.getArr();
//3.打印
for (Object object : arr) {
System.out.println(object);
}
}
2、Spring容器配置-List集合
测试
@Test
public void testList() {
//1.创建容器对象,相对于src下的路径
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.向容器“要”Dog对象
CollectionBean cb=(CollectionBean) ac.getBean("list");
//3.打印
System.out.println(cb.getList());
}
2、Spring容器配置-Map集合
测试
@Test
public void testMap() {
//1.创建容器对象,相对于src下的路径
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.向容器“要”Dog对象
CollectionBean cb=(CollectionBean) ac.getBean("map");
//3.打印
System.out.println(cb.getMap());
}
2、Spring容器配置-Properties配置文件
admin
root
1
测试
@Test
public void testProperties() {
//1.创建容器对象,相对于src下的路径
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.向容器“要”Dog对象
CollectionBean cb=(CollectionBean) ac.getBean("properties");
//3.打印
System.out.println(cb.getProp());
}
在 java 代码中使用 @Autowired 或 @Resource 注解方式进行装配的前 条件是。
【1】引入context命名空间 需要在xml配置文件中配置以下信息:
【2】在配置文件中添加context:annotation-config/ 标签
这个配置隐式注册了多个对注解进行解析处理的处理器
AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
PersistenceAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProces- sor
1.1、使用注解 @autowired 标注在属性上
* @Autowired注解默认按类型进行装配
* 获取该注解标注的字段的类型---PersonDao类型
* 以该类型为条件到spring容器(beans.xml)中去查找bean的id节点的类型是 PersonDao 类型 .
* 找到以后,获取该节点对应的对象,利用反射直接为personDao变量赋值
1.2、使用注解 @autowired 标注在 set 方法上
@Autowired 注解默认按类型进行装配
* 获取 setPersonDao() 方法的参数的类型 ---PersonDao 类型
* 以该类型为条件到spring容器(beans.xml)中去查找bean的id节点的类 型是PersonDao 类型 .
* 找到以后 , 获取该节点对应的对象 , 把该对象作为实参传递给该 setPersonDao(PersonDao personDao) 的形参 .
*测试代码*
接口PersonDao
public interface PersonDao {
int save();
}
实现类PersonDaoImpl
public class PersonDaoImpl implements PersonDao {
@Override
public int save() {
System.out.println("添加person成功!");
return 1;
}
}
接口PersonService
public interface PersonService {
boolean save();
}
实现类PersonServiceImpl
public class PersonServiceImpl implements PersonService {
/**
* Autowired 标注在字段上
* @Autowired注解默认按类型进行装配
* 获取该注解标注的字段的类型---PersonDao类型
* 以该类型为条件到 spring 容器 (beans.xml)中去查找bean的id节点的类型是PersonDao类型 .
* 找到以后,获取该节点对应的对象,利用反射直接为personDao
变量赋值
*/
//@Autowired
private PersonDao personDao;
/**
* Autowired标注在setter方法上
@Autowired 注解默认按类型进行装配
* 获取 setPersonDao() 方法的参数的类型 ---PersonDao 类型
* 以该类型为条件到spring容器(beans.xml)中去查找bean的 id 节点的类型是PersonDao类型 .
* 找到以后,获取该节点对应的对象, 把该对象作为实参传递给该setPersonDao(PersonDao personDao)的形参 .
* */
@Autowired
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
@Override
public boolean save() {
System.out.println("执行PersonServiceImpl类的save方法! ");
if (personDao.save()>0) {
return true;
}
return false;
}
}
Sptring容器配置
测试类
public class App {
public static void main(String[] args) {
// 调用 Service 类
// 加载 spring 容器:
//1.创建容器对象,相对于src下的路径
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
PersonService personService =(PersonService) ac.getBean("personService");
personService.save();
}
}
2.1、使用注解 @Resource 标注在属性上
如
@Resource //没有指定name属性
private PersonDao personDao;
@Resource(name="personDao") //指定name属性
private PersonDao personDao;
\
* @Resource 注解默认按名称装配。
\* 如果没有指定 name 属性
\* 获取该注解标注的字段值---personDao
\* 以该字段值为条件到 spring 容器 (beans.xml) 中去查找 bean 的 id 节点的值是 personDao 的节点
\* 找到以后,获取该节点对应的对象, 利用反射直接为personDao变量 赋值
\* 如果没有找到.并且按照默认的名称找不到依赖对象时, @Resource 注解会回退到按类型装配
\* 获取该注解标注的字段类型 --PersonDao
* 以该类型为条件到spring容器(beans.xml)中去查找bean的节点的 类型是 PersonDao 类型的对象
* 找到以后,获取该节点对应的对象,利用反射直接为personDao变量 赋值
\* 如果指定 name 属性,只能按名称装配
\* 获取 name 属性的值 personDao
\* 以该值为条件到spring容器(beans.xml)中去查找bean的id节点 的值是 PersonDao 的对象
\* 找到以后,获取该节点对应的对象, 利用反射直接为personDao变量 赋值
\* 如果不存在该名称 , 抛出异常
2.2使用注解 @Resource 标注在 set 方法上
如
private PersonDao personDao;
@Resource(name="personDao")
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
resource 注解标注在 setter 方法上
* @Resource注解默认按名称装配。
* 如果没有指定name属性
* 获取setPersonDao()方法的属性名---personDao
* 以该属性名为条件到spring容器(beans.xml)中去查找bean的id节 点的值是 personDao 的节点
* 找到以后 , 获取该节点对应的对象 , 把该对象作为实参传递给该 setPersonDao( PersonDao personDao) 的形参
* 如果没有找到.并且按照默认的名称找不到依赖对象时,@Resource注解会回退到按类型装配
* 获取setPersonDao()方法的参数类型---PersonDao
* 以该类型为条件到spring容器(beans.xml)中去查找bean的节点的类型是 PersonDao 类型对象
* 找到以后 , 获取该节点对应的对象 , 把该对象作为实参传递给该 setPersonDao(
PersonDao personDao) 方法的形参
* 如果指定 name 属性 只能按名称装配
* 获取name属性的值
* 以该值为条件到spring容器(beans.xml)中去查找bean的id节点的值 是 PersonDao 的对象
* 找到以后 , 获取该节点对应的对象 , 把该对象作为实参传递给该 setPersonDao(
PersonDao personDao) 的形参 .
* 如果不存在该名称 , 抛出异常
*测试代码*
在刚刚的例子上,修改实现类PersonServiceImpl的注解
public class PersonServiceImpl implements PersonService {
@Resource(name="personDao")
private PersonDao personDao;
//@Resource(name="personDao")
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
@Override
public boolean save() {
System.out.println("执行PersonServiceImpl类的save方法! ");
if (personDao.save()>0) {
return true;
}
return false;
}
}
作用:在开发时对项目的每一层进行划分
前面的例子我们都是使用 XML 的 bean 定义来配置组件。在一个稍大的项目中,通常 会有上百个组件,如果这些组件采用 xml 的 bean 定义来配置,显然会增加配置文件的体积, 查找及维护起来也不太方便。
Spring3.0 为我们引入了组件自动扫 机制,它可以在类路径底下寻找标注了 @ Component、@Service、@Controller、@Repository 注解的类,并把这些类纳入进 spring 容器中管理。
它的作用和在 xml 文件中使用 bean 节点配置组件是一样的。
要使用自动扫 机制,我们需要打开以下配置信息 :
【1】引入context命名空间 需要在xml配置文件中配置以下信息:
【2】在配置文件中添加
其中 base-package 为需要扫 的包 ( 含子包 )。
注:
1、在使用组件扫 元素时,
AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor会隐式地被包括进来。也就是说,连个组件都会被自动检测并织入,所有这一切都不需要 在 XML 中 供任何 bean 配置元数据。
2、功能介绍
@Service 用于标注业务层组件.
@Controller 用于标注控制层组件(如 struts 中的 action)
.
@Repository 用于标注数据访问组件,即 DAO 组件。
@Component 泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
例如
dao层
/*
@Repository 标注在类的上面
* 相当于 spring 容器中定义:
*
* 此时如果没有为@Repository指定value属性的名称,此时就是按照类的名称 作为 spring容器中 bean节点的 id,并且首字母要小写
*
* @Repository(value="userDao")
* 相当于 spring 容器中定义:
*
*/
@Repository
public class PersonDaoImpl implements PersonDao {
}
Service层
/**
* @Service 标注在类的上面
* 相当于 spring 容器中定义:
*
* 此时如果没有为@Service指定value属性的名称,此时就是按照类的名称作 为 spring 容器中 bean 节点的 id,并且首字母要小些
*
* @Service(userService)
* 相当于 spring 容器中定义:
* bean>
*
* 再添加 @Resource(name="personDao")
* 此时表示
*
*
*
*/
@Service
public class PersonServiceImpl implements PersonService {
@Resource(name="personDao")
private PersonDao personDao;
}
*示例*
继续使用刚刚的例子进行修改
接口PersonDao
public interface PersonDao {
int save();
}
实现类PersonDaoImpl
@Repository
public class PersonDaoImpl implements PersonDao {
@Override
public int save() {
System.out.println("添加person成功!");
return 1;
}
}
接口PersonService
public interface PersonService {
boolean save();
}
实现类PersonServiceImpl
@Service("personService")
public class PersonServiceImpl implements PersonService {
@Resource
private PersonDao personDao;
@Override
public boolean save() {
System.out.println("执行PersonServiceImpl类的save方法! ");
if (personDao.save()>0) {
return true;
}
return false;
}
}
Sptring容器配置
测试类
public class App {
public static void main(String[] args) {
// 调用 Service 类
// 加载 spring 容器:
//1.创建容器对象,相对于src下的路径
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
PersonService personService =(PersonService) ac.getBean("personService");
personService.save();
}
}