Spring 框架的核心模块
Core Container :核心容器提供了Spring的基本功能。Spring以bean的方式组织和管理Java应用中的各个组件及其关系。Spring使用BeanFactory来产生和管理Bean,它是工厂模式的实现。BeanFactory使用控制反转(IoC)模式将应用的配置和依赖性规范与实际的应用程序代码分开。
- spring-core:Spring中的核心工具类包;
- spring-beans:Spring中定义bean的组件;
- spring-context:Spring的运行容器;
- spring-context-support:Spring容器的扩展支持;
- spring-expression:Spring的表达式语言支持;
Spring AOP:提供了面向切面编程的支持。Spring AOP采用的是纯Java实现(采用基于代理的AOP实现方案)。AOP代理由Ioc容器负责生成、管理,依赖关系也一并由Ioc容器管理,尽管如此,Spring Ioc容器并不依赖于AOP,这样我们可以自由选择是否使用AOP。
- spring-aop:基于代理的AOP支持;
- spring-aspects:集成Aspects的AOP支持;
Spring Context:Spring上下文是一个配置文件,向Spring框架提供上下文信息,提供了框架式的对象访问方法。Spring上下文包括企业服务,如JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring DAO: 提供了JDBC的抽象层,它可消除冗长的JDBC编码和解析数据库厂商特有的错误代码。 并且,JDBC封装包还提供了一种比编程性更好的声明性事务管理方法,不仅仅是实现了特定接口,而且对所有的POJOs(plain old Java objects)都适用。
Spring ORM:ORM 封装包提供了常用的“对象/关系”映射APIs的集成层。 其中包括JPA、JDO、Hibernate 和 iBatis 。利用ORM封装包,可以混合使用所有Spring提供的特性进行“对象/关系”映射,如前边提到的简单声明性事务管理。
- spring-jdbc:提供对jdbc连接的封装功能。
- spring-tx:提供对事务的支持;
- spring-orm:提供对象-关系映射支持;
- spring-oxm:提供对象-XML映射支持;
- spring-jms:提供消息队列的支持;
Spring Web:提供了基础的针对Web开发的集成特性,例如多方文件上传,利用Servlet listeners进行IoC容器初始化和针对Web的applicationContext。
- spring-web:提供web的基础功能;
- spring-webmvc:提供springmvc的功能;
- spring-websocket:提供web socket支持;
- spring-webmvc-portlet:提供Portlet环境的支持;
Spring MVC:提供了Web应用的MVC实现。Spring的MVC框架并不是仅仅提供一种传统的实现,它提供了一种清晰的分离模型,在领域模型代码和web form之间。并且,还可以借助Spring框架的其他特性。
Spring 的工作机制
IoC (控制反转):应用程序本身不负责依赖对象的创建和维护,而是由外部容器负责创建和维护(获得依赖对象的过程被反转了,控制反转之后,获得依赖对象的过程由自身管理变为了由IoC容器主动注入)。
DI (依赖注入):控制反转的一种实现方式,目的:创建对象并且组装对象之间的关系(由IoC容器在运行期间,动态地将某种依赖关系注入到对象中;Spring容器管理容器中Bean之间的依赖关系,Spring使用一种被称为“依赖注入”的方式来管理Bean之间的依赖关系)。
- 设值注入:IoC容器通过成员变量的setter方法来注入被依赖对象(这种注入方式简单、直观,因而在Spring的依赖注入里大量使用;对于复杂的依赖关系,如果采用构造注入,会导致构造器过于臃肿,难以阅读)。
- 构造注入:利用构造器来设置依赖关系的方式,被称为构造注入(驱动Spring在底层以反射方式执行带指定参数的构造器,当执行带参数的构造器时,就可利用构造器参数对成员变量执行初始化;对于依赖关系无需变化的Bean,构造注入更有用处,因为没有setter方法,所有的依赖关系全部在构造器内设定,无须担心后续的代码对依赖关系产生破坏)。
AOP:它是一种面向切面编程的思想,核心功能的底层实现机制为 动态代理(AOP 代理是由 AOP 框架动态生成的一个对象,该对象可作为目标对象使用。AOP 代理包含了目标对象的全部方法,但 AOP 代理中的方法与目标对象的方法存在差异:AOP 方法在特定切入点添加了增强处理,并回调了目标对象的方法),Spring 的 AOP 代理由 Spring 的 IoC 容器负责生成、管理,其依赖关系也由 IoC 容器负责管理。因此,AOP 代理可以直接使用容器中的其他 Bean 实例作为目标(这种关系可由 IoC 容器的依赖注入提供)。
- jdk 动态代理:利用java.lang.reflect.Proxy类,但局限在于需要被代理的对象必须实现一个接口,如果被代理对象没有实现任何接口,或者被代理的业务方法没有相应的接口,就无法得到代理对象,这个时候就需要CGLIB方式产生代理对象。
- cglib 动态代理:原理实际上是动态生成被代理类的子类字节码,由于其字节码都是按照jvm编译后的class文件的规范编写的,因而其可以被jvm正常加载并运行,当然他也有局限,如果被代理类的方法被声明final类型,那么Cglib代理是无法正常工作的,因为final类型方法不能被重写。
Spring 容器及管理的bean
Spring 核心接口:BeanFactory、ApplicationContext(ApplicationContext是BeanFactory的子接口;他们都可以代表Spring容器)。
Spring 容器:Spring最基本的接口是BeanFactory(它有很多实现类,通常使用XmlBeanFactory,但是对于大部分的javaEE应用而言,推荐使用ApplictionContext),通过Spring容器来访问容器中的Bean(Spring容器,负责创建、管理所有的Java对象,这些Java对象被称为Bean),ApplicationContext是Spring容器最常用的接口,该接口的两个实现类:
- ClassPathXmlApplicationContext::从类加载路径下搜索配置文件,并根据配置文件来创建Spring容器;
- FileSystemXmlApplicationContext::从文件系统的相对路径或绝对路径下去搜索配置文件,并根据配置文件来创建Spring容器;
ApplicationContext的事件机制:基于观察者设计模式实现的(通过ApplicationEvent类和ApplicationListener接口)。
- ApplicationEvent:容器事件,必须由ApplicationContext发布。
- ApplicationListener:监听器,可有容器内的任何监听器Bean担任。
Bean的作用域:
- singleton:单例模式,在整个Spring IoC容器中,singleton作用域的Bean将只生成一个实例。
- prototype:当一个bean的作用域为 prototype,表示一个 bean 定义对应多个对象实例。 prototype 作用域的 bean 会导致在每次对该 bean 请求(prototype 是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象)
- request:只适用于Web程序,每一次 HTTP 请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,当请求结束后,该对象的生命周期即告结束。
- session:只适用于Web程序,session 作用域表示该针对每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当前 HTTP session 内有效.与request作用域一样,可以根据需要放心的更改所创建实例的内部状态,而别的 HTTP session 中根据 userPreferences 创建的实例,将不会看到这些特定于某个 HTTP session 的状态变化。当HTTP session最终被废弃的时候,在该HTTP session作用域内的bean也会被废弃掉。
- global session:类似于标准的 HTTP session 作用域,不过仅仅在基于 portlet 的 web 应用中才有意义。Portlet 规范定义了全局 Session 的概念,它被所有构成某个 portlet web 应用的各种不同的 portle t所共享。在global session 作用域中定义的 bean 被限定于全局portlet Session的生命周期范围内。
创建Bean的方法:1. 调用构造器创建Bean实例; 2. 调用静态工厂方法创建Bean(class属性是必须的,但此时的class并不是指定Bean实例的实现类而是静态工厂类); 3. 调用实例工厂创建Bean(class属性无需指定,因Spring容器不会直接实例化该Bean)。
Spring 的生命周期
Bean的完整生命周期所用到的组件大概可以分为:
- Bean自身定义的方法或者实现了接口的方法:即 init-method 和 destroy-method 指定的方法,还有实现了BeanNameAware、BeanFactoryAware、InitializingBean、DiposableBean 等接口的方法。
- 容器全局后处理器接口:包括了 BeanFactoryPostProcessor、InstantiationAwareBeanPostProcessor、BeanPostProcessor 这两个接口,它们是容器全局级别的接口。
- Bean容器找到配置文件中 Spring Bean 的定义。
- Bean容器利用Java Reflection API创建一个Bean的实例。
- 如果涉及到一些属性值 利用set方法设置一些属性值。
- 如果Bean实现了BeanNameAware接口,调用setBeanName()方法,传入Bean的名字。
- 如果Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。
- 如果Bean实现了BeanFactoryAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。
- 与上面的类似,如果实现了其他*Aware接口,就调用相应的方法。
- 如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执行postProcessBeforeInitialization()方法
- 如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。
- 如果Bean在配置文件中的定义包含init-method属性,执行指定的方法。
- 如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执行postProcessAfterInitialization()方法
- 当要销毁Bean的时候,如果Bean实现了DisposableBean接口,执行destroy()方法。
- 当要销毁Bean的时候,如果Bean在配置文件中的定义包含destroy-method属性,执行指定的方法。
Spring事物传播行为
事物的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:
- TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
- TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
- TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
- TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
- TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
- TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
SpringMVC 运行流程及九大组件
Spring MVC 的运行流程:
1. 用户发送请求至前端控制器 DispatcherServlet;
2. DispatcherServlet 收到请求调用 HandlerMapping处理映射器;
3. 处理映射器根据请求url 找到具体的处理器,生成处理对象及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet;
4. DispatcherServlet 通过HandlerAdapter 处理器适配器调用处理器;
5. 执行处理器(Controller 后端控制器);
6. Controller执行完成返回ModelAndView;
7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet;
8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器;
9. ViewReslover解析后返回具体View;
10. DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中);
11. DispatcherServlet响应用户。从上面可以看出,DispatcherServlet有接收请求,响应结果。
SpringMVC的九大组件:
protected void initStrategies(ApplicationContext context) {
//用于处理上传请求。处理方法是将普通的request包装成MultipartHttpServletRequest,后者可以直接调用getFile方法获取File.
initMultipartResolver(context);
//SpringMVC主要有两个地方用到了Locale:一是ViewResolver视图解析的时候;二是用到国际化资源或者主题的时候。
initLocaleResolver(context);
//用于解析主题。SpringMVC中一个主题对应一个properties文件,里面存放着跟当前主题相关的所有资源、
//如图片、css样式等。SpringMVC的主题也支持国际化,
initThemeResolver(context);
//用来查找Handler的。
initHandlerMappings(context);
//从名字上看,它就是一个适配器。Servlet需要的处理方法的结构却是固定的,都是以request和response为参数的方法。
//如何让固定的Servlet处理方法调用灵活的Handler来进行处理呢?这就是HandlerAdapter要做的事情
initHandlerAdapters(context);
//其它组件都是用来干活的。在干活的过程中难免会出现问题,出问题后怎么办呢?
//这就需要有一个专门的角色对异常情况进行处理,在SpringMVC中就是HandlerExceptionResolver。
initHandlerExceptionResolvers(context);
//有的Handler处理完后并没有设置View也没有设置ViewName,这时就需要从request获取ViewName了,
//如何从request中获取ViewName就是RequestToViewNameTranslator要做的事情了。
initRequestToViewNameTranslator(context);
//ViewResolver用来将String类型的视图名和Locale解析为View类型的视图。
//View是用来渲染页面的,也就是将程序返回的参数填入模板里,生成html(也可能是其它类型)文件。
initViewResolvers(context);
//用来管理FlashMap的,FlashMap主要用在redirect重定向中传递参数。
initFlashMapManager(context);
}
SpringMVC的设计思路
1. 读取配置: SpringMVC本质上是一个Servlet,这个 Servlet 继承自 HttpServlet;FrameworkServlet 负责初始化SpringMVC的容器,并将Spring容器设置为父容器。
2. 初始化: DispatcherServlet 的 initStrategies 方法会初始化9大组件(这里将实现一些SpringMVC的最基本组件而不是全部)按顺序包括: 1. 加载配置文件; 2. 扫描用户配置包下面所有的类; -3. 拿到扫描到的类,通过反射机制,实例化。并且放到ioc容器中(Map的键值对 beanName-bean) beanName默认是首字母小写; 4. 初始化HandlerMapping,这里其实就是把url和method对应起来放在一个k-v的Map中,在运行阶段取出;
3. 运行阶段:每一次请求将会调用 doGet 或 doPost 方法,所以统一运行阶段都放在 doDispatch 方法里处理,它会根据url请求去HandlerMapping 中匹配到对应的 Method,然后利用反射机制调用 Controller 中的 url 对应的方法,并得到结果返回。按顺序包括:1. 异常的拦截;2. 获取请求传入的参数并处理参数;3. 通过初始化好的 handlerMapping 中拿出 url 对应的方法名,反射调用。
Servlet
Servlet 主要负责接收用户请求 HttpServletRequest,在 doGet(), doPost() 中做相应的处理,并将回应 HttpServletResponse 反馈给用户。Servlet 可以设置初始化参数,供Servlet内部使用。一个 Servlet 类只会有一个实例,在它初始化时调用 init() 方法,销毁时调用 destroy() 方法。一个Servlet可以设置多个URL访问。Servlet不是线程安全,因此要谨慎使用类变量。
Servlet 接口中的方法及 Servlet 生命周期
Servlet接口定义了5个方法(前三个方法与Servlet生命周期相关)
- void init(ServletConfig config) throws ServletException
- void service(ServletRequest req, ServletResponse resp) throws ServletException, java.io.IOException
- void destory()
- java.lang.String getServletInfo()
- ServletConfig getServletConfig()
生命周期: Web容器加载Servlet并将其实例化后,Servlet生命周期开始,容器运行其init()方法进行Servlet的初始化;请求到达时调用Servlet的service()方法,service()方法会根据需要调用与请求对应的doGet或doPost等方法;当服务器关闭或项目被卸载时服务器会将Servlet实例销毁,此时会调用Servlet的destroy()方法。init方法和destory方法只会执行一次,service方法客户端每次请求Servlet都会执行。Servlet中有时会用到一些需要初始化与销毁的资源,因此可以把初始化资源的代码放入init方法中,销毁资源的代码放入destroy方法中,这样就不需要每次处理客户端的请求都要初始化与销毁资源。
Spring 常用注解
声明bean的注解:
- @Component :把普通pojo实例化到spring容器中
- @Service :在业务逻辑层使用(service层)
- @Repository :在数据访问层使用(dao层)
- @Controller :在展现层使用,控制器的声明(C)
注入bean的注解:
- @Autowired:是按类型装配依赖对象(spring自带的注解)
- @Inject:根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Named(由JSR-330提供)
- @Resource:按照名称自动注入(Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型,由JSR-250提供)
java配置类相关注解:
- @Configuration:声明当前类为配置类,相当于xml形式的Spring配置(类上)
- @Bean:注解在方法上,声明当前方法的返回值为一个bean,替代xml中的方式(方法上)
- @Configuration:声明当前类为配置类,其中内部组合了@Component注解,表明这个类是一个bean(类上)
- @ComponentScan:用于对Component进行扫描,相当于xml中的(类上)
- @WishlyConfiguration:为@Configuration与@ComponentScan的组合注解,可以替代这两个注解。
@Scope:设置Spring容器如何新建Bean实例(方法上,得有@Bean)
@Value:为属性注入值(属性上)
@EnableAsync:配置类中,通过此注解开启对异步任务的支持,叙事性AsyncConfigurer接口(类上)
@Async:在实际执行的bean方法使用该注解来申明其是一个异步任务(方法上或类上所有的方法都将异步,需要@EnableAsync开启异步任务)
@EnableScheduling:在配置类上使用,开启计划任务的支持(类上)
@RequestMapping:用于映射Web请求,包括访问路径和参数(类或方法上)
@ResponseBody:支持将返回值放在response内,而不是一个页面,通常用户返回json数据(返回值旁或方法上)
@RequestBody:允许request的参数在request体中,而不是在直接连接在地址后面。(放在参数前)
@PathVariable:用于接收路径参数,比如@RequestMapping(“/hello/{name}”)申明的路径,将注解放在参数中前,即可获取该值,通常作为Restful的接口实现方法。
将项目打包为可执行 jar 命令: mvn clean package -Dmaven.test.skip=true