JAVA反射机制是在运行状态中, 对于任意一个类, 都能够知道这个类的所有属性和方法; 对于任意一个对象, 都能够调用它的任意一个方法和属性; 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制.
主要作用有三:
用处如下:
执行完以下代码int [ ] x = new int[10];后. 以下哪项说明是正确的( A )
A.x[9]为0
B.x[9]未定义
C.x[10]为0
D.x[0]为空
下面哪个语句(初始化数组)是不正确的:( B )
A: int x[] = {1,2,3};
B: int x[3] = {1,2,3};
C: int[] x = {1,2,3};
D: int x[] = new int[]{1,2,3};
给出下面代码:
public class Person{
static int arr[] = new int[10];
public static void main(String a[])
{
System.out.println(arr[1]);
}
}
那个语句是正确的? ( C )
A. 编译时将产生错误;
B. 编译时正确. 运行时将产生错误;
C . 输出零;
D. 输出空。
下面哪条语句定义了5个元素的数组( A )
A. int [] a={22,23,24,25,12};
B. int a []=new int(5);
C. int [5] array;
D. int [] arr;
下面表达式中. 用来访问数组中第一个值的是( C )
A. intArray[1]
B. intArray.1
C.intArray[0]
D. intArray.0
从同步性来看. ArrayList和LinkedList是不同步的. 而Vector是的。所以线程安全的话. 可以使用ArrayList或LinkedList. 可以节省为同步而耗费的开销。但在多线程下. 有时候就不得不使用Vector了。当然. 也可以通过一些办法包装ArrayList. LinkedList. 使我们也达到同步. 但效率可能会有所降低。
从内部实现机制来讲ArrayList和Vector都是使用Object的数组形式来存储的。当你向这两种类型中增加元素的时候. 如果元素的数目超出了内部数组目前的长度它们都需要扩展内部数组的长度. Vector缺省情况下自动增长原来一倍的数组长度. ArrayList是原来的50%. 所以最后你获得的这个集合所占的空间总是比你实际需要的要大。如果你要在集合中保存大量的数据. 那么使用Vector有一些优势. 因为你可以通过设置集合的初始化大小来避免不必要的资源开销。
ArrayList和Vector中. 从指定的位置(用index)检索一个对象. 或在集合的末尾插入. 删除一个对象的时间是一样的. 可表示为O(1)。但是. 如果在集合的其他位置增加或者删除元素那么花费的时间会呈线性增长O(n-i). 其中n代表集合中元素的个数. i代表元素增加或移除元素的索引位置. 因为在进行上述操作的时候集合中第i和第i个元素之后的所有元素都要执行(n-i)个对象的位移操作。LinkedList底层是由双向循环链表实现的. LinkedList在插入. 删除集合中任何位置的元素所花费的时间都是一样的O(1). 但它在索引一个元素的时候比较慢. 为O(i). 其中i是索引的位置. 如果只是查找特定位置的元素或只在集合的末端增加. 移除元素. 那么使用Vector或ArrayList都可以。如果是对其它指定位置的插入. 删除操作. 最好选择LinkedList。
HashTable线程安全则是依靠方法简单粗暴的sychronized修饰. HashMap则没有相关的线程安全问题考虑。。
在以前的版本貌似ConcurrentHashMap引入了一个“分段锁”的概念. 具体可以理解为把一个大的Map拆分成N个小的HashTable. 根据key.hashCode()来决定把key放到哪个HashTable中。在ConcurrentHashMap中. 就是把Map分成了N个Segment. put和get的时候. 都是现根据key.hashCode()算出放到哪个Segment中。
通过把整个Map分为N个Segment(类似HashTable). 可以提供相同的线程安全. 但是效率提升N倍。
Collection是一个接口. 它是Set. List等容器的父接口;Collections是一个工具类. 提供了一系列的静态方法来辅助容器操作. 这些方法包括对容器的搜索. 排序. 线程安全化等等。
Collection 是对象集合. Collection 有两个子接口 List 和 Set
List 可以通过下标 (1,2…) 来取得值. 值可以重复
而 Set 只能通过游标来取值. 并且值是不能重复的
ArrayList . Vector . LinkedList 是 List 的实现类
ArrayList 是线程不安全的. Vector 是线程安全的. 这两个类底层都是由数组实现的
LinkedList 是线程不安全的. 底层是由链表实现的
Map 是键值对集合
HashTable 和 HashMap 是 Map 的实现类
HashTable 是线程安全的. 不能存储 null 值
HashMap 不是线程安全的. 可以存储 null 值
Stack类:继承自Vector. 实现一个后进先出的栈。提供了几个基本方法. push. pop. peak. empty. search等。
Queue接口:提供了几个基本方法. offer. poll. peek等。已知实现类有LinkedList. PriorityQueue等。
ArrayList底层实际是采用数组实现的(并且该数组的类型是Object类型的)
如果jdk6,采用Array.copyOf()方法来生成一个新的数组. 如果是jdk5. 采用的是System.arraycopy()方法(当添加的数据量大于数组的长度的时候)
List list = new ArrayList()时. 底层会生成一个长度为10的数组来存放对象
ArrayList. Vector底部都是采用数组实现的
对于ArrayList. 方法都不是同步的. 对于Vector. 大部分public方法都是同步的
LinkedList采用双向循环列表
对于ArrayList. 查询速度很快. 增加和删除(非最后一个节点)操作非常慢(本质上由数组的特性决定的)
对于LinkedList. 查询速度非常慢. 增加和删除操作非常快(本质上是由双向循环列表决定的)
Spring是一个轻量级的IoC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架. 目的是用于简化企业应用程序的开发. 它使得开发者只需要关心业务需求。常见的配置方式有三种:基于XML的配置、基于注解的配置、基于Java的配置。
主要由以下几个模块组成:
Spring Core:核心类库. 提供IOC服务;
Spring Context:提供框架式的Bean访问方式. 以及企业级功能(JNDI、定时任务等);
Spring AOP:AOP服务;
Spring DAO:对JDBC的抽象. 简化了数据访问异常的处理;
Spring ORM:对现有的ORM框架的支持;
Spring Web:提供了基本的面向Web的综合特性. 例如多方文件上传;
Spring MVC:提供面向Web应用的Model-View-Controller实现。
Spring5框架图
Spring5 系统架构-详解
(1)AOP
AOP思想的实现一般都是基于代理模式 . 在JAVA中一般采用JDK动态代理模式. 但是我们都知道. JDK动态代理模式只能代理接口而不能代理类。因此. Spring AOP 会这样子来进行切换. 因为Spring AOP 同时支持 CGLIB、ASPECTJ、JDK动态代理。
AspectJ是一个AOP框架. 它能够对java代码进行AOP编译(一般在编译期进行). 让java代码具有AspectJ的AOP功能(当然需要特殊的编译器). 可以这样说AspectJ是目前实现AOP框架中最成熟. 功能最丰富的语言. 更幸运的是. AspectJ与java程序完全兼容. 几乎是无缝关联. 因此对于有java编程基础的工程师. 上手和使用都非常容易。
Spring注意到AspectJ在AOP的实现方式上依赖于特殊编译器(ajc编译器). 因此Spring很机智回避了这点. 转向采用动态代理技术的实现原理来构建Spring AOP的内部机制(动态织入). 这是与AspectJ(静态织入)最根本的区别。
(2)IOC
IOC是Inversion of Control的缩写. 多数书籍翻译成“控制反转”. 还有些书籍翻译成为“控制反向”或者“控制倒置”。
IOC解耦过程
(1)切面(Aspect):被抽取的公共模块. 可能会横切多个对象。 在Spring AOP中. 切面可以使用通用类(基于模式的风格) 或者在普通类中以 @AspectJ 注解来实现。
(2)连接点(Join point):指方法. 在Spring AOP中. 一个连接点 总是 代表一个方法的执行。
(3)通知(Advice):在切面的某个特定的连接点(Join point)上执行的动作。通知有各种类型. 其中包括“around”、“before”和“after”等通知。许多AOP框架. 包括Spring. 都是以拦截器做通知模型. 并维护一个以连接点为中心的拦截器链。
(4)切入点(Pointcut):切入点是指 我们要对哪些Join point进行拦截的定义。通过切入点表达式. 指定拦截的方法. 比如指定拦截add、search。
(5)引入(Introduction):(也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如. 你可以使用一个引入来使bean实现 IsModified 接口. 以便简化缓存机制。
(6)目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做 被通知(adviced) 对象。 既然Spring AOP是通过运行时代理实现的. 这个对象永远是一个 被代理(proxied) 对象。
(7)织入(Weaving):指把增强应用到目标对象来创建新的代理对象的过程。Spring是在运行时完成织入。
切入点(pointcut)和连接点(join point)匹配的概念是AOP的关键. 这使得AOP不同于其它仅仅提供拦截功能的旧技术。 切入点使得定位通知(advice)可独立于OO层次。 例如. 一个提供声明式事务管理的around通知可以被应用到一组横跨多个对象中的方法上(例如服务层的所有业务操作)。
(1)前置通知(Before advice):在某连接点(join point)之前执行的通知. 但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
(2)返回后通知(After returning advice):在某连接点(join point)正常完成后执行的通知:例如. 一个方法没有抛出任何异常. 正常返回。
(3)抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。
(4)后通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
(5)环绕通知(Around Advice):包围一个连接点(join point)的通知. 如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。 环绕通知是最常用的一种通知类型。大部分基于拦截的AOP框架. 例如Nanning和JBoss4. 都只提供环绕通知。
同一个aspect. 不同advice的执行顺序:
①没有异常情况下的执行顺序:
around before advice
before advice
target method 执行
around after advice
after advice
afterReturning
②有异常情况下的执行顺序:
around before advice
before advice
target method 执行
around after advice
after advice
afterThrowing:异常发生
java.lang.RuntimeException: 异常发生
propagation(传播行为)
spring事务的传播行为有7种。
1)PlatformTransactionManager:事务管理器–主要用于平台相关事务的管理
主要有三个方法:
2)TransactionDefinition:事务定义信息–用来定义事务相关的属性. 给事务管理器PlatformTransactionManager使用
这个接口有下面四个主要方法:
事务管理器能够根据这个返回值进行优化. 这些事务的配置信息. 都可以通过配置文件进行配置。
3)TransactionStatus:事务具体运行状态–事务管理过程中. 每个时间点事务的状态信息。
例如它的几个方法:
Spring事务的本质其实就是数据库对事务的支持. 没有数据库的事务支持. spring是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。
(1)Spring事务的种类:
spring支持编程式事务管理和声明式事务管理两种方式:
①编程式事务管理使用TransactionTemplate。
②声明式事务管理建立在AOP之上的。其本质是通过AOP功能. 对方法前后进行拦截. 将事务处理的功能编织到拦截的方法中. 也就是在目标方法开始之前加入一个事务. 在执行完目标方法之后根据执行情况提交或者回滚事务。
声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码. 只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式. 便可以将事务规则应用到业务逻辑中。
声明式事务管理要优于编程式事务管理. 这正是spring倡导的非侵入式的开发方式. 使业务代码不受污染. 只要加上注解就可以获得完全的事务支持。唯一不足地方是. 最细粒度只能作用到方法级别. 无法做到像编程式事务那样可以作用到代码块级别。
(2)spring的事务传播行为:
spring事务的传播行为说的是. 当多个事务同时存在的时候. spring如何处理这些事务的行为。
① PROPAGATION_REQUIRED:如果当前没有事务. 就创建一个新事务. 如果当前存在事务. 就加入该事务. 该设置是最常用的设置。
② PROPAGATION_SUPPORTS:支持当前事务. 如果当前存在事务. 就加入该事务. 如果当前不存在事务. 就以非事务执行。‘
③ PROPAGATION_MANDATORY:支持当前事务. 如果当前存在事务. 就加入该事务. 如果当前不存在事务. 就抛出异常。
④ PROPAGATION_REQUIRES_NEW:创建新事务. 无论当前存不存在事务. 都创建新事务。
⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作. 如果当前存在事务. 就把当前事务挂起。
⑥ PROPAGATION_NEVER:以非事务方式执行. 如果当前存在事务. 则抛出异常。
⑦ PROPAGATION_NESTED:如果当前存在事务. 则在嵌套事务内执行。如果当前没有事务. 则按REQUIRED属性执行。
(3)Spring中的隔离级别:
① ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别. 使用数据库默认的事务隔离级别。
② ISOLATION_READ_UNCOMMITTED:读未提交. 允许另外一个事务可以看到这个事务未提交的数据。
③ ISOLATION_READ_COMMITTED:读已提交. 保证一个事务修改的数据提交后才能被另一事务读取. 而且能看到该事务对已有记录的更新。
④ ISOLATION_REPEATABLE_READ:可重复读. 保证一个事务修改的数据提交后才能被另一事务读取. 但是不能看到该事务对已有记录的更新。
⑤ ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据库所做的更新。
BeanFactory和ApplicationContext是Spring的两大核心接口. 都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
1、BeanFactory:是Spring里面最底层的接口. 包含了各种Bean的定义. 读取bean配置文档. 管理bean的加载、实例化. 控制bean的生命周期. 维护bean之间的依赖关系。ApplicationContext接口作为BeanFactory的派生. 除了提供BeanFactory所具有的功能外. 还提供了更完整的框架功能:
2、BeanFactroy采用的是延迟加载形式来注入Bean的. 即只有在使用到某个Bean时(调用getBean()). 才对该Bean进行加载实例化。这样. 我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入. BeanFacotry加载后. 直至第一次使用调用getBean方法才会抛出异常。
ApplicationContext. 它是在容器启动时. 一次性创建了所有的Bean。这样. 在容器启动时. 我们就可以发现Spring中存在的配置错误. 这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单实例Bean. 通过预载入单实例bean ,确保当你需要的时候. 你就不用等待. 因为它们已经创建好了。
相对于基本的BeanFactory. ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时. 程序启动较慢。
3、BeanFactory通常以编程的方式被创建. ApplicationContext还能以声明的方式创建. 如使用ContextLoader。
4、BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用. 但两者之间的区别是:BeanFactory需要手动注册. 而ApplicationContext则是自动注册。
首先说一下Servlet的生命周期:实例化. 初始init. 接收请求service. 销毁destroy;
Spring上下文中的Bean生命周期也类似. 如下:
(1)实例化Bean:
对于BeanFactory容器. 当客户向容器请求一个尚未初始化的bean时. 或初始化bean的时候需要注入另一个尚未初始化的依赖时. 容器就会调用createBean进行实例化。对于ApplicationContext容器. 当容器启动结束后. 通过获取BeanDefinition对象中的信息. 实例化所有的bean。
(2)设置对象属性(依赖注入):
实例化后的对象被封装在BeanWrapper对象中. 紧接着. Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。
(3)处理Aware接口:
接着. Spring会检测该对象是否实现了xxxAware接口. 并将相关的xxxAware实例注入给Bean:
①如果这个Bean已经实现了BeanNameAware接口. 会调用它实现的setBeanName(String beanId)方法. 此处传递的就是Spring配置文件中Bean的id值;
②如果这个Bean已经实现了BeanFactoryAware接口. 会调用它实现的setBeanFactory()方法. 传递的是Spring工厂自身。
③如果这个Bean已经实现了ApplicationContextAware接口. 会调用setApplicationContext(ApplicationContext)方法. 传入Spring上下文;
(4)BeanPostProcessor:
如果想对Bean进行一些自定义的处理. 那么可以让Bean实现了BeanPostProcessor接口. 那将会调用postProcessBeforeInitialization(Object obj, String s)方法。
(5)InitializingBean 与 init-method:
如果Bean在Spring配置文件中配置了 init-method 属性. 则会自动调用其配置的初始化方法。
(6)如果这个Bean实现了BeanPostProcessor接口. 将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的. 所以可以被应用于内存或缓存技术;
以上几个步骤完成后. Bean就已经被正确创建了. 之后就可以使用这个Bean了。
(7)DisposableBean:
当Bean不再需要时. 会经过清理阶段. 如果Bean实现了DisposableBean这个接口. 会调用其实现的destroy()方法;
(8)destroy-method:
最后. 如果这个Bean的Spring配置中配置了destroy-method属性. 会自动调用其配置的销毁方法。
Spring容器中的bean可以分为5个范围:
(1)singleton:默认. 每个容器中只有一个bean的实例. 单例的模式由BeanFactory自身来维护。
(2)prototype:为每一个bean请求提供一个实例。
(3)request:为每一个网络请求创建一个实例. 在请求完成以后. bean会失效并被垃圾回收器回收。
(4)session:与request范围类似. 确保每个session中有一个bean的实例. 在session过期后. bean会随之失效。
(5)global-session:全局作用域. global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时. 它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话. 那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。
Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上. 大部分的Spring bean并没有可变的状态(比如Serview类和DAO类). 所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象). 就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用域由“singleton”变更为“prototype”。
在一般情况下. 只有无状态的Bean才可以在多线程环境下共享. 在Spring中. 绝大部分Bean都可以声明为singleton作用域. 因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理. 解决线程安全问题。
ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式. 仅提供一份变量. 不同的线程在访问前需要获取锁. 没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。
ThreadLocal会为每一个线程提供一个独立的变量副本. 从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本. 从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象. 在编写多线程代码时. 可以把不安全的变量封装进ThreadLocal。
在spring中. 对象无需自己查找或创建与其关联的其他对象. 由容器负责把需要相互协作的对象引用赋予各个对象. 使用autowire来配置自动装载模式。
在Spring框架xml配置中共有5种自动装配:
(1)no:默认的方式是不进行自动装配的. 通过手工设置ref属性来进行装配bean。
(2)byName:通过bean的名称进行自动装配. 如果一个bean的 property 与另一bean 的name 相同. 就进行自动装配。
(3)byType:通过参数的数据类型进行自动装配。
(4)constructor:利用构造函数进行装配. 并且构造函数的参数通过byType进行装配。
(5)autodetect:自动探测. 如果有构造方法. 通过 construct的方式自动装配. 否则使用 byType的方式自动装配。
基于注解的方式:
使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置.
如果查询结果刚好为一个. 就将该bean装配给@Autowired指定的数据;
如果查询的结果不止一个. 那么@Autowired会根据名称来查找;
如果上述查找的结果为空. 那么会抛出异常。解决方法时. 使用required=false。
@Autowired可用于:构造函数、成员变量、Setter方法
注:@Autowired和@Resource之间的区别
(1) @Autowired默认是按照类型装配注入的. 默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。
(2) @Resource默认是按照名称来装配注入的. 只有当找不到与名称匹配的bean才会按照类型来装配注入。
(1)工厂模式:BeanFactory就是简单工厂模式的体现. 用来创建对象的实例;
(2)单例模式:Bean默认为单例模式。
(3)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;
(4)模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
(5)观察者模式:定义对象键一种一对多的依赖关系. 当一个对象的状态发生改变时. 所有依赖于它的对象都会得到通知被制动更新. 如Spring中listener的实现–ApplicationListener。
Spring 提供了以下5种标准的事件:
(1)上下文更新事件(ContextRefreshedEvent):在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。
(2)上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。
(3)上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。
(4)上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时. 其管理的所有单例Bean都被销毁。
(5)请求处理事件(RequestHandledEvent):在Web应用中. 当一个http请求(request)结束触发该事件。
如果一个bean实现了ApplicationListener接口. 当一个ApplicationEvent 被发布以后. bean会自动被通知。
spring和springMvc:
springMvc和springBoot:
springBoot和springCloud:
总结:
Spring的ApplicationContext容器内部中的所有事件类型均继承自org.springframework.context.AppliationEvent. 容器中的所有监听器都实现org.springframework.context.ApplicationListener接口. 并且以bean的形式注册在容器中。一旦在容器内发布ApplicationEvent及其子类型的事件. 注册到容器的ApplicationListener就会对这些事件进行处理。
1、客户端用户发送请求至前端控制器DispatcherServlet。
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 HandlerMapping处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找). 生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、DispatcherServlet调用HandlerAdapter处理器适配器. HandlerAdapter经过适配调用具体的处理器(Controller. 也叫后端控制器)。
5、Controller控制器执行完成返回ModelAndView. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
6、 DispatcherServlet前端控制器将ModelAndView传给ViewReslover视图解析器。
7、 ViewReslover解析后返回具体View。
8、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中). 并返回给客户端用户。
SpringMVC框架组件说明:
以下组件通常使用框架提供实现:
DispatcherServlet:作为前端控制器. 整个流程控制的中心. 控制其它组件执行. 统一调度. 降低组件之间的耦合性. 提高每个组件的扩展性。
HandlerMapping:通过扩展处理器映射器实现不同的映射方式. 例如:配置文件方式. 实现接口方式. 注解方式等。
HandlAdapter:通过扩展处理器适配器. 支持更多类型的处理器。
ViewResolver:通过扩展视图解析器. 支持更多类型的视图解析. 例如:jsp、freemarker、pdf、excel等。
各个组件的具体作用:
1、前端控制器DispatcherServlet(不需要工程师开发),由框架提供
作用:接收请求. 响应结果. 相当于转发器. 中央处理器。有了dispatcherServlet减少了其它组件之间的耦合度。
用户请求到达前端控制器. 它就相当于mvc模式中的c. dispatcherServlet是整个流程控制的中心. 由它调用其它组件处理用户的请求. dispatcherServlet的存在降低了组件之间的耦合性。
2、处理器映射器HandlerMapping(不需要工程师开发),由框架提供
作用:根据请求的url查找Handler
HandlerMapping负责根据用户请求找到Handler即处理器. springmvc提供了不同的映射器实现不同的映射方式. 例如:配置文件方式. 实现接口方式. 注解方式等。
3、处理器适配器HandlerAdapter
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
通过HandlerAdapter对处理器进行执行. 这是适配器模式的应用. 通过扩展适配器可以对更多类型的处理器进行执行。
4、处理器Handler(需要工程师开发)
注意:编写Handler时按照HandlerAdapter的要求去做. 这样适配器才可以去正确执行Handler
Handler 是继DispatcherServlet前端控制器的后端控制器. 在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
由于Handler涉及到具体的用户业务请求. 所以一般情况需要工程师根据业务需求开发Handler。
5、视图解析器View resolver(不需要工程师开发),由框架提供
作用:进行视图解析. 根据逻辑视图名解析成真正的视图(view)
View Resolver负责将处理结果生成View视图. View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址. 再生成View视图对象. 最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型. 包括:jstlView、freemarkerView、pdfView等。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户. 需要由工程师根据业务需求开发具体的页面。
6、视图View(需要工程师开发页面渲染)
View是一个接口. 实现类支持不同的View类型(jsp、freemarker、pdf…)
简单了解下MVC:常说的 MVC 是一种设计模式. 并不是SpringMVC框架(只是该框架支持这种MVC模式)
M-Model 模型(完成业务逻辑:有javaBean构成. service+dao+entity)
V-View 视图(做界面的展示 jsp. html……)
C-Controller 控制器(接收请求—>调用模型—>根据结果派发页面)
SpringMVC是什么:
SpringMVC是一个MVC的开源框架. springMVC就相当于是Struts2与Sring框架的整合. 但是这里有一个疑惑就是. SpringMVC和Spring是什么样的关系呢?这个在百度百科上有一个很好的解释:意思是说. SpringMVC是Spring框架的一个后续产品(一个模块). 其实就是Spring在原有基础上. 又提供了web应用的MVC模块. 可以简单的把SpringMVC理解为是Spring的一个模块(类似AOP. IOC这样的模块). 网络上经常会说SpringMVC和Spring无缝集成. 其实SpringMVC就是Spring的一个子模块. 所以根本不需要同spring进行整合。
了解DispatcherServlet的初始化过程. 来看一下他的initStrategies()方法
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
1.@Controller 负责处理DispatcherServlet分发的请求
2.@RequestMapping 处理请求地址映射. 作用于类和方法上
3.@Autowired 根据类型注入
4.@Qualifier 当一个接口存在多个实现类时. 可以根据名称注入
5.@ResponseBody 用于异步请求返沪json数据
6.@PathVariable 在使用Resultful风格开发时. 可使用该注解配上对应url中参数的名称来获取参数的值
7.@RequestParam 两个属性value、required. value用来指定参数名称. required用来确定参数是否必须传入。
8.@RequestHeader 可以把request请求header部分的值绑定到参数上
9.@CookieValue 把request请求header中的cookie绑定到参数上
10.@RequestBody 可指定请求数据格式application/json, application/xml
11.@ModelAttribute 为请求绑定需要从后台获取的值
Java里有个API叫做ThreadLocal. spring单例模式下用它来切换不同线程之间的参数。用ThreadLocal是为了保证线程安全. 实际上ThreadLoacal的key就是当前线程的Thread实例。单例模式下. spring把每个线程可能存在线程安全问题的参数值放进了ThreadLocal。这样虽然是一个实例在操作. 但是不同线程下的数据互相之间都是隔离的. 因为运行时创建和销毁的bean大大减少了. 所以大多数场景下这种方式对内存资源的消耗较少. 而且并发越高优势越明显。
1、SpirngMVC的生命周期 :
A. DispatcherSerlvet(前端控制器)
B. -》 HandlerMapping(处理器映射器). 根据xml注解查找对应的Hander -》 返回Handler
C. -》处理器适配器去执行Handler
D. -》Handler执行完成后给处理器适配器返回ModelAndView
E. -》前端控制器请求视图解析器去执行视图解析. 根据逻辑视图名解析成真正的视图JSP. 向前端控制器返回view
F. -》前端控制器进行视图渲染. 将模型数据放到request-》返回给用户
2、SpringBean的生命周期:
Instance实例化-》设置属性值-》调用BeanNameAware的setBeanName方法-》调用BeanPostProsessor的预初始化方法-》调用InitializationBean的afterPropertiesSet()的方法-》调用定制的初始化方法callCustom的init-method-》调用BeanPostProsessor的后初始化方法-》Bean可以使用了 -》 容器关闭-》 调用DisposableBean的destroy方法-》调用定制的销毁方法CallCustom的destroy-method。