1 介绍一下spring:
spring管理你的业务对象,“一站式”解决方案,并贯穿表现层springmvc、业务层及持久层spring j dbc,与其他框架无缝结合。
Spring框架是一个为Java应用程序的开发提供了综合、广泛的基础性支持的Java平台。Spring帮助开发者解决了开发中基础性的问题,使得开发人员可以专注于应用程序的开发。Spring框架本身亦是按照设计模式精心打造,这使得我们可以在开发环境中安心的集成Spring框架,不必担心Spring是如何在后台进行工作的。
Spring框架至今已集成了20多个模块。这些模块主要被分如下图所示的核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。
Spring是一个一站式的解决框架,对我们web开发当中的各个层级都有对应的解决方案。
2 spring的优缺点:
优点:高内聚低耦合
1.方便解耦,简化开发
sping就是一个大工厂,可以将所有的对象创建和依赖关系维护,交给sprong管理
2.AOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截,运行监控等功能
3.声明式事务的支持
只需要通过配置就可以完成对事务的管理,不用动手编程
4.方便程序的测试
Spring对Junit4支持,可以通过注解方便的测试Spring程序
5.方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如: Struts, Hibernate, Mybatis, Quartz 等)的直接支持
6.降低JavaEE API的使用难度
Spring对JAvaEE开发中非常难用的一些API (JDBC, javaMail,远程协调_,都提供了封装,是这些API应用难度大大降低
7.IOC和DI
大大降低程序的耦合性,促进了低耦合,简化了开发
- 缺点:
1.增加一定复杂度
2.依赖spring容器重
3. 配置文件比较多,配置比较复杂
3 Spring的架构体系
Test:测试模块,spring可以与我们的junit进行整合做测试非常方便
Core container :核心容器,就是用来装javaBean对象。
AOP:切面编程
Aspects:切面编程应用的一个模块,与我们aop共同组成spring当中的切面编程
Data Access:数据访问
Web:对数据访问的支持
Transactions:用于支持我们的事物处理。用于解决我么业务层的事物处理问题
Messaging: 消息队列
4 spring第一大特性 控制反转 IOC : 创建对象
4.1 IOC:
inversion of controller 控制反转,什么是控制反装:就是将创建对象的过程或者说创建对象的权限交给了spring框架来帮我们处理,我们再不用通过new的方式来创建Javabean对象,这个过程就叫做控制反转, 通过spring容器主动创建对象,就是通过反射来创建对象。。
4.3 IOC与DI的区别与联系
- IOC是创建我们的对象
- DI就是为我们对象中的属性赋值
- DI依赖于IOC,只有我们先创建对象,才能个属性赋值
5 spring第二大特性 DI 依赖注入: 给属性赋值
DI:dependency injection 依赖注入,就是创建对象之后,给属性赋值的过程就叫做DI,说白了就是通过配置来给属性赋值
- IOC与DI的关系:先创建对象,然后才有可能通过DI来进行赋值
- DI是属性赋值,依赖于对象的创建,也就是依赖于IOC。
5.1 第一种属性赋值: 通过set 方法进行属性赋值
属性的类型一定要匹配
<bean id = "date" class = "java.util.Date"></bean>
<bean id = "dog" class = "com.hzh.demo4.Dog">
<property name = "name" value = "金毛"></property>
<property name = "age" value = "4"></property>
<property name = "color" value = "红色"></property>
</bean>
<bean id = "PersonProperty" class="com.hzh.demo4.Person">
<property name="name" value = "张三"></property>
<property name="age" value = "4"></property>
<property name = "dog" ref = "dog"></property>
<property name = "date" ref = "date"></property>
</bean>
5.2 第二种属性赋值: 通过构造器(有参)给属性赋值
无参 有参 都给
<bean id = "tom" class = "com.hzh.demo5.Tom">
<constructor-arg name = "color" value = "蓝色"></constructor-arg>
<constructor-arg name = "name" value = "汤姆猫"></constructor-arg>
<constructor-arg name = "age" value = "12"></constructor-arg>
<constructor-arg name = "jerry" ref = "jerry"></constructor-arg>
</bean>
<bean id = "jerry" class = "com.hzh.demo5.Jerry">
<constructor-arg name = "name" value = "小老鼠"></constructor-arg>
<constructor-arg name = "age" value = "2"></constructor-arg>
</bean>
5.3 给集合属性 List 赋值
<bean id = "collectProperty" class = "com.hzh.demo6.CollectProperty">
<property name = "lists">
<list>
<value>张三</value>
<value>list</value>
<value>123</value>
<value type = "java.lang.Integer">456</value>
<value>"lisi"</value>
<!--对象的引用-->
<ref bean="tom"/>
</list>
</property>
</bean>
5.4 给集合属性 List 赋值
<bean id = "collectProperty" class = "com.hzh.demo6.CollectProperty">
<property name = "lists">
<list>
<value>张三</value>
<value>list</value>
<value>123</value>
<value type = "java.lang.Integer">456</value>
<value>"list"</value>
<ref bean="tom"/>
</list>
</property>
<property name="maps">
<map>
<entry key = "张三" value= "123"></entry>
<entry key = "list" value-ref= "jerry"></entry>
<!--字符串 = 对象-->
<entry key = "lists" value-ref= "tom"></entry>
<!--字符串 = 对象-->
<entry key-ref = "jerry" value-ref= "tom"></entry>
<!--对象 = 字符串-->
<entry key-ref = "jerry" value= "王五"></entry>
</map>
</property>
</bean>
5.5 给集合属性 set 赋值
</property>
<property name="sets">
<set>
<value>张三</value>
<value>123</value>
<value>123</value>
<ref bean="dog"/>
<ref bean="dog"/>
</set>
</property>
5.6 给集合属性Property赋值
<!--注意properties的属性赋值只能写字符串 -->
<property name="properties">
<props>
<prop key="list">34</prop>
<prop key="zhangsan">12</prop>
<prop key="中国">首都北京</prop>
</props>
</property>
6 核心容器 Core container :核心容器,就是用来装javaBean对象的容器。
6.1 获取容器的三种方式:
- 1 使用ClassPathXmlApplicationContext获取容器类,ApplicationContext 是我们容器的一个子接口
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao dao = (UserDao) context.getBean("userDao");
- 2 XmlBeanFactory来获取容器类,已过时
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
UserDao dao = (UserDao) factory.getBean("userDao");
- 3 使用FileSystemXmlApplicationContext来获取容器,需要传入spring配置文件的绝对路径
可以使用外部的配置文件
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("F:\\workspace_myProject\\springDemo\\src\\main\\resources\\applicationContext.xml");
UserDao dao = (UserDao)context.getBean("userDao");
7 Java Bean
7.1 IOC 创建Java Bean 的三种方式
在配置文件加载完成之后就会创建配置的全部的JavaBean,并且放入到容器中
注意: 在创建Java Bean对象的时候对对象进行初始化,执行初始化方法
- 1 通过无参构造的方式创建:
- 条件: 必须有无参构造
<bean id = "createBean" class="com.hzh.springbean.UserBeanFactory">
</bean>
- 2 通过静态工厂方式创建对象
- factory-method :工厂类的静态方法.必须用static修饰
- 静态方法必须有返回值
- class: 工厂类的相对路径
< !-- 通过静态工厂创建对象 -->
<bean id = "userBean2Factory" class = "com.hzh.springbean.UserBeanFactory2" factory-method="getFactory"></bean>
- 3 通过实例工厂获取javaBean
- 工厂类的方法不需要static修饰
- factory-bean: 为工厂类对象
- factory-method: 为工厂类的方法.
- 第二个class : 返回对象类的相对路径
<!-- 通过实例工厂获取javaBean -->
<!-- 创建实例工厂 -->
<bean id = "userBean3Factory" class ="com.hzh.springbean.UserBean3Factory" ></bean>
<!-- 通过已经申明的工厂来获取我们的javaBean对象 -->
<bean id = "userBean3" class = "com.hzh.springbean.UserBeanFactory2" factory-bean="userBean3Factory" factory-method="getBean2"></bean>
静态工厂和实例工厂的区别就是方法有没有静态修饰
使用默认构造可以直接获取某一个javaBean的对象
通过静态工厂和实例工厂则可以一个工厂提供不同的JavaBean对象,只需要选择相对应的工厂方法即可.
7.2 Spring Bean的作用域与作用范围
Bean的作用域范围有四种:
singleton 单列 默认 :
创建一个对象,每次调用,都使用这个对象
这种范围确保不管接受到多少个请求,每个容器中只有一个bean的实例,单例的模式由bean factory自身来维护。
prototype 多例 :
每次调用都会创建一个新的实例 ,为每一个bean请求提供一个实例。
Request:
适用于web开发当中,将我们的对象存储在request域中
Session:
适用于web开发当中,将我们的对象存储在session中
7.3 java Bean 的生命周期
可以配置init-method与destroy-method来实现bean的初始化和关闭的时候调用指定的方法
Spring Bean的生命周期简单易懂。在一个bean实例被初始化时,需要执行一系列的初始化操作以达到可用的状态。同样的,当一个bean不在被调用时需要进行相关的析构操作,并从bean容器中移除。
Spring bean factory 负责管理在spring容器中被创建的bean的生命周期。Bean的生命周期由两组回调(call back)方法组成。
初始化之后调用的回调方法。
销毁之前调用的回调方法。Spring框架提供了以下四种方式来管理bean的生命周期事件:
- InitializingBean和DisposableBean回调接口
- 针对特殊行为的其他Aware接口
- Bean配置文件中的Custom init()方法和destroy()方法
@PostConstruct和@PreDestroy注解方式
使用customInit()和 customDestroy()方法管理bean生命周期的代码样例如下:
- InitializingBean和DisposableBean回调接口
<bean id = "userDemo" class="com.hzh.User" init-method="initMethod" destroy-method="destoryMethod"></bean>
如果要销毁一个方法,则使用 ClassPathXmlApplicationContext类的对象调用 .close()即可
7.4 BeanFactory和ApplicationContext有什么区别?
①ApplicationContext 接口继承BeanFactory接口,Spring核心工厂是BeanFactory ,BeanFactory采取延迟加载,第一次getBean时才会初始化Bean, ApplicationContext是会在加载配置文件时初始化Bean。
②ApplicationContext是对BeanFactory扩展,它可以进行国际化处理、事件传递和bean自动装配以及各种不同应用层的Context实现
③从表面上看,application context如同bean factory一样具有bean定义、bean关联关系的设置,根据请求分发bean的功能。但application context在此基础上还提供了其他的功能。
- 提供了支持国际化的文本消息
- 统一的资源文件读取方式
- 已在监听器中注册的bean的事件
7.5 Spring通过配置文件和注解的方式创建javaBean对象的比较
- 自己写的java类,建议全部用注解的方式
- Jar包中的类,全部用配置文件的方式
8 spring 与 WEB的整合
8.1 Spring为什么要与我们的javaWeb整合???
我们是从spring容器中取出对象,那么我们每请求一个java Bean 对象,就要创建一个spring容器吗?,每创建一个spring容器,就要在jvm中开辟出一块空间,分配地址,这样会浪费我们的jvm资源,我们可不可以让spring容器之创建一次?
整合思路:在我们创建javaWeb容器的时候,就会创建一个ServletContext对象,并且这个对象是唯一的,单例的,直到javaWeb容器关闭的时候,才会销毁。
那么问题来了,我们可不可以监听ServletContext的启动,如果监听到ServletContext的启动,我们马上就去启动我们的spring容器,也就是说,ServletContext只启动一次,我们的spring容器也只启动一次,将spring容器启动成功之后,就把我们的spring容器放到ServletContext对象当中,以后需要使用spring容器,再不用自己去new了,直接从ServletContext当中获取即可
8.2 导入jar
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
8.3 监听ServletContext的创建
- 在WEB-INF下的web.xml中配置监听器:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
8.4 定义自己的servlet,在servlet请求中获取spring容器
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1 获取servletContext对象
ServletContext servletContext = request.getServletContext();
//2 从servletContext中取出spring容器,
WebApplicationContext attribute = (WebApplicationContext) servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
//3 获取javaBean对象
Dog bean = (Dog) attribute.getBean("dog");
System.out.println("小狗的名字: "+bean.getName());
response.getWriter().append("Served at: ").append(request.getContextPath());
}
8.5 设置访问路径,访问
如果使用tomcat插件,配置了 :
<path>/</path>
则访问时不用写项目名: http://localhost:8080/ContextSerlvet
9 spring注解的使用
9.1 导入jar包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
9.2 开启注解
<!-- 开启注解 -->
<context:annotation-config></context:annotation-config>
9.3 开启包扫描
<!-- 包扫描 -->
<context:component-scan base-package="com/hzh/demo8"></context:component-scan>
9.4 使用注解
/**
* @Value("张三"):简单类型的注入
*
* @Autowired : 复杂属性的注入,会直接去spring容器中找注入的对象,不用关心 (value = "?"),即不用考虑类的ID.
*
* @Autowired+@Qualifier(value = "cat") :无论类名上面有没有ID,(value = "?")必须有,类名有ID,?=类名ID,类名无ID,?=类名首字母小写
*
* @Resource : 可以写ID,也可以不写ID,
*
* @Resource(name = "cat"): 如果写ID,则要与我们类名的ID保持一致.
*/
@Component == @Controller == @Service ==@Repository
@Controller 用于我们的数据展现层
@Service 用于我们的业务逻辑层
@Repository 用于我们的到层
@Value 用于我们简单类型属性的赋值
10 spring与junit的整合
10.1 导入jar包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.4.RELEASE</version>
<scope>test</scope>
</dependency>
10.2 在我们的测试类上添加两个注解,并且指定我们的配置文件所在的位置
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:applicationContext-web.xml")